/** * Inline script that runs in before hydration. * * Reads the persisted theme id + mode from localStorage and applies them * to so the user never sees a flash of the default theme. * * MUST stay dependency-free — it's bundled as a string and inlined. */ export function ThemeBootstrapScript() { const code = ` (function() { try { var themeId = localStorage.getItem('wfdash-theme') || 'crisp'; var mode = localStorage.getItem('wfdash-mode') || 'warm'; var root = document.documentElement; root.setAttribute('data-theme', themeId); root.classList.remove('warm', 'dark'); root.classList.add(mode); var radiusMap = { 'crisp': '0.625rem', 'midnight': '0.75rem', 'editorial': '0.375rem', 'bento': '1.125rem', 'field-ops': '0.5rem', 'terminal': '0', 'blueprint': '0.125rem', 'confetti': '1.25rem' }; if (radiusMap[themeId]) root.style.setProperty('--radius', radiusMap[themeId]); // If the active theme is a custom theme, apply its inline token overrides // so the page renders correctly before React hydrates. var activeCustomId = localStorage.getItem('wfdash-active-custom-id'); if (activeCustomId) { try { var raw = localStorage.getItem('wfdash-custom-themes'); if (raw) { var list = JSON.parse(raw); var found = null; for (var i = 0; i < list.length; i++) { if (list[i].id === activeCustomId) { found = list[i]; break; } } if (found && found.colors) { var c = found.colors; // Direct mappings root.style.setProperty('--background', c.background); root.style.setProperty('--foreground', c.foreground); root.style.setProperty('--primary', c.primary); root.style.setProperty('--accent', c.accent); root.style.setProperty('--destructive', c.destructive); root.style.setProperty('--sidebar', c.sidebar); root.style.setProperty('--border', c.border); // Contrast foregrounds function lum(hex){ var r = parseInt(hex.slice(1,3),16)/255; var g = parseInt(hex.slice(3,5),16)/255; var b = parseInt(hex.slice(5,7),16)/255; var f = function(v){return v<=0.03928 ? v/12.92 : Math.pow((v+0.055)/1.055,2.4);}; return 0.2126*f(r)+0.7152*f(g)+0.0722*f(b); } function fgFor(bg){ return lum(bg) > 0.55 ? '#0F172A' : '#FFFFFF'; } root.style.setProperty('--primary-foreground', fgFor(c.primary)); root.style.setProperty('--accent-foreground', fgFor(c.accent)); root.style.setProperty('--destructive-foreground', fgFor(c.destructive)); root.style.setProperty('--sidebar-foreground', fgFor(c.sidebar)); // Derived function hexA(hex,a){return hex+(Math.round(a*2.55).toString(16).padStart(2,'0'));} function mix(a,b,p){var ar=parseInt(a.slice(1,3),16),ag=parseInt(a.slice(3,5),16),ab=parseInt(a.slice(5,7),16),br=parseInt(b.slice(1,3),16),bg=parseInt(b.slice(3,5),16),bb=parseInt(b.slice(5,7),16);var k=p/100;var r=Math.round(ar*k+br*(1-k)),g=Math.round(ag*k+bg*(1-k)),bb2=Math.round(ab*k+bb*(1-k));var h=function(n){return n.toString(16).padStart(2,'0');};return '#'+h(r)+h(g)+h(bb2);} root.style.setProperty('--card', mix('#FFFFFF', c.background, 2)); root.style.setProperty('--popover', mix('#FFFFFF', c.background, 2)); root.style.setProperty('--muted', mix('#000000', c.background, 4)); root.style.setProperty('--secondary', mix('#000000', c.background, 3)); root.style.setProperty('--card-foreground', c.foreground); root.style.setProperty('--popover-foreground', c.foreground); root.style.setProperty('--secondary-foreground', c.foreground); root.style.setProperty('--muted-foreground', mix('#94A3B8', c.foreground, 60)); root.style.setProperty('--input', c.border); root.style.setProperty('--ring', c.primary); root.style.setProperty('--sidebar-primary', c.primary); root.style.setProperty('--sidebar-primary-foreground', fgFor(c.primary)); root.style.setProperty('--sidebar-accent', mix('#FFFFFF', c.sidebar, 8)); root.style.setProperty('--sidebar-accent-foreground', fgFor(c.sidebar)); root.style.setProperty('--sidebar-border', mix('#FFFFFF', c.sidebar, 12)); root.style.setProperty('--sidebar-ring', c.primary); } } } catch(e2) { /* ignore */ } } } catch (e) { // localStorage may be blocked — fall back to defaults silently } })(); `; return