From edfce3b7e66ce1375f3be891fecde06f25280d7a Mon Sep 17 00:00:00 2001 From: pavlov346346-source Date: Sat, 12 Sep 2026 17:56:19 +0300 Subject: [PATCH] fix: pre-apply cached brand/sidebar theme before first paint The static :root fallback for --sun-ui-*/--sun-sidebar-* hardcodes the "Standard Purple" preset (SIDEBAR_STANDARD's exact values). Any workspace that has actually saved a different theme only gets it applied once app-runtime.js's brand-theme module loads and runs applyActual(), which reads the same localStorage cache (sunBrandThemeV1) it always did - but by then the purple/mixed defaults have already painted, so every load flashes the wrong colors before snapping to the real ones. Reads the same localStorage key synchronously in the sun-startup-stability-guard script (already first in , before any stylesheet or the app-runtime.js bundle loads) and sets the same CSS custom properties as inline styles on . Inline element styles always win over a stylesheet's :root selector regardless of load order, so the correct theme is already active for the very first paint. Workspaces with no saved theme yet are unaffected - the existing static fallback still shows, same as today. Co-Authored-By: Claude Sonnet 5 --- public/index.html | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/public/index.html b/public/index.html index 777b9e3..9831c85 100644 --- a/public/index.html +++ b/public/index.html @@ -20,6 +20,30 @@ }); }catch(_){ } + // Apply the workspace's saved brand/sidebar theme before first paint, straight from the + // localStorage cache. Without this the page briefly shows the hardcoded "Standard Purple" + // :root fallback until app-runtime.js's theme module loads and corrects it - a visible + // color flash on every load for any workspace that isn't actually using that preset. + try{ + const rawTheme=localStorage.getItem('sunBrandThemeV1'); + if(rawTheme){ + const parsed=JSON.parse(rawTheme)||{}; + const root=document.documentElement.style; + const isHex=v=>/^#[0-9a-f]{6}$/i.test(String(v||'')); + if(parsed.ui&&typeof parsed.ui==='object'){ + Object.entries(parsed.ui).forEach(([k,v])=>{ + if(isHex(v))root.setProperty(`--sun-ui-${k.replace(/[A-Z]/g,m=>'-'+m.toLowerCase())}`,v); + }); + } + if(parsed.sidebar&&typeof parsed.sidebar==='object'){ + const sideMap={background:'--sun-sidebar-bg',background2:'--sun-sidebar-bg2',glow:'--sun-sidebar-glow',border:'--sun-sidebar-border',icons:'--sun-sidebar-icons',iconBackground:'--sun-sidebar-icon-bg',text:'--sun-sidebar-text',muted:'--sun-sidebar-muted',activeBackground:'--sun-sidebar-active-bg',activeText:'--sun-sidebar-active-text',activeIcon:'--sun-sidebar-active-icon',indicator:'--sun-sidebar-indicator',toolsBackground:'--sun-sidebar-tools-bg',toolsBorder:'--sun-sidebar-tools-border',collapseBackground:'--sun-sidebar-collapse-bg',collapseText:'--sun-sidebar-collapse-text',badgeBackground:'--sun-sidebar-badge-bg',badgeText:'--sun-sidebar-badge-text'}; + Object.entries(sideMap).forEach(([k,cssVar])=>{ + if(isHex(parsed.sidebar[k]))root.setProperty(cssVar,parsed.sidebar[k]); + }); + } + } + }catch(_){ } + window.sunFetchWithTimeout=window.sunFetchWithTimeout||async function(url,options={},timeout=8000){ const controller=new AbortController(); const timer=setTimeout(()=>controller.abort(),Math.max(1000,Number(timeout)||8000));