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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ node_modules
.netlify
.wrangler
/.svelte-kit
/.claude
/build

# OS
Expand Down
1 change: 1 addition & 0 deletions AGENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REFER TO CLAUDE.md
95 changes: 95 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

ECSESS Website - the official site for McGill University's Engineering and Computer Science Students' Society. Built with SvelteKit 2, Svelte 5, TailwindCSS 4, and Sanity CMS.

## Commands

```bash
bun i # Install dependencies
bun run dev # Start dev server (localhost:5173)
bun run build # Production build
bun run check # TypeScript type checking
bun run format # Format with Prettier
bun run lint # Check formatting
```

## Environment Setup

Copy `.env.example` to `.env` and set `SANITY_ID` (get from VP Technical Development or VP Communications).

## Architecture

### Data Flow

- **Server-side data fetching**: Each route uses `+page.server.ts` to fetch from Sanity CMS via GROQ queries
- **CMS client**: `src/lib/utils.ts` exports `getFromCMS(query)` for all Sanity fetches
- **Type definitions**: `src/lib/schemas.ts` contains all TypeScript types for CMS data

### Key Patterns

**GROQ Query Pattern** (used in all `+page.server.ts` files):

```typescript
import { getFromCMS } from '$lib/utils.js';

const query = `*[_type == "events"]{ name, date, ... }`;

export const load = async ({ url }) => {
const data = await getFromCMS(query);
return { data, canonical: url.href };
};
```

**Image URLs**: Always append Sanity optimization params: `?h=800&fm=webp`

**Svelte 5 Runes**: Project uses `$props()`, `$state()`, and `{@render}` syntax

### Path Aliases

- `components` → `src/components/`
- `assets` → `src/assets/`
- `$lib` → `src/lib/`

### Component Organization

- `src/components/layout/` - NavBar, Footer, Section, SeoMetaTags
- `src/components/homepage/` - Sponsors, FAQAccordion, Gallery, AffiliatedGroups
- `src/components/council/` - CouncilCard, CouncilAvatar, CouncilCardPopUp
- `src/components/event/` - EventBlock, EventTabsContent

### Custom Colors

TailwindCSS theme includes `ecsess-*` color palette (greens 50-950) defined in `src/app.css`.

## Routes

- `/` - Homepage with council photo, office hours, sponsors, FAQs
- `/council` - Council member directory
- `/events` - Event listings with category filtering
- `/resources` - External resources
- `/join` - Membership info
- `/r/[shortname]` - URL shortener redirects (managed via CMS)

## 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.
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="/sponsors">Sponsors</NavButton>
<NavButton href="/events">Events</NavButton>
<NavButton href="/resources">Resources</NavButton>
<NavButton href="/devteam">Dev Team</NavButton>
Expand All @@ -51,6 +52,7 @@
</a>
<NavButton href="/">Home</NavButton>
<NavButton href="/council">Meet the council</NavButton>
<NavButton href="/sponsors">Sponsors</NavButton>
<NavButton href="/events">Events</NavButton>
<NavButton href="/resources">Resources</NavButton>
<NavButton href="/devteam">Dev Team</NavButton>
Expand Down
11 changes: 11 additions & 0 deletions src/lib/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,20 @@ export type Resource = {
export type Sponsors = {
name: string;
url: string;
tier: string;
logo: string;
};

export type Benefits = {
benefit: string;
category: string;
description: string;
platinum: string;
gold: string;
silver: string;
custom: string;
};

export type Redirect = {
name: string;
shortname: string;
Expand Down
1 change: 1 addition & 0 deletions src/routes/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const homepageQuery = `{
"sponsors": *[_type=="sponsors"]{
name,
url,
tier,
"logo": logo.asset->url+"?h=100&fm=webp"
},
"sponsorsLastUpdated": *[_type=="sponsors"] | order(_updatedAt desc)[0]._updatedAt
Expand Down
31 changes: 31 additions & 0 deletions src/routes/sponsors/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Benefits, Sponsors } from '$lib/schemas';
import { getFromCMS } from '$lib/utils.js';

const query = `{
"benefits": *[_type == "benefits"]{
benefit,
category,
description,
platinum,
gold,
silver,
custom
},
"sponsors": *[_type == "sponsors"]{
name,
url,
tier,
"logo": logo.asset->url+"?h=100&fm=webp"
}
}`;

export const load = async ({ url }) => {
const response = await getFromCMS(query);
const benefits: Benefits[] = response.benefits;
const sponsors: Sponsors[] = response.sponsors;
return {
benefits,
sponsors,
canonical: url.href
};
};
Loading