- CV header with highlights and keeping-up summary replaces the intro and Now strip - "Projects I'm proudest of": up to six featured panels; screenshots muted until hover - "Also made" list; searching it also lists matching courses - Record section: recognition & volunteering, courses by topic - /work/learning/: searchable course list (plain script), in the sitemap - Top bar: Projects, Record, Writing, CV; no Bluesky link in the work footer - Highlights: only the placement takes the accent (owner, after the preview) Owner looked at the rendered preview on 2026-11-12 before this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.8 KiB
status
| 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)
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, wrongkind, badcompleteddate (incl. 2025-02-30), non-positive or non-integerminutes, non-booleancertificate/highlight, badurl,statuson a competition or notongoing|retired,keywordsnot a list of text, unknown key, file not a list, entry not a map.src/library/types.ts:Recognition(title, kind: 'competition'|'volunteering', result, highlight, detail?, year?, url?, status?) andCourse(title, provider, kind: 'course'|'lab', topic, completed, minutes, certificate, url?, keywords: string[]);Content.recognition,Content.courses.src/library/load.ts: read both optional files (a missing file is not an error); validate as above.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 withurl, oneretired; ≥ 3 topics, labs and courses, some without certificate).fixtures/sparse/gets neither file.docs/CONTENT-CONTRACT.md: both files, as in the spec;introno longer shown on/work/.- Commit
feat(library): recognition.yml and courses.yml.
2. Pure course logic in src/core/courses.ts (commit)
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".src/core/courses.ts(takes a plain course shape, not the library type). Commitfeat(core): course summary and search.
3. Six featured panels and muted screenshots (do not commit)
- Test for the pure part in
sections.ts:featuredOfreturns up to 6;featLayout(n)is['wide','','','wide rev','','']sliced to n, with a trailing lone half madewide: 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. Featured.astrouses it; heading "Projects I'm proudest of", hint, AI legend line at the right (moved from intro).- CSS:
.featimage stages and.rowthumbnails muted (saturate(.5) brightness(.8)), full colour on:hover/:focus-within; transition 300 ms, none underprefers-reduced-motion. Drawn showcases untouched. - Fixtures: six featured fixture projects (add
featuredto existing synthetic ones / add synthetic ones).
4. CV header (do not commit)
src/site/components/work/WorkHeader.astroreplaces the intro block andNowStrip.astro(delete it if unused). Content and fallbacks exactly as spec §1. UsescourseSummary.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.nowlist.
5. Also made + certificate search (do not commit)
ProjectList.tsx: heading "Also made"; new propcourses(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).
- Tests: unit test for the strip's data (pure helper) + Playwright check in
e2e/work.spec.ts.
6. Record section (do not commit)
src/site/components/work/Record.astro(#record) as spec §4;workSectionsgainsrecord.- Build test: both cards, groups, accent on highlights, status words, years only when present, topic table.
7. /work/learning/ (do not commit)
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").- Add to the sitemap page list (
src/site/feeds.ts), not to feeds. - Tests: build test (rows newest first, no page without courses), sitemap test, Playwright (filter,
?q=, no-JS shows all rows ine2e/nojs.spec.ts).
8. Top bar and footer (do not commit)
TopBar.astro: Projects (#featured), Record (#record), Writing, CV — only existing sections; on/work/learning/the links point to/work/#….Work.astro: no Bluesky link. Personal footer and/simpleunchanged. Tests for both footers.
9. Checks and docs (do not commit)
bun run typecheck,bun test,bunx playwright testall 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.tscover/work/and/work/learning/. (No axe dependency in the repo;/work/learning/added to the existing alt-text and motion checks instead; seedocs/TODO.md.) docs/ARCHITECTURE.md(new files,src/core/courses.ts, learning page),docs/DECISIONS.md(the [call]s),DESIGN.mdwork section,docs/TODO.md(anything noticed and left), spec status →implementedafter review.
10. Preview for the owner (main session)
- Build a temporary copy of the real content with the proposed
recognition.yml,courses.yml, featured ranks and showcases (scratchpadcontent-proposal/); serve on port 4392; screenshots at 1440 and 390 in~/. - Wait for his look; then commit tasks 3–9 in small Conventional Commits; remove this plan before merging.