Merge pull request #22 from mcgill-ecsess/council_card_component

Council Card Component
This commit is contained in:
Mel
2025-07-07 18:55:46 -04:00
committed by GitHub
8 changed files with 213 additions and 81 deletions

View File

@@ -1,3 +1,14 @@
<button class="btn bg-ecsess-600 text-ecsess-200 px-4 py-2 m-1 rounded-lg border-none hover:shadow-lg hover:shadow-ecsess-800 active:bg-ecsess-800 transition-all"> <script lang="ts">
<slot /> let { children, onclick } = $props();
</script>
<button
class="bg-ecsess-600 hover:bg-ecsess-400 active:bg-ecsess-800
m-1 inline-block rounded-lg border-none px-4
py-2 text-white transition-all
duration-200 ease-out
hover:shadow-2xl"
{onclick}
>
{@render children()}
</button> </button>

View File

@@ -1,31 +1,49 @@
<script> <script>
/** let { onViewProfile, name, position, image } = $props();
* Schemas for Council Members:
* {
* email,
* name,
* position,
* positionDescription,
* yearProgram,
* image // CDN URL from Sanity CMS
* }
*/
let { name, position, email, positionDescription, yearProgram, image } = $props();
import placeholder from 'assets/placeholderAvatar.png'; import placeholder from 'assets/placeholderAvatar.png';
import { Avatar } from '@skeletonlabs/skeleton-svelte'; import Button from 'components/Button.svelte';
</script> </script>
<div class="card h-1/2 max-h-1/2 w-full max-w-1/6 rounded-lg border-4 p-4"> <style lang="postcss">
<!-- <img class="size-4/5" src={placeholder} alt="Placeholder"> --> @reference '../app.css';
<!-- <Avatar src={placeholder} {name} /> -->
{#if image} .card {
<Avatar src={image} {name} /> @apply flex items-center gap-4 bg-transparent p-6 rounded-lg text-ecsess-200 max-w-[400px];
{:else} }
<Avatar src={placeholder} {name} />
{/if} .profile-img {
<p class="pb-2 text-xl font-bold">{name} - <span class="text-sm"> {yearProgram} </span></p> @apply size-[100px] rounded-full overflow-hidden;
<hr /> }
<p class="py-2 text-base font-bold">~ {position} ~</p>
<p class="underline">{email}</p> .profile-img :global(img) {
<p class="text-sm">{positionDescription}</p> @apply object-cover size-full;
}
.info {
@apply flex-1;
}
.name {
@apply text-xl font-bold;
}
.role {
@apply text-ecsess-200 mb-2;
}
</style>
<div class="card">
<div class="profile-img">
<img src={image || placeholder} alt={name} />
</div> </div>
<div class="info">
<div class="name">{name}</div>
<div class="role">{position}</div>
<!-- <button class="button" onclick={onViewProfile}>View Profile</button> -->
<Button onclick={onViewProfile}>View Profile</Button>
</div>
</div>

View File

