diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 68be0f3..672af28 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -3,6 +3,16 @@ Where development stopped, and how to pick it up. Delete or rewrite this file when the next session starts. Everything a new agent needs from the 2026-11-11 session is in this file or in a file it points to. +## 2026-11-12: spec 009 merged (CV-first `/work/`) + +Spec 009 (`docs/specs/009-work-page-cv-first.md`, mockup `mockups/work-k2.html`) was designed with the owner, built +(Opus 5.5 subagent, checked by the main session), previewed on a copy of the real content, adjusted once (only the +placement of a highlight is orange) and merged into `main` locally with his approval. The content for it +(`recognition.yml`, `courses.yml`, featured ranks 1–6 + showcases, the spreadsheet in `sources/`) is committed and +merged into `main` of `~/portfolio-next-content` locally. **Neither repo is pushed** until the owner says so; push the +app first (an older app ignores the new content files, but the new page wants them). Axe checks run in +`e2e/a11y.spec.ts` with `color-contrast` disabled until the dim tokens are retuned (`docs/TODO.md`). + ## State in one paragraph The site is **live** at `lucaswinther.info` (behind Cloudflare) since the DNS cutover on 2026-11-10; the 2021 site is at diff --git a/docs/plans/009-work-page-cv-first.md b/docs/plans/009-work-page-cv-first.md deleted file mode 100644 index 34e98f8..0000000 --- a/docs/plans/009-work-page-cv-first.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -status: approved ---- - -# Plan 009 — `/work/`: CV first, six proud projects, record of competitions and courses - -Spec: `docs/specs/009-work-page-cv-first.md`. Mockup: `mockups/work-k2.html`, `mockups/shots/work-k2-1440.png` -(built from `mockups/tech-r3-c.html`, whose featured panels are already the site's `Featured.astro`). -Branch: `feat/work-page-cv-first`. Commands: `bun run typecheck`, `bun test`, `bunx playwright test` (`--workers=2` -if pages crash). - -**Commit rule.** Tasks 1–2 (data and pure logic) are committed as they finish. Tasks 3–9 change what visitors see: -build and test them, but leave them **uncommitted** until the owner has looked at the rendered preview (his standing -rule: visual changes are shown before they are committed). Task 10 is the preview. - -TDD for every task: write the failing test, run it and see it fail, write the code, see it pass. -Test imports use explicit `.ts` extensions. `src/core` stays pure (no imports from other `src/` folders, no I/O). - -## 1. Content: `recognition.yml` and `courses.yml` (commit) -- [x] `test/library/load.test.ts`: both files load (order kept for recognition); missing files → empty lists; one error - per problem with file and field: missing required field, wrong `kind`, bad `completed` date (incl. 2025-02-30), - non-positive or non-integer `minutes`, non-boolean `certificate`/`highlight`, bad `url`, `status` on a - competition or not `ongoing|retired`, `keywords` not a list of text, unknown key, file not a list, entry not a map. -- [x] `src/library/types.ts`: `Recognition` (`title, kind: 'competition'|'volunteering', result, highlight, detail?, - year?, url?, status?`) and `Course` (`title, provider, kind: 'course'|'lab', topic, completed, minutes, - certificate, url?, keywords: string[]`); `Content.recognition`, `Content.courses`. -- [x] `src/library/load.ts`: read both optional files (a missing file is not an error); validate as above. -- [x] `fixtures/content/recognition.yml`, `fixtures/content/courses.yml`: synthetic, enough to exercise every branch - (≥ 4 highlighted entries so the "+N more" shows; both kinds; one with `url`, one `retired`; ≥ 3 topics, labs and - courses, some without certificate). `fixtures/sparse/` gets neither file. -- [x] `docs/CONTENT-CONTRACT.md`: both files, as in the spec; `intro` no longer shown on `/work/`. -- [x] Commit `feat(library): recognition.yml and courses.yml`. - -## 2. Pure course logic in `src/core/courses.ts` (commit) -- [x] `test/core/courses.test.ts`: `courseSummary(courses)` → `{ count, certificates, minutes, since (YYYY-MM), topics: - [{ topic, courses, labs, certificates, minutes }] }` with topics ordered by minutes desc then name; - `courseMatches(course, query)` (case-insensitive over title, provider, topic, keywords; empty query → false); - `formatHours(minutes)` ("9.4h"; "~27 h" form for the totals is the caller's); `monthYear('2025-02')` → "Feb 2025". -- [x] `src/core/courses.ts` (takes a plain course shape, not the library type). Commit `feat(core): course summary and search`. - -## 3. Six featured panels and muted screenshots (do not commit) -- [x] Test for the pure part in `sections.ts`: `featuredOf` returns up to 6; `featLayout(n)` is - `['wide','','','wide rev','','']` sliced to n, with a trailing lone half made `wide`: - n=1 → wide; n=2 → wide, wide; n=3 → wide, half, half; n=4 → … wide rev; n=5 → … wide rev, wide; n=6 → as listed. -- [x] `Featured.astro` uses it; heading "Projects I'm proudest of", hint, AI legend line at the right (moved from intro). -- [x] CSS: `.feat` image stages and `.row` thumbnails muted (`saturate(.5) brightness(.8)`), full colour on - `:hover`/`:focus-within`; transition 300 ms, none under `prefers-reduced-motion`. Drawn showcases untouched. -- [x] Fixtures: six featured fixture projects (add `featured` to existing synthetic ones / add synthetic ones). - -## 4. CV header (do not commit) -- [x] `src/site/components/work/WorkHeader.astro` replaces the intro block and `NowStrip.astro` (delete it if unused). - Content and fallbacks exactly as spec §1. Uses `courseSummary`. -- [x] `test/site/build-pages.test.ts`: header rows, highlights (max 3, "+N more"), keeping-up count/line/chips, - blocks left out on the sparse fixture, `site.now` list. - -## 5. Also made + certificate search (do not commit) -- [x] `ProjectList.tsx`: heading "Also made"; new prop `courses` (minimal fields); when the query is non-empty show the - matching-courses strip (max 5, "+ N more on the learning page →" to `/work/learning/?q=`), and the count text - "

