Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions AGENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# ECSESS Agent Guidelines

This document outlines the standards, technology stack, and best practices for the **ECSESS (Engineering and Computer Science Students' Society)** website project. All AI agents and developers should follow these guidelines strictly.

## 1. Technology Stack

- **Runtime & Package Manager**: **Bun**.
- Use `bun install`, `bun run dev`, `bun run build`.
- Do NOT use `npm` or `yarn` unless explicitly instructed.
- **Framework**: **SvelteKit v2** with **Svelte 5**.
- **Runes**: The project is configured with `runes: true`. ALWAYS use Svelte 5 Runes (`$state`, `$derived`, `$effect`, `$props`) for reactivity. Avoid legacy `export let` or `store` syntax for new components.
- **Styling**: **TailwindCSS v4**.
- Configuration is largely handled in CSS (`@theme` in `app.css`) rather than `tailwind.config.js`.
- **CMS**: **Sanity**.
- Content is managed via Sanity. Content schemas and fetching logic are critical parts of the app.
- **Icons**: **Lucide Svelte** (`@lucide/svelte`).

## 2. Setup Instructions

1. **Install Dependencies**: Run `bun install` in the project root.
2. **Environment Setup**:
- Copy `.env.example` to `.env` if it doesn't exist.
- Ensure Sanity CMS credentials (project ID, dataset) are correctly populated.
3. **Development**: Run `bun run dev` to start the local server.

## 3. Project Structure & Imports

- **Aliases**: Always use the configured import aliases:
- `import X from 'components/...'` (mapped to `src/components`)
- `import X from 'utils/...'` (mapped to `src/utils`)
- `import X from 'assets/...'` (mapped to `src/assets`)
- `$lib` is available for `src/lib`.

## 4. Styling & Design System

- **Global Styles**: Refer to [`src/app.css`](file:///src/app.css) for the design system.
- **Custom Styles**: For custom css styling, please use `<style></style>` tags in the component.
- **Color Palette**: Use the ECSESS brand colors defined in CSS variables. Do not hardcode hex values if a variable exists.
- Light: `--color-ecsess-50` to `--color-ecsess-200`
- Mid: `--color-ecsess-300` to `--color-ecsess-600`
- Dark: `--color-ecsess-700` to `--color-ecsess-950`
- Black: `--color-ecsess-black`
- **Typography**:
- Primary Font: 'Saira', sans-serif.
- Classes: Use the `.typography` global class for prose content (CMS text, blogs) to ensure consistent formatting of headers, lists, and quotes.
- Use Tailwind utility classes for layout and spacing.

## 5. Coding Standards

- **Specification & Clarification (CRITICAL)**:
- **Ask Questions**: The agent **MUST** ask for clarification if the prompt is ambiguous, vague, or lacks sufficient detail.
- **Maximize Detail**: Require as much detail as possible from the user regarding functionality, design preferences, and edge cases before coding.
- **Confirm Plan**: Before implementing complex changes, re-state the requirements to the user to ensure alignment.
- **Svelte Components**:
- Use `snippets` for repeated markup within a file.
- Ensure accessibility (a11y) attributes are present.
- Type all props using `$props()`.
- **TypeScript**:
- Strict typing is encouraged. Avoid `any`.
- Define interfaces/types in `src/lib/types` or colocated with components if specific.

## 6. UI/UX Philosophy

- **Premium & Modern**: The design should feel high-quality. Use smooth transitions, subtle hover states, and the specific color palette to maintain brand identity.
- **Responsive**: Mobile responsiveness is a strict requirement. Always verify layouts on small screens.
- **Consistency**: Maintain consistency in design and functionality throughout the website.

## 7. Workflow

- **Development**: `bun run dev`
- **Formatting**: `bun run format` (Prettier)
- **Linting**: `bun run check`
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ The official open-source website for the Engineering and Computer Science Studen
- SvelteKit v2 with Svelte v5
- TailwindCSS v4
- Sanity CMS for content management
- SkelentonUI (https://www.skeleton.dev) for UI components
- Lucide (https://lucide.dev/icons/) for icons
74 changes: 17 additions & 57 deletions src/components/layout/Footer.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import ECSESS from 'assets/ECSESS.png';
import { FacebookIcon, Github, InstagramIcon, LinkedinIcon, Mail } from '@lucide/svelte';
const year = new Date().getFullYear();

// Social links data
Expand Down Expand Up @@ -32,6 +34,12 @@
url: 'mailto:[email protected]',
icon: 'email',
ariaLabel: 'Send us an email'
},
{
name: 'GitHub',
url: 'https://github.com/mcgill-ecsess/ECSESS',
icon: 'github',
ariaLabel: 'Visit our open source website'
}
];
</script>
Expand Down Expand Up @@ -86,42 +94,11 @@
class="bg-ecsess-800 hover:bg-ecsess-600 flex h-10 w-10 items-center justify-center rounded-full transition-all hover:scale-110"
>
{#if link.icon === 'instagram'}
<svg
class="h-5 w-5 text-white"
fill="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z"
clip-rule="evenodd"
/>
</svg>
<InstagramIcon class="text-white" />
{:else if link.icon === 'facebook'}
<svg
class="h-5 w-5 text-white"
fill="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z"
clip-rule="evenodd"
/>
</svg>
<FacebookIcon class="text-white" fill="white" color="transparent" />
{:else if link.icon === 'linkedin'}
<svg
class="h-5 w-5 text-white"
fill="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
/>
</svg>
<LinkedinIcon class="text-white" fill="white" color="transparent" />
{:else if link.icon === 'linktree'}
<svg
class="h-5 w-5 text-white"
Expand All @@ -134,20 +111,9 @@
/>
</svg>
{:else if link.icon === 'email'}
<svg
class="h-5 w-5 text-white"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
/>
</svg>
<Mail class="text-white" />
{:else if link.icon == 'github'}
<Github class="text-white" />
{/if}
</a>
{/each}
Expand All @@ -161,19 +127,13 @@
Let us know!
</p>
<a
href="https://github.com/mcgill-ecsess/ECSESS"
href="https://forms.gle/hTA9hZdy3UPNs12R6"
target="_blank"
rel="noopener noreferrer"
class="bg-ecsess-800 hover:bg-ecsess-600 inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-semibold text-white transition-colors"
>
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path
fill-rule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clip-rule="evenodd"
/>
</svg>
<span>ECSESS on GitHub</span>
<img src={ECSESS} alt="ECSESS Logo" class="w-8" />
<span>Bug Report Form</span>
</a>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/components/layout/NavBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
>
<NavButton href="/">Home</NavButton>
<NavButton href="/council">Meet the council</NavButton>
<NavButton href="/team">Team</NavButton>
<NavButton href="/events">Events</NavButton>
<NavButton href="/resources">Resources</NavButton>
{#if isElectionTime}
Expand All @@ -50,6 +51,7 @@
</a>
<NavButton href="/">Home</NavButton>
<NavButton href="/council">Meet the council</NavButton>
<NavButton href="/team">Team</NavButton>
<NavButton href="/events">Events</NavButton>
<NavButton href="/resources">Resources</NavButton>
{#if isElectionTime}
Expand Down
32 changes: 32 additions & 0 deletions src/components/team/Avatar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
let {
name,
src,
role = ''
}: {
name: string;
src: string;
role: string;
} = $props();

let array = $derived(role ? [...Array(3)].map((_) => [...role].concat('*')).flat() : []);
</script>

<div class="relative {role ? 'size-58' : 'size-48'} rounded-full">
<img
class="size-full rounded-full object-cover {role ? 'border-ecsess-900 border-20' : ''}"
{src}
alt={name}
/>
{#if role}
{#each array as char, index}
<p
class="char absolute inset-29 z-10 size-3 text-xs"
style="transform: translate(-50%, -50%) rotate({(360 / array.length) *
index}deg) translateY(-108px);"
>
{char}
</p>
{/each}
{/if}
</div>
49 changes: 49 additions & 0 deletions src/components/team/TeamBanner.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script lang="ts">
import { Github } from '@lucide/svelte';
import Avatar from 'components/team/Avatar.svelte';

let { idx, src, name, role, funFact } = $props();
</script>

<div
class="fadeup relative flex flex-col rounded-2xl md:flex-row {idx % 2 == 0
? 'md:-translate-x-1/12'
: 'md:translate-x-1/12'} from-ecsess-800 to-ecsess-950 w-5/6 max-w-300 items-center bg-radial from-40% to-90% p-5"
>
<!-- bg-linear-to-tl from-ecsess-300 to-ecsess-900-->
<!-- Avatar box -->
<Avatar {src} {name} {role} />
<div class="flex-1">
<h2>{name}</h2>
<div>Fun Fact:</div>
<div>{funFact}</div>
<div>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Aliquid ex voluptate minus ratione
animi unde beatae, maiores maxime adipisci alias, omnis vel, modi provident. Numquam accusamus
nisi dolores nihil temporibus?
</div>
</div>

<div class="absolute right-2 bottom-2 flex gap-2">
<Github />
</div>
</div>

<style>
.fadeup {
animation: fadeUp both;
animation-timeline: view();
animation-range: entry 25% cover 40%;
}

@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(20px) scale(0.5);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
</style>
10 changes: 10 additions & 0 deletions src/lib/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,13 @@ export type Redirect = {
shortname: string;
url: string;
};

export type DevTeam = {
name: string;
role: string;
yeaProgram: string;
email: string;
funFact: string;
github: string;
image: string; //URL
};
6 changes: 5 additions & 1 deletion src/routes/council/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ const councilQuery = `{
}`;

export const load = async ({ url }) => {
const { members, councilGoofyPic }: { members: CouncilMember[], councilGoofyPic: { url: string } } = await getFromCMS(councilQuery);
const {
members,
councilGoofyPic
}: { members: CouncilMember[]; councilGoofyPic: { url: string } } =
await getFromCMS(councilQuery);

return {
members: members,
Expand Down
22 changes: 22 additions & 0 deletions src/routes/team/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//Wait for CMS to setup
import type { DevTeam } from '$lib/schemas';
import { getFromCMS } from '$lib/utils';

const query = `*[_type == "devTeam"]{
name,
role,
yearProgram,
email,
funFact,
github,
"image": image.asset->url+"?h=300&fm=webp",
}`;

export const load = async ({ url }) => {
let devTeam: DevTeam[] = await getFromCMS(query);

return {
devTeam: devTeam,
canonical: url.href
};
};
36 changes: 36 additions & 0 deletions src/routes/team/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script>
import SeoMetaTags from 'components/layout/SeoMetaTags.svelte';
import Section from 'components/layout/Section.svelte';
import TeamBanner from 'components/team/TeamBanner.svelte';
import Avatar from 'components/team/Avatar.svelte';
let { data } = $props();
</script>

<SeoMetaTags />

<Section from="from-ecsess-black" to="to-ecsess-black" via="via-ecsess-800" direction="to-b">
<div class="flex h-full w-full flex-col items-center">
<p class="page-title">Meet the team!</p>
<h1 class="border-b-ecsess-300 w-full border-b-2 lg:w-1/2">Our Current Team</h1>

<div class="flex flex-col items-center space-y-50 py-40">
{#each data.devTeam as member, idx}
<TeamBanner
{idx}
name={member.name}
role={member.role}
src={member.image}
funFact={member.funFact}
/>
{/each}
</div>

<h1 class="border-b-ecsess-300 w-full border-b-2 lg:w-1/2">Past Contributors</h1>
<div class="flex w-full flex-wrap justify-evenly space-y-5 p-10">
<Avatar name={data.devTeam[0].name} role="" src={data.devTeam[0].image} />
<Avatar name={data.devTeam[0].name} role="" src={data.devTeam[0].image} />
<Avatar name={data.devTeam[0].name} role="" src={data.devTeam[0].image} />
<Avatar name={data.devTeam[0].name} role="" src={data.devTeam[0].image} />
</div>
</div>
</Section>