@@ -0,0 +1,41 @@
<script>
let { name, position, email, positionDescription, yearProgram, image } = $props();
import placeholder from 'assets/placeholderAvatar.png';
</script>
<style lang="postcss">
@reference '../app.css';
.card {
@apply flex items-center gap-4 bg-transparent rounded-2xl p-6 text-ecsess-800 border-transparent max-w-[450px] h-[250px];
background-image: linear-gradient(to bottom right, #E8FFD9, #97C583);
}
.profile-img {
@apply w-32 h-32 shadow-md overflow-hidden rounded-lg;
}
.profile-img :global(img) {
@apply w-full h-full object-cover;
}
.name {
@apply text-xl font-bold;
}
</style>
<div class="card">
<div class="avatar-container justify-left">
<div class="profile-img justify-center">
<img src={image || placeholder} alt={name} />
</div>
<span class="yearProgram text-sm justify-center"> {yearProgram} </span>
</div>
<div class="content">
<p class="name">{name} </p>
<p class="py-2 text-base">{position}</p>
<p class="pb-2 text-xs">{positionDescription}</p>
<a href="mailto:{email}" class="py-2 text-sm underline">{email}</a>
</div>
</div>

View File

@@ -12,7 +12,4 @@
<NavButton href="/events">Events</NavButton> <NavButton href="/events">Events</NavButton>
<NavButton href="/resources">Resources</NavButton> <NavButton href="/resources">Resources</NavButton>
<NavButton href="/join">Join ECSESS</NavButton> <NavButton href="/join">Join ECSESS</NavButton>
{#if import.meta.env.DEV}
<NavButton href="/showroom">Componenets</NavButton>
{/if}
</nav> </nav>

View File

@@ -9,8 +9,13 @@ const query = `*[_type == "members"]{
yearProgram yearProgram
}`; }`;
const councilGoofyPicQuery = `*[_type == "homepage"]{
"url": councilGoofyPic.asset->url+"?h=1000&fm=webp"
}[0]`;
export const load = async () => { export const load = async () => {
return { return {
members: await getFromCMS(query) members: await getFromCMS(query),
councilGoofyPic: await getFromCMS(councilGoofyPicQuery),
}; };
}; };

View File

@@ -1,26 +1,108 @@
<script> <script lang="ts">
import CouncilCard from 'components/CouncilCard.svelte'; import CouncilCardPopUp from 'components/CouncilCardPopUp.svelte';
import Section from 'components/Section.svelte'; import Section from 'components/Section.svelte';
// import CouncilMember from 'utils/schemas.ts'; import CardCouncil from 'components/CouncilCard.svelte';
import type CouncilMember from 'utils/schemas';
let { data } = $props(); let { data } = $props();
let years = ['U4', 'U3', 'U2', 'U1', 'U0'];
let vps: CouncilMember[] = [];
let ureps: CouncilMember[] = [];
// svelte-ignore non_reactive_update
let president: CouncilMember | null = null;
data.members.forEach((member: CouncilMember) => {
if (
member.position.includes('VP') ||
member.position.includes('Equity and Mental Health Officer')
) {
vps.push(member);
} else if (member.position.includes('Representative')) {
ureps.push(member);
ureps.sort((a, b) => {
const aYear = years.findIndex((y) => a.position.includes(y));
const bYear = years.findIndex((y) => b.position.includes(y));
return aYear - bYear;
});
} else if (member.position.includes('President')) {
president = member;
}
});
let selectedMember = $state<CouncilMember | null>(null);
function handleViewProfile(member: CouncilMember) {
selectedMember = member;
}
console.log(ureps)
// svelte-ignore state_referenced_locally
// console.log(selectedMember);
</script> </script>
<title> ECSESS council </title> <title> ECSESS council </title>
<Section> <Section>
<p class="page-title">Meet the council!</p> <p class="page-title">Meet the council!</p>
<div>
<p>Group picture!</p> <h1>Our Student Council</h1>
<img src={data.councilGoofyPic.url} alt="ECSESS Council, but we are goofy" />
<div class="flex flex-row flex-wrap items-center align-middle gap-10 p-4">
{#each data.members as councilMember}
<CouncilCard
name={councilMember.name}
position={councilMember.position}
email={councilMember.email}
positionDescription={councilMember.positionDescription}
yearProgram={councilMember.yearProgram}
image={councilMember.image}
></CouncilCard>
{/each}
</div> </div>
</Section> </Section>
<Section>
<div class="president">
{#if president}
<CardCouncil
name={president.name}
position={president.position}
image={president.image}
onViewProfile={() => handleViewProfile(president!)}
/>
{/if}
</div>
<div class="flex justify-center">
<div class="flex flex-row flex-wrap justify-center gap-10 p-4 align-middle">
{#each vps as councilMember}
<CardCouncil
name={councilMember.name}
position={councilMember.position}
image={councilMember.image}
onViewProfile={() => handleViewProfile(councilMember)}
/>
{/each}
{#each ureps as councilMember}
<CardCouncil
name={councilMember.name}
position={councilMember.position}
image={councilMember.image}
onViewProfile={() => handleViewProfile(councilMember)}
/>
{/each}
</div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
{#if selectedMember}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="fixed inset-0 z-50 flex items-center justify-center bg-black/60"
onclick={() => (selectedMember = null)}
>
<CouncilCardPopUp
name={selectedMember.name}
position={selectedMember.position}
email={selectedMember.email}
positionDescription={selectedMember.positionDescription}
yearProgram={selectedMember.yearProgram}
image={selectedMember.image}
/>
</div>
{/if}
</div>
</Section>
<!-- <CouncilCard
name={vps[1].name}
position={vps[1].position}
email={vps[1].email}
positionDescription={vps[1].positionDescription}
yearProgram={vps[1].yearProgram}
image={vps[1].image}
></CouncilCard> -->

View File

@@ -1,22 +0,0 @@
<script>
import Button from 'components/Button.svelte';
import ResourceCard from 'components/ResourceCard.svelte';
import Section from 'components/Section.svelte';
</script>
<title> Component showroom for developers </title>
<Section>
<Button>Button</Button>
<ResourceCard></ResourceCard>
</Section>
<Section black>
<Button>Button</Button>
<ResourceCard title="Workshop feedback">
Description of the workshop
</ResourceCard>
</Section>
<Section>
<Button>Button</Button>
</Section>

View File

@@ -1,8 +1,8 @@
type CouncilMember = { export default interface CouncilMember {
name: string, name: string;
email: string, email: string;
position: string, position: string;
positionDescription: string, positionDescription: string;
image: string, // URL image: string; // URL
yearProgram: string yearProgram: string;
} }