refactor(web): conventional class-based dark mode + decoupled theme module#97
Open
ajianaz wants to merge 1 commit into
Open
refactor(web): conventional class-based dark mode + decoupled theme module#97ajianaz wants to merge 1 commit into
ajianaz wants to merge 1 commit into
Conversation
…odule - Bind dark: variant to .dark class via @custom-variant dark (&:is(.dark *)) in app.css. Previously dark: followed the OS media query while CSS vars followed a .light opt-in class, so manual light/dark toggling desynced the 21 dark: usages in badge/button/input/textarea from the variable swap. - Light is now the default; dark is opt-in via .dark on <html>. Add color-scheme: light/dark so native UI (scrollbars, select, autofill) follows the theme. - Extract theme logic into src/lib/theme.ts (pure TS, SSR-safe, framework-agnostic): getStoredTheme, resolveTheme, applyTheme, setTheme, cycleTheme, watchSystemTheme (live OS change listener). ThemeToggle.svelte is now a thin UI shell over it. - Fix FOUC script in app.html: handle stored 'system' correctly (was treated as concrete dark -> dark->light flash for system + light-OS users). - Add 16 unit tests in theme.test.ts (vitest). localStorage key unchanged (backward compatible).
🔍 Cora AI Code Review🟡 Warning (1)
Review powered by cora-cli · BYOK · MIT |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactors the frontend theme system to fix a desync bug between CSS variables and Tailwind
dark:utilities, and makes the architecture framework-agnostic for the future.Problem
The previous design was inverted: dark was the default, light was opt-in via a
.lightclass, and there was no@custom-variant dark. As a result:.lightclass viaThemeToggledark:utilities — 21 usages across badge/button/input/textarea) followed the OSprefers-color-schememedia query (Tailwind v4 default)These two systems were independent. Manual light/dark toggling produced broken component styling — only
systemmode was correct (by accident). Additional issues: FOUC flash forsystem+ light-OS users, missingcolor-scheme, no live OS-change reaction.Changes
app.css—@custom-variant dark (&:is(.dark *))binds both the variable swap anddark:utilities to the same.darkclass. Light is now default; dark is opt-in. Addedcolor-scheme: light/darkso native UI (scrollbars,<select>, autofill) follows the theme.theme.ts(new) — Pure TS, SSR-safe, framework-agnostic theme module:getStoredTheme,resolveTheme,applyTheme,setTheme,cycleTheme,watchSystemTheme(live OS-change listener). Logic is reusable/testable independent of Svelte or shadcn.ThemeToggle.svelte— Now a thin UI shell overtheme.ts.app.html— Fixed FOUC script:system+ light-OS no longer flashes dark→light (mirrorstheme.tslogic exactly).theme.test.ts(new) — 16 unit tests (vitest).Why this approach
.darkclass = universal Tailwind convention → any future component (shadcn, hand-written, or a third-party kit) works out of the box--color-*) are the contract in@theme, not tied to shadcn → survives moving away from shadcntheme.tsis decoupled → reusable across UI layersTrade-off: default flips from dark → light (web/shadcn convention). Mode
systemstill follows OS preference, so most users are unaffected.Validation
vitest— 62 passed | 1 skipped (theme: 16/16)svelte-check— 0 errors (1 pre-existing@types/nodewarning)vite build— OK@media prefers-color-schemeremains;dark:variants now compile to:is(.dark *)rungu-theme) — backward compatibleNotes
zai/glm-5.2returns empty responses (downstream infra issue, not code). CI will run Cora on GitHub as backup.