project(s) · course(s) match" (spec: courses, labs included; a seal marks the ones with a certificate). -- [x] Tests: unit test for the strip's data (pure helper) + Playwright check in `e2e/work.spec.ts`. - -## 6. Record section (do not commit) -- [x] `src/site/components/work/Record.astro` (`#record`) as spec §4; `workSections` gains `record`. -- [x] Build test: both cards, groups, accent on highlights, status words, years only when present, topic table. - -## 7. `/work/learning/` (do not commit) -- [x] `src/site/pages/work/learning.astro` (only when courses exist) + `src/site/scripts/learning-filter.ts` (plain - script: search, topic buttons, `?q=`, "No course matches"). -- [x] Add to the sitemap page list (`src/site/feeds.ts`), not to feeds. -- [x] Tests: build test (rows newest first, no page without courses), sitemap test, Playwright (filter, `?q=`, - no-JS shows all rows in `e2e/nojs.spec.ts`). - -## 8. Top bar and footer (do not commit) -- [x] `TopBar.astro`: Projects (`#featured`), Record (`#record`), Writing, CV — only existing sections; on - `/work/learning/` the links point to `/work/#…`. -- [x] `Work.astro`: no Bluesky link. Personal footer and `/simple` unchanged. Tests for both footers. - -## 9. Checks and docs (do not commit) -- [x] `bun run typecheck`, `bun test`, `bunx playwright test` all pass; update existing tests that asserted the old - intro, "All projects"/"Everything else" headings, the Now strip or a four-panel cap. -- [ ] Axe checks in `e2e/a11y.spec.ts` cover `/work/` and `/work/learning/`. (No axe dependency in the repo; `/work/learning/` added to the existing alt-text and motion checks instead; see `docs/TODO.md`.) -- [x] `docs/ARCHITECTURE.md` (new files, `src/core/courses.ts`, learning page), `docs/DECISIONS.md` (the [call]s), - `DESIGN.md` work section, `docs/TODO.md` (anything noticed and left), spec status → `implemented` after review. - -## 10. Preview for the owner (main session) -- [x] Build a temporary copy of the real content with the proposed `recognition.yml`, `courses.yml`, featured ranks - and showcases (scratchpad `content-proposal/`); serve on port 4392; screenshots at 1440 and 390 in `~/`. -- [x] Wait for his look; then commit tasks 3–9 in small Conventional Commits; remove this plan before merging.