Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ SPOTIFY_CLIENT_SECRET=
SPOTIFY_REFRESH_TOKEN=

# --- Mapbox -------------------------------------------------------------------
# Public token for `/playlists/map` (Mapbox GL JS). Create at mapbox.com → Access tokens.
# Public token for `/music-for-life/map` (Mapbox GL JS). Create at mapbox.com → Access tokens.
NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=
# Optional: override basemap style (default Standard monochrome). Example:
# NEXT_PUBLIC_MAPBOX_MAP_STYLE=mapbox://styles/mapbox/outdoors-v12
Expand Down
35 changes: 35 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,41 @@ Run `git status` and `git diff --staged` before committing.

---

## Site patterns (for agents)

Keep **[README.md](README.md)** in sync when you touch these areas.

### Music for Life routes

| Path | Notes |
| --- | --- |
| **`/music-for-life`** | Index — curated Spotify playlists (`MUSIC_FOR_LIFE_BASE` in [`lib/spotify-playlists.ts`](lib/spotify-playlists.ts)) |
| **`/music-for-life/[id]`** | Single playlist — title + **Tracks** TOC only (not per-song) |
| **`/music-for-life/map`** | Fullscreen Mapbox GL; **no PageToc**, compact footer via `html.playlist-map-view` |

Legacy **`/playlists`** and **`/playlists/*`** → **301 permanent redirect** to `/music-for-life/*` in [`next.config.ts`](next.config.ts). Use `MUSIC_FOR_LIFE_BASE` for all new internal links — never hardcode `/playlists`.

Config: [`app/lib/spotify-playlists.ts`](app/lib/spotify-playlists.ts) (`CURATED_SPOTIFY_PLAYLISTS`, server fetch). Shared types/helpers: [`lib/spotify-playlists.ts`](lib/spotify-playlists.ts).

### Page table of contents (`PageToc`)

- **Components:** [`app/components/page-toc.tsx`](app/components/page-toc.tsx), [`app/components/toc-section.tsx`](app/components/toc-section.tsx)
- **Mount:** [`app/components/subpage-enter.tsx`](app/components/subpage-enter.tsx) — portaled to `document.body`, `position: fixed` (does not affect layout flow)
- **Discovery order:** explicit `TocSection` (`data-toc-item`) → `.mag-label` → `.mag-card h1/h2`
- **Shown when:** ≥2 entries, viewport gutter ≥28px right of content column, not on excluded paths (`/music-for-life/map`)
- **Home `/`:** `TocSection` labels — Kai Thomas Chen, Greeting, Contact; `.mag-label` — Listening, Location, Projects. Identity row uses **`md:flex-row-reverse`** + mobile `order-*` so TOC DOM order matches reading order **without** CSS Grid row-height gaps under the social column.
- **Playlist pages:** index = Music for Life + each playlist name (`level={1}`); detail = playlist name + **Tracks** — never one TOC entry per song.

### Performance / loading (recent)

- **Fonts:** Nunito via [`app/fonts.ts`](app/fonts.ts) (`next/font/google`); no `@fontsource` in client bundle
- **Weather:** Berkeley weather SSR on home via [`app/lib/weather.ts`](app/lib/weather.ts); `WeatherCard` accepts `initialWeather`
- **Mapbox:** dynamic import in [`app/components/playlist-map-loader.tsx`](app/components/playlist-map-loader.tsx)
- **GitHub heatmap:** prefetch on `/projects` via [`app/lib/github-contributions.ts`](app/lib/github-contributions.ts)
- **Route loading UI:** `app/music-for-life/loading.tsx`, `app/music-for-life/[id]/loading.tsx`

---

## Where to read more

| Topic | Document |
Expand Down
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ Canonical documentation: **[README.md](README.md)** (setup, routes, APIs, env, C
| **Client polling** | `app/hooks/use-now-playing.ts` — polls every **10s** (`cache: "no-store"`) |
| **GitHub** | `GET /api/github/contributions` — GraphQL calendar; pinned repos in `app/lib/github-pinned.ts` |
| **Weather** | `GET /api/weather` — Open-Meteo (Berkeley); `berkeley-time.tsx` |
| **Home UI** | Identity + social links; **Listening** / **Location** cards; **Projects** outer card with nested Course + Personal (`projects-split.tsx`) |
| **Home UI** | Identity + social links; **Listening** / **Location** cards; **Projects** outer card with nested Course + Personal (`projects-split.tsx`); **PageToc** (Kai Thomas Chen, Greeting, Contact, Listening, Location, Projects) |
| **Music for Life** | `/music-for-life` — curated Spotify playlists ([`MUSIC_FOR_LIFE_BASE`](lib/spotify-playlists.ts)); `[id]` detail; `/map` Mapbox viewer; old `/playlists` → 301 redirect |
| **Page TOC** | [`page-toc.tsx`](app/components/page-toc.tsx) + [`toc-section.tsx`](app/components/toc-section.tsx) — fixed right rail on `/`, `/about`, `/projects`, `/misc`, `/music-for-life` (not map); auto `.mag-label` + explicit `TocSection` |
| **Course Projects** | `app/lib/course-projects.ts` — Oxford DUL (`/projects/oxford-dul-2025`) + Notion notes |
| **Oxford portfolio** | `app/lib/oxford-dul-projects.ts` + `app/projects/oxford-dul-2025/` + `app/components/oxford-dul/` |
| **Nav** | Bold labels; active link = accent + pill underline (`.nav-link` in `globals.css`) |
Expand Down Expand Up @@ -49,6 +51,10 @@ npm run lint && npm run typecheck && npm run test && npm run build
- [`app/components/oxford-dul/`](app/components/oxford-dul/) — portfolio UI components
- [`app/components/pinned-project-link.tsx`](app/components/pinned-project-link.tsx) — GitHub pinned repo cards/rows
- [`app/components/hover-link-hint.tsx`](app/components/hover-link-hint.tsx) — ↗ hover hints
- [`app/components/page-toc.tsx`](app/components/page-toc.tsx) — right-side page TOC rail + panel
- [`app/components/toc-section.tsx`](app/components/toc-section.tsx) — explicit TOC scroll targets
- [`lib/spotify-playlists.ts`](lib/spotify-playlists.ts) — `MUSIC_FOR_LIFE_BASE`, playlist types, map URL helper
- [`app/music-for-life/`](app/music-for-life/) — Music for Life index, `[id]`, `/map`
- [`public/portfolio/oxford-dul-2025/`](public/portfolio/oxford-dul-2025/) — exported training PNGs
- [`lib/now-playing.ts`](lib/now-playing.ts) — Spotify types shared by API + hook
- [`app/globals.css`](app/globals.css) — `.mag-card`, `.mag-card-inset`, `.nav-link`, social link hovers
Expand Down
Loading