feat(themes): add theme picker with swatch previews and per-theme fonts

PART 1: Add missing CSS variables to all ui objects
- Add --bg-inset, --bg-muted for component backgrounds
- Add --success, --warning as aliases for --status-success/warning
- Add --warning-muted for warning background states
- Each theme now has 32 CSS variables

PART 2: Per-theme font support
- Move --font-sans and --font-mono from :root to ui objects
- Add fontImports array to theme config (for future custom fonts)
- applyThemeUI() now manages <link> tags for font imports
- Existing themes use empty fontImports (system fonts already loaded)

PART 3: Swatch preview colors
- Add swatch array (3 hex colors) to each theme for visual preview
- light: warm tan, sage green, khaki
- dark: dark brown, sage green, tan
- clean: light gray, Google blue, Google green
- themeList() now returns swatch in result shape

PART 4: Theme picker UI
- New ThemePicker component replaces icon toggle in header
- Palette icon trigger opens popover below
- Shows all themes as circular swatches (conic gradient)
- Active theme has accent ring indicator
- Click swatch to apply theme, closes popover
- Click outside or Escape closes popover
- Styled with current theme CSS variables

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Matt 2026-05-01 17:42:51 +00:00
commit a7fd4e4e8c
5 changed files with 263 additions and 53 deletions

View file

@ -162,29 +162,46 @@ const cleanColors = {
* Clean Google-inspired white panels with standard gray text
*/
const cleanUI = {
// Fonts
'--font-sans': "'Inter', system-ui, -apple-system, sans-serif",
'--font-mono': "'JetBrains Mono', ui-monospace, monospace",
// Backgrounds
'--bg-base': '#f5f5f5',
'--bg-raised': '#ffffff',
'--bg-overlay': '#ffffff',
'--bg-input': '#ffffff',
'--bg-inset': '#f0f0f0',
'--bg-muted': '#f8f9fa',
// Text
'--text-primary': '#202124',
'--text-secondary': '#5f6368',
'--text-tertiary': '#9aa0a6',
'--text-inverse': '#ffffff',
// Borders
'--border': '#dadce0',
'--border-subtle': '#e8eaed',
// Accent
'--accent': '#1a73e8',
'--accent-hover': '#1557b0',
'--accent-muted': '#e8f0fe',
// Tan
'--tan': '#f9a825',
'--tan-muted': '#fef7e0',
// Pins
'--pin-origin': '#34a853',
'--pin-destination': '#ea4335',
'--pin-intermediate': '#5f6368',
'--pin-stroke': '#ffffff',
// Status
'--status-success': '#34a853',
'--status-warning': '#fbbc04',
'--status-danger': '#ea4335',
'--success': '#34a853',
'--warning': '#fbbc04',
'--warning-muted': '#fef7e0',
// Route
'--route-line': '#1a73e8',
// Shadows
'--shadow': '0 1px 3px rgba(60, 64, 67, 0.15), 0 1px 2px rgba(60, 64, 67, 0.1)',
'--shadow-lg': '0 2px 6px rgba(60, 64, 67, 0.2), 0 1px 3px rgba(60, 64, 67, 0.15)',
}