diff --git a/rsbuild.config.ts b/rsbuild.config.ts index 96aa071..ea3d97a 100644 --- a/rsbuild.config.ts +++ b/rsbuild.config.ts @@ -36,6 +36,18 @@ export default defineConfig({ // "Install app". The service worker (audio offline cache) is registered // from src/index.tsx, not here. tags: [ + // Theme bootstrap — runs inline before first paint to kill the flash of + // white on a dark-themed load. Mirrors modern-sk's own logic exactly + // (localStorage 'modern-sk-theme' || 'dark' → data-theme on ), so + // there's no second flip when mounts. Inline (not an + // external file) so it costs zero round-trips. + { + tag: 'script', + children: + "(function(){try{var t=localStorage.getItem('modern-sk-theme')||'dark';document.documentElement.setAttribute('data-theme',t);}catch(e){}})();", + head: true, + append: false, + }, // Runtime operator config. A classic (non-deferred) head script, so it // runs before the deferred app bundle and window.__APP_CONFIG__ is set by // the time src/config/env.ts reads it. Served from public/ in dev and diff --git a/src/styles/global.css b/src/styles/global.css index 6d70b12..3befac2 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -28,6 +28,11 @@ body { margin: 0; font-family: var(--font-sans); color: var(--fg-1); + /* Paint the themed background immediately. The inline theme script in + index.html (see rsbuild.config.ts) sets [data-theme] before first paint, so + --color-bg resolves to the right value here before React mounts #root and + layers the .modern-sk-felt grain on top — no flash of white. */ + background: var(--color-bg); -webkit-font-smoothing: antialiased; }