diff options
| author | Fuwn <[email protected]> | 2026-01-20 04:41:41 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-01-20 04:41:41 -0800 |
| commit | 90d9451d7cdae596adf42362fed6c3fa54884193 (patch) | |
| tree | 719eb1ac3eec89a7d0dd04dca43d8dcad2b0019f | |
| parent | fix: Prevent flash of light mode on page load (diff) | |
| download | kaze-90d9451d7cdae596adf42362fed6c3fa54884193.tar.xz kaze-90d9451d7cdae596adf42362fed6c3fa54884193.zip | |
fix: Prevent flash of light mode on page load
- Default to dark mode by setting class="dark" on html element
- Move theme CSS before external stylesheet to prevent flash
- Only remove dark class if light mode is explicitly preferred
- Add !important to theme variable overrides for precedence
| -rw-r--r-- | internal/server/templates/index.html | 19 | ||||
| -rw-r--r-- | internal/theme/theme.go | 50 |
2 files changed, 36 insertions, 33 deletions
diff --git a/internal/server/templates/index.html b/internal/server/templates/index.html index 025df89..1ba3177 100644 --- a/internal/server/templates/index.html +++ b/internal/server/templates/index.html @@ -1,12 +1,19 @@ <!DOCTYPE html> -<html lang="en"> +<html lang="en" class="dark"> <head> <script> // Theme detection - runs immediately before any rendering - if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { - document.documentElement.classList.add('dark'); + // Default is dark (set on html element above), switch to light only if explicitly set + if (localStorage.theme === 'light' || (localStorage.theme !== 'dark' && window.matchMedia('(prefers-color-scheme: light)').matches)) { + document.documentElement.classList.remove('dark'); } </script> + {{if .ThemeCSS}} + <style> + /* OpenCode Theme - Loaded before external CSS to prevent flash */ +{{.ThemeCSS}} + </style> + {{end}} <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{.Site.Name}}</title> @@ -17,12 +24,6 @@ <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎐</text></svg>"> {{end}} <link rel="stylesheet" href="/static/style.css"> - {{if .ThemeCSS}} - <style> - /* OpenCode Theme */ -{{.ThemeCSS}} - </style> - {{end}} </head> <body class="bg-neutral-50 dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100 min-h-screen font-mono"> <div class="max-w-4xl mx-auto px-4 py-8 sm:py-12"> diff --git a/internal/theme/theme.go b/internal/theme/theme.go index 9e3d30b..691afa0 100644 --- a/internal/theme/theme.go +++ b/internal/theme/theme.go @@ -185,6 +185,7 @@ func GetColorMapping() map[string]string { // GenerateVariableOverrides generates CSS that maps OpenCode theme to Kaze's CSS variables // This is the proper approach - override the root CSS variables that style.css uses +// Uses !important to ensure theme overrides take precedence over external CSS func (t *ResolvedTheme) GenerateVariableOverrides() string { if t == nil { return "" @@ -192,51 +193,52 @@ func (t *ResolvedTheme) GenerateVariableOverrides() string { return ` /* OpenCode Theme - Override Kaze CSS Variables */ +/* Uses !important to prevent flash when external CSS loads */ /* Light mode - uses theme's light colors */ :root, :root.light { /* Background colors */ - --bg-primary: var(--theme-background); - --bg-secondary: var(--theme-background-panel); - --bg-tertiary: var(--theme-background-element); + --bg-primary: var(--theme-background) !important; + --bg-secondary: var(--theme-background-panel) !important; + --bg-tertiary: var(--theme-background-element) !important; /* Border color */ - --border-color: var(--theme-border); + --border-color: var(--theme-border) !important; /* Text colors */ - --text-primary: var(--theme-text); - --text-secondary: var(--theme-text-muted); - --text-tertiary: var(--theme-text-muted); - --text-dim: var(--theme-border); + --text-primary: var(--theme-text) !important; + --text-secondary: var(--theme-text-muted) !important; + --text-tertiary: var(--theme-text-muted) !important; + --text-dim: var(--theme-border) !important; /* Status colors */ - --status-ok: var(--theme-success); - --status-warn: var(--theme-warning); - --status-error: var(--theme-error); - --status-unknown: var(--theme-text-muted); + --status-ok: var(--theme-success) !important; + --status-warn: var(--theme-warning) !important; + --status-error: var(--theme-error) !important; + --status-unknown: var(--theme-text-muted) !important; } /* Dark mode - uses theme's dark colors */ :root.dark { /* Background colors */ - --bg-primary: var(--theme-background); - --bg-secondary: var(--theme-background-panel); - --bg-tertiary: var(--theme-background-element); + --bg-primary: var(--theme-background) !important; + --bg-secondary: var(--theme-background-panel) !important; + --bg-tertiary: var(--theme-background-element) !important; /* Border color */ - --border-color: var(--theme-border); + --border-color: var(--theme-border) !important; /* Text colors */ - --text-primary: var(--theme-text); - --text-secondary: var(--theme-text-muted); - --text-tertiary: var(--theme-text-muted); - --text-dim: var(--theme-border); + --text-primary: var(--theme-text) !important; + --text-secondary: var(--theme-text-muted) !important; + --text-tertiary: var(--theme-text-muted) !important; + --text-dim: var(--theme-border) !important; /* Status colors */ - --status-ok: var(--theme-success); - --status-warn: var(--theme-warning); - --status-error: var(--theme-error); - --status-unknown: var(--theme-text-muted); + --status-ok: var(--theme-success) !important; + --status-warn: var(--theme-warning) !important; + --status-error: var(--theme-error) !important; + --status-unknown: var(--theme-text-muted) !important; } ` } |