You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: project/2026-06-13-v5-dual-theme-uzh-neutral-plan.md
+12-2Lines changed: 12 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -83,37 +83,44 @@ In `tailwind.css` `@theme inline` + `:root` (neutral defaults) and `themes.css`
83
83
Dep graph: `S0 → S1 → {S2, S3, S4} → S5 → S6`. S2/S3/S4 parallelizable after S1.
84
84
85
85
### Slice 0 — Token foundation + data-theme switch + Ladle toggle + Button pilot
86
+
86
87
- Do: add `themes.css`; restructure `tailwind.css` (neutral default on `:root`, uzh block, status+shadow tokens, font `@import`, font-sans simplification). Ladle `.ladle/components.tsx`: import `themes.css` + add neutral/uzh toggle on story wrapper. Verify Button renders both themes (no `uzh-*` in Button — confirm it routes through `bg-primary-100`/`text-primary-foreground`).
87
88
- Check: Ladle Button story toggles neutral↔uzh, colors switch; `tsc` clean; no regression in other stories. Screenshot both.
### Slice 1 — Purge hardcoded uzh-* so all components theme-switch
92
+
### Slice 1 — Purge hardcoded uzh-\* so all components theme-switch
93
+
92
94
- Do: route the 7 blocker components through semantic tokens. `UserNotification.tsx` switch map → status tokens (A5). `Workflow.tsx` default `twStyles` → `primary-*`. `Switch.tsx` disabled, `StepProgress.tsx` error, `ColorPicker.tsx` border, `Checkbox.tsx`, `Select.tsx` → `primary-*`/`destructive`/status. Grep-confirm zero remaining `uzh-blue-*` (and other `uzh-*` that should theme) in component TSX.
93
95
- Check: Ladle stories for all 7 in both themes; spot-check disabled Switch, error StepProgress, each UserNotification type; neutral shows NO UZH blue leak. `tsc` clean.
94
96
- Commit: `refactor(theme): route hardcoded uzh-* through semantic tokens`
- Do: `src/ThemeProvider.tsx` (`<div data-theme>` + `useTheme`), export from `index.ts`. Ladle: all stories run under ThemeProvider + global toggle. `README`/`MIGRATION.md`: data-theme opt-in; **UZH apps add `data-theme="uzh"`** (D1). Add `_adherence` oxlint config as internal dev script (A2). Final security review subagent (`$security-review`).
118
125
- Check: full Ladle suite toggles on every component; ThemeProvider sample page switches cleanly; `tsc`; lint passes; security review clean. Screenshots for MR (before/after, both themes).
@@ -137,7 +144,7 @@ Reference this plan path. Work one slice at a time. Update `Progress` each slice
137
144
-[x] Setup: zip extracted to `uzh-design-reference/`; zip + extract gitignored (verified). Branch `v5` created off `main`@`0a78b2c`. Exploration workflow done. 4 forks resolved with user.
138
145
-[x] Plan committed; user approved full slice-by-slice execution + MR + demo deploy.
139
146
-[x] S0 Token foundation + Button pilot. Added `src/themes.css` (`:root,[data-theme=neutral]` neutral defaults + `[data-theme=uzh]` UZH overrides), routed fonts/primary/secondary/status through `--theme-*` indirection in `tailwind.css`, Google Fonts @import, Ladle neutral/uzh+dark switcher. Verified: tsc clean; `ladle build` ok; compiled CSS asserts `.bg-primary-100{background:var(--theme-color-primary)}`, neutral=`oklch(20.5% 0 0)`, uzh=`var(--color-uzh-blue-100)`; neutral font=system, uzh=Source Sans 3. Review+simplify: added font `var(...,fallback)` for robustness, pinned Ladle toolbar text colour. Deferred to S6 migration docs: `--theme-font-primary`/`--source-sans-pro` injection points removed (v5 break); shadcn `--secondary` stays neutral in uzh (matches v4; UZH red via `bg-secondary-100`).
-[x] S2 Alert + Badge. Alert: added neutral/info/success/warning/error (tinted bg + 4px coloured left border + variant-coloured consumer icon); kept default/destructive as legacy surfaces. Badge: added success/warning/info/error solid variants; `error` dedup'd to shared `destructiveBadge` const. Updated Alert + Badge stories (Variants showcase, Status row) + docs. Review fixes: kept warning icon `text-warning-foreground` for visibility on light tint (commented), removed redundant `[&>svg]:text-destructive`. Verified tsc/build/format; CSS has bg-/border-l-/-background status utils.
142
149
-[x] S3 Input + Textarea invalid. Added `invalid?: boolean` to base Input + Textarea → native `aria-invalid` (`invalid ?? ariaInvalid`, no `{...props}` clobber). Existing shadcn classes already give destructive border/ring on aria-invalid + UZH-blue `focus-visible:ring-ring` — no class churn. Wired `invalid={!!error && isTouched}` from forms/TextField (2 branches) + forms/TextareaField (2 branches). Review fix: added missing `isTouched` guard to TextareaField error tooltip (consistency w/ TextField + aria gating). Existing Error stories demo it. Verified tsc/build/format.
143
150
-[x] S4 Refinement batch (scoped to additive/low-regression). Avatar: `size` prop sm/md/lg (28/40/56px, no default → legacy 32px kept); fallback `bg-primary-20 text-primary-100` (theme-tinted, ~7:1 contrast both themes). Table (shadcn): `hoverable?: boolean` opt-out. Avatar story Sizes example. Verified tsc/build/format; CSS has size-7/10/14. DELIBERATELY NOT forced (regression-averse, components already theme-switch + close to spec): uppercase shadcn table headers, 13px/600 labels, shimmer skeleton (kept animate-pulse), Progress (already h-2 + themed primary). MIGRATION note: AvatarFallback bg changed muted→primary-20 (override via className if undesired).
@@ -149,10 +156,13 @@ Reference this plan path. Work one slice at a time. Update `Progress` each slice
149
156
- Next action: final security review subagent (whole branch), then `$df-mr-description-writer` MR vs `main` + both-theme screenshots; confirm gh-pages demo deploy carries theme toggle.
150
157
151
158
### Verification approach note
159
+
152
160
Per-slice: `tsc` + `ladle build` + targeted compiled-CSS/grep assertions. Live visual both-theme screenshots consolidated at finish for MR evidence (browser set up once across all components) rather than per slice.
153
161
154
162
## Next Steps (running)
155
163
156
164
- Dark-mode for status tokens: `.dark` overrides only core shadcn vars, not the new `--theme-*`/status tokens, so status alerts/badges keep light tints on a dark page. Dark is an orthogonal axis; out of v5 scope. Follow-up: add `.dark` overrides (or `[data-theme=uzh].dark`) for status + theme tokens.
157
165
- Confirm neutral palette choice (zinc vs slate ramp) at S0 start — low-stakes, pick zinc to match shadcn default.
158
166
- After v5 publish: open follow-up for v5.x composites (filter rail, proposal card, app shells) and Preact package theming if still needed.
167
+
- Security review (whole branch) DONE_WITH_CONCERNS, 0 Critical/Important. Follow-up: self-host Source Sans 3 + JetBrains Mono and drop the Google Fonts `@import` for GDPR/CSP-sensitive UZH deployments (privacy: runtime fetch to fonts.googleapis.com leaks user IP). Documented as CSP/privacy note in MIGRATION.md for now. Ladle `as Theme` cast is dev-tool-only (not shipped) — no action.
168
+
- Deferred dev-lint (A2): author a Tailwind-aware token-regression guard if wanted; the reference `_adherence.oxlintrc.json` does not fit a Tailwind+cva codebase (≈83 false positives, 0 catches).
0 commit comments