Tasks — add-reference-web-dark-mode
tasks17/20
1. Brand tokens
- 1.1 Add
--surface-tintlight/dark token inpackages/pdpp-brand/base.cssand replace literalwhitekeyword incolor-mix(...)expressions and the hardcodedoklch(1 0 0)in the body gradient. - 1.2 Add
html.dark { ... }override block inpackages/pdpp-brand/base.csswith full dark token palette (background, foreground, card, popover, primary, secondary, muted, accent, destructive, border, input, ring, success, warning, edu-fg, success-wash, success-wash-strong, primary-wash, verified-wash, warning-wash, human, human-wash, surface-tint). - 1.3 Update
packages/pdpp-brand/docs.cssto use--surface-tintrather than literalwhitein thecolor-mixmixers it uses for sidebar tint, prose body color, prose code background, and table header. - 1.4 Override scrollbar thumb color under
html.darkso theoklch(0 0 0 / …)light-mode thumb does not vanish on dark.
2. Theme runtime
- 2.1 Add inline pre-hydration theme script in
apps/web/src/app/layout.tsx(head, dangerouslySetInnerHTML) that readslocalStorage+prefers-color-schemeand applieshtml.dark,data-theme, andstyle.colorSchemebefore paint. - 2.2 Add
apps/web/src/components/theme/theme-provider.tsx(client) that exposes{ theme, resolvedTheme, setTheme }via context, persists tolocalStorage, and listens for system preference changes when in"system"mode. - 2.3 Add
apps/web/src/components/theme/theme-toggle.tsx(client) — a small icon button cycling light → dark → system, with accessible labels.
3. Mount points
- 3.1 Wrap
RootProvider's children withThemeProviderinapps/web/src/app/layout.tsx. - 3.2 Place
<ThemeToggle />in the dashboardTopbar(apps/web/src/app/dashboard/components/shell.tsx). - 3.3 Place
<ThemeToggle />in the publicSiteHeader(apps/web/src/components/site-header.tsx).
4. Surface polish
- 4.1 Audit dashboard surfaces (records, runs, deployment, search,
overview) for any hardcoded color utilities that would regress in dark mode.
Convert to semantic tokens or add
dark:variants where unavoidable. - 4.2 Verify shadcn primitives (
button,badge,card,dialog,popover,input,select,tooltip) render correctly in dark mode under the new tokens — they already usedark:variants in places, so most just needs the underlying tokens to be right.
5. Validation
- 5.1
pnpm --dir apps/web run types:check - 5.2
pnpm --dir apps/web run check - 5.3
pnpm --dir apps/web run build - 5.4
openspec validate add-reference-web-dark-mode --strict - 5.5
openspec validate --all --strict
6. Deferred
- 6.1 Marketing
/hero polish in dark mode (illustrations/washes use light-mode-baked gradients; legible but not a deliberate dark composition). - 6.2 Dedicated docs toggle inside Fumadocs chrome — currently controlled
by the dashboard/site header toggle via the shared
html.darkclass. - 6.3
/paletteand/designreference pages beyond falling out of the new tokens.
Acceptance checks
- Booting the dashboard with the OS in dark mode and no stored preference renders dark on first paint with no flash.
- Toggling the theme changes both the dashboard chrome and the embedded
/docsand/referencesurfaces in the same window. - Reload preserves the explicit choice; clearing storage falls back to system preference.
- Status badges (online/offline, success/destructive) remain identifiable at a glance in dark mode.