feat: theme family system with 12 color palettes + NavRail redesign
Theme system:
- Two-layer architecture: mode (light/dark/system via next-themes) + theme family (color palette via CSS variables)
- 12 theme families: Default, GitHub, Rosé Pine, Tokyo Night, Everforest, Nord, Kanagawa, Night Owl, Poimandres, Vesper, Horizon, SynthWave '84
- Per-family code block highlighting for Prism, HLJS, and Shiki (no more generic oneLight/oneDark fallback)
- Anti-FOUC: synchronous script in <head> reads localStorage and sets data-theme-family before paint
- Theme JSON files in themes/ directory, auto-discovered by server-side loader
- OKLCH color space for all values; CSS specificity html[data-theme-family] beats :root
UI changes:
- NavRail: moved Settings to bottom (replacing theme toggle), removed light/dark toggle button
- Settings: merged General controls into one card with dividers; Appearance section with live Shiki code preview
- Replaced hardcoded blue-500/blue-600 with primary/primary-foreground across 19 components
- Appearance settings: pill mode selector (light/dark/system), theme family dropdown, live code preview
New files:
- src/lib/theme/{types,loader,render-css,context,code-themes}.ts — core theme infrastructure
- src/components/layout/ThemeFamilyProvider.tsx — client context provider
- src/components/settings/AppearanceSection.tsx — appearance settings UI
- src/hooks/useAppTheme.ts — combined theme hook
- themes/*.json — 12 theme family definitions
- docs/handover/theme-system.md — handover documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
7ad66f82c4
commit
4da188bfe5
53 files changed
+2446
-144
No files matched your search
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"id": "github",
|
||||
"label": "GitHub",
|
||||
"order": 1,
|
||||
"description": "Clean and familiar, inspired by GitHub's Primer design system",
|
||||
"codeTheme": {
|
||||
"light": "ghcolors",
|
||||
"dark": "vscDarkPlus"
|
||||
},
|
||||
"shikiTheme": {
|
||||
"light": "github-light-default",
|
||||
"dark": "github-dark-default"
|
||||
},
|
||||
"light": {
|
||||
"background": "oklch(1.000 0 0)",
|
||||
"foreground": "oklch(0.254 0.011 254.0)",
|
||||
"card": "oklch(1.000 0 0)",
|
||||
"cardForeground": "oklch(0.254 0.011 254.0)",
|
||||
"popover": "oklch(1.000 0 0)",
|
||||
"popoverForeground": "oklch(0.254 0.011 254.0)",
|
||||
"primary": "oklch(0.540 0.191 257.5)",
|
||||
"primaryForeground": "oklch(1.000 0 0)",
|
||||
"secondary": "oklch(0.947 0.007 247.9)",
|
||||
"secondaryForeground": "oklch(0.338 0.015 252.3)",
|
||||
"muted": "oklch(0.947 0.007 247.9)",
|
||||
"mutedForeground": "oklch(0.531 0.017 251.3)",
|
||||
"accent": "oklch(0.978 0.003 247.9)",
|
||||
"accentForeground": "oklch(0.338 0.015 252.3)",
|
||||
"destructive": "oklch(0.552 0.205 24.5)",
|
||||
"border": "oklch(0.876 0.012 248.0)",
|
||||
"input": "oklch(0.876 0.012 248.0)",
|
||||
"ring": "oklch(0.540 0.191 257.5)",
|
||||
"chart1": "oklch(0.540 0.191 257.5)",
|
||||
"chart2": "oklch(0.546 0.147 146.3)",
|
||||
"chart3": "oklch(0.700 0.160 48.0)",
|
||||
"chart4": "oklch(0.620 0.165 310.0)",
|
||||
"chart5": "oklch(0.600 0.120 185.0)",
|
||||
"sidebar": "oklch(0.978 0.003 247.9)",
|
||||
"sidebarForeground": "oklch(0.254 0.011 254.0)",
|
||||
"sidebarPrimary": "oklch(0.540 0.191 257.5)",
|
||||
"sidebarPrimaryForeground": "oklch(1.000 0 0)",
|
||||
"sidebarAccent": "oklch(0.947 0.007 247.9)",
|
||||
"sidebarAccentForeground": "oklch(0.338 0.015 252.3)",
|
||||
"sidebarBorder": "oklch(0.876 0.012 248.0)",
|
||||
"sidebarRing": "oklch(0.540 0.191 257.5)"
|
||||
},
|
||||
"dark": {
|
||||
"background": "oklch(0.176 0.014 258.4)",
|
||||
"foreground": "oklch(0.943 0.011 243.7)",
|
||||
"card": "oklch(0.220 0.016 256.8)",
|
||||
"cardForeground": "oklch(0.943 0.011 243.7)",
|
||||
"popover": "oklch(0.220 0.016 256.8)",
|
||||
"popoverForeground": "oklch(0.943 0.011 243.7)",
|
||||
"primary": "oklch(0.569 0.202 259.7)",
|
||||
"primaryForeground": "oklch(1.000 0 0)",
|
||||
"secondary": "oklch(0.267 0.015 256.8)",
|
||||
"secondaryForeground": "oklch(0.857 0.014 248.0)",
|
||||
"muted": "oklch(0.267 0.015 256.8)",
|
||||
"mutedForeground": "oklch(0.662 0.018 250.9)",
|
||||
"accent": "oklch(0.246 0.015 256.8)",
|
||||
"accentForeground": "oklch(0.943 0.011 243.7)",
|
||||
"destructive": "oklch(0.665 0.205 27.0)",
|
||||
"border": "oklch(0.330 0.015 252.3)",
|
||||
"input": "oklch(0.330 0.015 252.3)",
|
||||
"ring": "oklch(0.569 0.202 259.7)",
|
||||
"chart1": "oklch(0.569 0.202 259.7)",
|
||||
"chart2": "oklch(0.600 0.140 146.0)",
|
||||
"chart3": "oklch(0.750 0.150 48.0)",
|
||||
"chart4": "oklch(0.680 0.170 310.0)",
|
||||
"chart5": "oklch(0.650 0.120 185.0)",
|
||||
"sidebar": "oklch(0.104 0.019 248.3)",
|
||||
"sidebarForeground": "oklch(0.943 0.011 243.7)",
|
||||
"sidebarPrimary": "oklch(0.569 0.202 259.7)",
|
||||
"sidebarPrimaryForeground": "oklch(1.000 0 0)",
|
||||
"sidebarAccent": "oklch(0.267 0.015 256.8)",
|
||||
"sidebarAccentForeground": "oklch(0.943 0.011 243.7)",
|
||||
"sidebarBorder": "oklch(0.330 0.015 252.3)",
|
||||
"sidebarRing": "oklch(0.569 0.202 259.7)"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user