feat(pwa): rebuild /experience with subnav + view/edit toggle (#144) #172

Merged
james merged 1 commit from 144-experience-ds-rebuild into main 2026-06-20 03:54:55 +00:00
Owner

Closes #144.

Summary

  • /experience now opens read-only with a page-level Edit (secondary, pencil-led). Header flips to ghost Cancel + primary Done in edit mode.
  • Segmented sub-nav for Education / Jobs / Contracts (Education default). Implemented inline since there's no Tabs primitive yet — role="tablist", role="tab", aria-selected, aria-controls, tabIndex per active state. Sub-nav stays interactive whether or not edit mode is on (acceptance criterion).
  • Education tab:
    • View — entry cards with institution + type Badge + focus + mono start–end dates + description.
    • Edit — Add entry (primary, leading Plus) in the section head; per-card Pencil + Trash2 IconButton pair. Creating or editing replaces the affected card with a dashed "Editing X…" placeholder while the form sits above the list.
    • Form uses Field + Input + Select + Textarea primitives; start/end dates share a formRow flex.
  • Jobs / Contracts tabs — centered planned-note card with Hammer icon tile, {tab} — coming soon title, body copy from #146's en.json, and a mono "Tracked in epic #4" label.
  • Cancel / Done on the page header are no-op exits — every entry mutation persists eagerly via the existing PUT / PATCH / DELETE. Matches the model the rest of the rebuilds adopted.
  • Split the route into a server page.tsx that prefetches ["educations"] and an experience-client.tsx shell that owns tab + edit state. The Education subsection moved to education-section.tsx (replacing the old education-client.tsx) so the shell can pass editing down without lifting TanStack state.
  • New experience.module.css ports cax-subnav / cax-exp / cax-edu / cax-planned onto the Carol DS aliases. No inline styles.
  • New i18n keys: experience.tabs.aria, experience.comingSoon.title. experience.education.addEntry value dropped its leading "+" since the button supplies a Plus leadingIcon.

Test plan

  • npm run lint / npx tsc --noEmit / npm test all clean (440 passed).
  • View mode in both themes — sub-nav segmented, Education cards with type badge + mono dates.
  • Edit mode in both themes — Add entry button visible, pencil/trash IconButtons per card.
  • Switched to Jobs tab → planned-note card with Hammer icon tile + "Jobs — coming soon".
  • Clicked Add entry → inline form (Institution / Type / Focus / Start date / End date / Description) above the list.
  • HTML inline-style grep returns only style="color:transparent" on the sidebar <img> (Next.js Image default).

🤖 Generated with Claude Code

Closes #144. ## Summary - `/experience` now opens read-only with a page-level `Edit` (secondary, pencil-led). Header flips to ghost `Cancel` + primary `Done` in edit mode. - Segmented sub-nav for Education / Jobs / Contracts (Education default). Implemented inline since there's no `Tabs` primitive yet — `role="tablist"`, `role="tab"`, `aria-selected`, `aria-controls`, `tabIndex` per active state. Sub-nav stays interactive whether or not edit mode is on (acceptance criterion). - **Education tab**: - View — entry cards with institution + type `Badge` + focus + mono start–end dates + description. - Edit — `Add entry` (`primary`, leading `Plus`) in the section head; per-card `Pencil` + `Trash2` `IconButton` pair. Creating or editing replaces the affected card with a dashed `"Editing X…"` placeholder while the form sits above the list. - Form uses `Field` + `Input` + `Select` + `Textarea` primitives; start/end dates share a `formRow` flex. - **Jobs / Contracts tabs** — centered planned-note card with `Hammer` icon tile, `{tab} — coming soon` title, body copy from #146's en.json, and a mono "Tracked in epic #4" label. - Cancel / Done on the page header are no-op exits — every entry mutation persists eagerly via the existing PUT / PATCH / DELETE. Matches the model the rest of the rebuilds adopted. - Split the route into a server `page.tsx` that prefetches `["educations"]` and an `experience-client.tsx` shell that owns tab + edit state. The Education subsection moved to `education-section.tsx` (replacing the old `education-client.tsx`) so the shell can pass `editing` down without lifting TanStack state. - New `experience.module.css` ports `cax-subnav` / `cax-exp` / `cax-edu` / `cax-planned` onto the Carol DS aliases. No inline styles. - New i18n keys: `experience.tabs.aria`, `experience.comingSoon.title`. `experience.education.addEntry` value dropped its leading "+" since the button supplies a `Plus` `leadingIcon`. ## Test plan - [x] `npm run lint` / `npx tsc --noEmit` / `npm test` all clean (440 passed). - [x] View mode in both themes — sub-nav segmented, Education cards with type badge + mono dates. - [x] Edit mode in both themes — `Add entry` button visible, pencil/trash IconButtons per card. - [x] Switched to Jobs tab → planned-note card with Hammer icon tile + "Jobs — coming soon". - [x] Clicked `Add entry` → inline form (Institution / Type / Focus / Start date / End date / Description) above the list. - [x] HTML inline-style grep returns only `style="color:transparent"` on the sidebar `<img>` (Next.js Image default). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(pwa): rebuild /experience with subnav + view/edit toggle (#144)
Some checks failed
Commits / Conventional Commits (pull_request) Successful in 11s
PR / Static analysis (pull_request) Successful in 34s
PR / OSV-Scanner (pull_request) Successful in 22s
PR / Trivy (image) (pull_request) Failing after 1m4s
PR / Package age policy (soft) (pull_request) Successful in 15s
Secrets / gitleaks (pull_request) Successful in 16s
PR / Test (postgres) (pull_request) Successful in 4m7s
PR / Lint (pull_request) Successful in 4m8s
PR / npm audit (pull_request) Successful in 4m40s
PR / Test (sqlite) (pull_request) Successful in 5m7s
PR / Coverage (soft) (pull_request) Successful in 5m17s
PR / Typecheck (pull_request) Successful in 16m30s
PR / Build (pull_request) Successful in 23m47s
e4b106846d
The Experience page now opens read-only with a page-level Edit
button (secondary, pencil-led) and a segmented sub-nav for
Education / Jobs / Contracts (Education default). Sub-nav is
keyboard-accessible with role="tab" + role="tablist" + aria-selected
+ aria-controls, and stays interactive whether or not edit mode is
on (per the ticket's acceptance criterion).

Education tab — view mode renders the entry cards from the design:
institution + type Badge + focus + mono start-end dates +
description. Edit mode reveals an "Add entry" Button (primary,
leading Plus icon) in the section head and a pencil + trash
IconButton pair on each card. Creating or editing an entry replaces
the corresponding card with a dashed placeholder while the form
sits above the list. Cancel and Done are no-op exits — every entry
mutation persists eagerly via the existing PUT / PATCH / DELETE.

Jobs / Contracts tabs — centred planned-note card with a Hammer
icon tile, "{tab} — coming soon" title, body copy from #146's
en.json, and a "Tracked in epic #4" mono ticket label.

Split the route into a server page.tsx that prefetches
["educations"] and an experience-client.tsx shell. The Education
subsection moved into education-section.tsx (replacing the old
education-client.tsx) so the page shell can pass `editing` down
without sharing TanStack state.

Carol DS token aliases throughout; no inline styles. New
experience.module.css ports cax-subnav / cax-exp / cax-edu /
cax-planned from the design package.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
james merged commit 1ebc4aaee2 into main 2026-06-20 03:54:55 +00:00
james deleted branch 144-experience-ds-rebuild 2026-06-20 03:54:56 +00:00

Trivy (container image)

Threshold: high  ·  Total findings: 121  ·  At/above threshold: 1

critical high medium low
0 1 50 70
severity id package installed / range fix
high CVE-2026-12151 undici 6.25.0 6.27.0, 7.28.0, 8.5.0
<!-- scanner-comment: trivy --> ### Trivy (container image) **Threshold:** `high` &nbsp;·&nbsp; **Total findings:** 121 &nbsp;·&nbsp; **At/above threshold:** 1 | critical | high | medium | low | |---:|---:|---:|---:| | 0 | 1 | 50 | 70 | | severity | id | package | installed / range | fix | |---|---|---|---|---| | high | [CVE-2026-12151](https://avd.aquasec.com/nvd/cve-2026-12151) | undici | 6.25.0 | `6.27.0, 7.28.0, 8.5.0` |

📊 Test coverage

Patch coverage: 0.0% (0/301 added lines) ⚠️ (soft target ≥ 80%)

Overall (app/, lib/, db/, excluding UI per ADR-0019):

Metric Value Soft target
Lines 75.3% ≥ 50%
Branches 80.8% ≥ 75%
Functions 88.2% informational

Changed files in this PR (source only — tests excluded):

File Patch coverage Overall lines Branches
app/(app)/experience/education-section.tsx 0.0% (0/301) 0.0% 0.0%

Soft thresholds per ADR-0019. Coverage is informational and does not block merge.

<!-- coverage-comment --> ## 📊 Test coverage **Patch coverage:** 0.0% (0/301 added lines) ⚠️ *(soft target ≥ 80%)* **Overall** (`app/`, `lib/`, `db/`, excluding UI per ADR-0019): | Metric | Value | Soft target | |---|---|---| | Lines | 75.3% ✅ | ≥ 50% | | Branches | 80.8% ✅ | ≥ 75% | | Functions | 88.2% | informational | **Changed files in this PR** (source only — tests excluded): | File | Patch coverage | Overall lines | Branches | |---|---|---|---| | `app/(app)/experience/education-section.tsx` | 0.0% (0/301) | 0.0% | 0.0% | Soft thresholds per [ADR-0019](docs/adr/0019-coverage-soft-targets.md). Coverage is informational and does not block merge.
Sign in to join this conversation.
No description provided.