Add complete multi-theme dashboard system including: - 8 selectable themes with persistent per-browser preferences - Theme bootstrap script to prevent FOUC on page load - 12+ reusable chart components (area, bar, donut, radial gauge, etc) - Custom checkbox UI component - New settings page for appearance customization Other changes: - Optimize supplier map API payload with getMappableSuppliers helper - Add aria-label attributes to back buttons on detail pages for better accessibility - Update next.config.ts to include new local development IP 192.168.1.128 - Update site manifest with all new favicon and PWA assets - Fix styling and layout spacing in rewrite quote modal
3.9 KiB
WFDASH — Multi-theme system
Ship 8 selectable themes (5 standard + 3 standout) with a warm/dark mode toggle. Theme selection persists per browser. No FOUC on reload.
File map
src/
├── lib/
│ ├── themes.ts # 8-theme registry (id, label, fonts, swatches)
│ └── use-theme-id.ts # Client hook to read/write active theme
├── styles/
│ └── themes.css # OKLCH token blocks for all 8 themes (warm + dark)
├── components/
│ ├── theme-provider.tsx # next-themes wrapper (manages warm/dark mode)
│ ├── theme-bootstrap.tsx # Inline <head> script — prevents FOUC
│ ├── theme-picker.tsx # Settings UI — mini preview cards
│ └── sidebar.tsx # +Settings nav item
└── app/
├── layout.tsx # +Inter, Space Grotesk, DM Sans, Playfair,
│ # Lato, Nunito, Outfit, JetBrains Mono via next/font
├── globals.css # Imports themes.css
└── (app)/settings/page.tsx # New Settings page with Appearance section
The 8 themes
| # | ID | Category | Fonts | Radius | Notes |
|---|---|---|---|---|---|
| 1 | crisp |
Standard | Inter | 10px | Default. Calm, professional. |
| 2 | midnight |
Standard | Space Grotesk + DM Sans | 12px | Dark control-room. |
| 3 | editorial |
Standard | Playfair Display + Lato | 6px | Warm cream + serif. |
| 4 | bento |
Standard | Inter | 18px | Tinted tiles, big radius. |
| 5 | field-ops |
Standard | Inter | 8px | Dense, navy sidebar, gold CTA. |
| 6 | terminal |
Standout | JetBrains Mono | 0px | Green CRT, scanlines, mono. |
| 7 | blueprint |
Standout | JetBrains Mono + Inter | 2px | White-on-blue, grid, technical. |
| 8 | confetti |
Standout | Outfit + Nunito | 20px | Pastel, playful, oversized radius. |
How it works
Theme identity = data-theme="<id>" on <html>
- Set by
theme-bootstrap.tsxbefore hydration (prevents flash) - Updated by
useThemeId()hook when user picks a new theme - Persisted to
localStorage["wfdash-theme"]
Mode (warm/dark) = .warm or .dark class on <html>
- Managed by
next-themes(already wired intheme-provider.tsx) - Persisted to
localStorage["wfdash-mode"] - Independent from theme — you can mix any theme with any mode
shadcn/ui adapts automatically because all components read from CSS vars
(--background, --primary, --accent, --radius, etc.) that themes.css
overrides per theme.
How to add a new theme
- Add an entry to
THEMESinsrc/lib/themes.ts - Add a
[data-theme="<id>"]block insrc/styles/themes.css(copy an existing theme and adjust tokens). Add.darkvariant if it works in dark mode. - Add
radiusMap[<id>]intheme-bootstrap.tsx - Done — picker picks it up automatically
How to ship a font swap
Each theme has fontHeading + fontBody pointing at a CSS var. Add the font to
src/app/layout.tsx via next/font/google and register its .variable. Then
add the binding in src/styles/themes.css:
[data-theme="<id>"] {
--font-heading: var(--font-<your-font>);
--font-body: var(--font-<your-font>);
}
The body picks up var(--font-body) automatically; font-heading-theme class
applies heading font where you need it.
Standout theme caveats
The 3 standout themes override default component styling:
- Terminal — sharp 0px radius, uppercase headings, mono everywhere, scanline body overlay
- Blueprint — sharp 2px radius, uppercase headings, grid overlay, transparent inputs
- Confetti — 20px radius (capped — shadcn's
--radius-4xlcalc clamps at ~1.6rem)
All three are still built on the brand palette (#4C96D7 / #F2AF58 / #E94E49) but applied in different ways. They're tested against the standard shadcn components but may render slightly differently from the 5 standard themes — by design.