theme system
Presets, light/dark, fonts, view transitions. Values land in CSS custom properties that Tailwind utilities read.
Related: Styling System, Theme & Navigation Components.
Architecture overview#
Theme system architecture#
flowchart TD Presets["src/utils/theme-presets.ts"] --> Store["src/stores/theme-store.ts"] Store --> Provider["theme-provider.tsx"] Provider --> CSS["documentElement style + .dark"] CSS --> TW["index.css @theme inline"] Store --> Fonts["DynamicFontLoader"] Script["theme-script.tsx"] --> CSS
Theme presets configuration#
Theme preset structure#
flowchart TD Rec["Record string ThemePreset"] --> Key["preset key adefault twitter ..."] Key --> Label["label"] Key --> Styles["styles.light styles.dark"] Styles --> Tokens["background primary chart-1 grade-*"]
defaultPresets is extendAllThemePresets(basePresets). Keys include adefault, modern-minimal, violet-bloom, t3-chat, twitter, mocha-mousse, bubblegum, amethyst-haze, notebook, doom-64, catppuccin, graphite, perpetuity, plus later presets such as kodama-grove, claude, vercel.
| Preset key | Label |
|---|---|
adefault |
Default |
modern-minimal |
Modern Minimal |
violet-bloom |
Violet Bloom |
t3-chat |
T3 Chat |
twitter |
|
mocha-mousse |
Mocha Mousse |
bubblegum |
Bubblegum |
amethyst-haze |
Amethyst Haze |
notebook |
Notebook |
doom-64 |
Doom 64 |
catppuccin |
Catppuccin |
graphite |
Graphite |
perpetuity |
Perpetuity |
Color token system#
| Category | Properties |
|---|---|
| Base | background, foreground |
| Surface | card, popover and foregrounds |
| Interactive | primary, secondary |
| Semantic | muted, accent, destructive |
| Inputs | border, input, ring |
| Charts | chart-1 through chart-5 |
| Sidebar | sidebar-* |
| JPortal | grade-*, marks-* |
State management with zustand#
Theme store data flow#
flowchart LR User["ThemeSelector"] --> Apply["applyThemePreset"] Apply --> Store["useThemeStore persist"] Store --> Provider["ThemeProvider"] Store --> History["history undo redo"]
Store fields: themeState, themeCheckpoint, history, future, setThemeState, applyThemePreset, undo/redo.
ThemeSelector reads defaultPresets[presetKey], copies light and dark styles, updates the store.
CSS architecture#
CSS variable flow#
flowchart TD Root[":root fallbacks in index.css"] --> Vars["--background --primary"] Store --> Vars Vars --> Theme["@theme inline --color-background"] Theme --> Util["bg-background text-primary"]
Shadows compose --shadow-offset-x, --shadow-blur, --shadow-color, --shadow-opacity.
Theme provider and context#
Theme provider responsibilities#
flowchart TD Init["localStorage theme-mode or prefers-color-scheme"] --> Mode["light or dark"] Mode --> Class["html classList"] Store["themeState.styles"] --> Apply["setProperty on documentElement"] Toggle["toggleTheme x y"] --> VT["document.startViewTransition"]
Default mode is dark when nothing is stored. Click coordinates set --x and --y for the circular reveal.
User interface components#
Theme UI component hierarchy#
flowchart TD Header["Header"] --> Dialog["ThemeSelectorDialog"] Dialog --> Toggle["ThemeToggle"] Dialog --> Grid["ThemeSelector"] Grid --> Card["theme-card preview"]
ThemeSelectorDialog gestures:
- Click opens the dialog
- Hold ~500ms toggles mode at the pointer
- Horizontal or vertical swipe cycles presets
ThemeSelector is a grid of preset buttons with a four-color stripe from light styles.
ThemeToggle is Sun/Moon and calls toggleTheme({x, y}).
Dynamic font loading#
Font loading architecture#
flowchart TD
Style["font-sans from preset"] --> Extract["extractFontFamily"]
Extract --> Sys{"system stack?"}
Sys -->|yes| Skip["no fetch"]
Sys -->|no| URL["fonts.googleapis.com css2"]
URL --> Head["link stylesheet"]Weights: ["400", "500", "600", "700"]. index.html already preloads a large Google Fonts CSS covering preset families.
View transition animations#
index.css @supports (view-transition-name: none):
- new root expands
clip-pathfromcircle(0 at var(--x) var(--y))to100vmax - old root shrinks
- duration 1s
Browsers without the API snap instantly.
Integration with application#
Application integration points#
flowchart TD App["App"] --> Script["ThemeScript"] App --> Provider["ThemeProvider"] App --> Font["DynamicFontLoader"] Pages["Navbar AttendanceCard Grades"] --> Tokens["bg-background text-foreground fill-primary"]
Navbar example: bg-muted, fill-primary-foreground when active.
Custom tokens in index.css: --grade-aa through --grade-f, --marks-outstanding, --marks-good, --marks-average, --marks-poor.