Fix accent color loss on refresh by using injected style tag
The inline script's style.setProperty values on <html> were being stripped during Vite's CSS injection. Switch to injecting a <style> tag with :root vars which persists in the DOM. Restore CSS defaults as safety fallback. Update useTheme to sync both the style tag and inline styles when settings load. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
988dc37b64
commit
e7be762198
@ -9,24 +9,24 @@
|
|||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<title>UMBRA</title>
|
<title>UMBRA</title>
|
||||||
<script>
|
<script>
|
||||||
// Apply accent color before React hydrates to prevent FOUC.
|
// Inject a <style> tag with accent color vars before React hydrates.
|
||||||
// Reads from localStorage cache; falls back to cyan on first visit.
|
// Uses a style element (not inline style attr) because Vite's CSS
|
||||||
|
// injection strips the html element's style attribute.
|
||||||
(function() {
|
(function() {
|
||||||
var s = document.documentElement.style;
|
var h = '187', s = '85.7%', l = '53.3%';
|
||||||
try {
|
try {
|
||||||
var c = localStorage.getItem('umbra-accent-color');
|
var c = localStorage.getItem('umbra-accent-color');
|
||||||
if (c) {
|
if (c) {
|
||||||
var p = JSON.parse(c);
|
var p = JSON.parse(c);
|
||||||
s.setProperty('--accent-h', p.h);
|
if (p.h) h = p.h;
|
||||||
s.setProperty('--accent-s', p.s);
|
if (p.s) s = p.s;
|
||||||
s.setProperty('--accent-l', p.l);
|
if (p.l) l = p.l;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
// First visit or corrupt cache — apply cyan defaults
|
var el = document.createElement('style');
|
||||||
s.setProperty('--accent-h', '187');
|
el.id = 'umbra-accent';
|
||||||
s.setProperty('--accent-s', '85.7%');
|
el.textContent = ':root{--accent-h:' + h + ';--accent-s:' + s + ';--accent-l:' + l + '}';
|
||||||
s.setProperty('--accent-l', '53.3%');
|
document.head.appendChild(el);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export function useTheme() {
|
|||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
|
|
||||||
// Only apply accent color once settings have loaded from the API.
|
// Only apply accent color once settings have loaded from the API.
|
||||||
// The inline script in index.html handles the initial paint from localStorage cache.
|
// The <style id="umbra-accent"> tag in index.html handles initial paint.
|
||||||
// Firing this effect with settings=undefined would overwrite the cache with cyan.
|
// Firing this effect with settings=undefined would overwrite the cache with cyan.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!settings) return;
|
if (!settings) return;
|
||||||
@ -28,9 +28,17 @@ export function useTheme() {
|
|||||||
const h = preset.h.toString();
|
const h = preset.h.toString();
|
||||||
const s = `${preset.s}%`;
|
const s = `${preset.s}%`;
|
||||||
const l = `${preset.l}%`;
|
const l = `${preset.l}%`;
|
||||||
|
|
||||||
|
// Update the injected <style> tag (survives Vite CSS injection, unlike inline styles)
|
||||||
|
const el = document.getElementById('umbra-accent');
|
||||||
|
if (el) {
|
||||||
|
el.textContent = `:root{--accent-h:${h};--accent-s:${s};--accent-l:${l}}`;
|
||||||
|
}
|
||||||
|
// Also set inline styles as a belt-and-suspenders fallback
|
||||||
document.documentElement.style.setProperty('--accent-h', h);
|
document.documentElement.style.setProperty('--accent-h', h);
|
||||||
document.documentElement.style.setProperty('--accent-s', s);
|
document.documentElement.style.setProperty('--accent-s', s);
|
||||||
document.documentElement.style.setProperty('--accent-l', l);
|
document.documentElement.style.setProperty('--accent-l', l);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
localStorage.setItem('umbra-accent-color', JSON.stringify({ h, s, l }));
|
localStorage.setItem('umbra-accent-color', JSON.stringify({ h, s, l }));
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|||||||
@ -26,9 +26,12 @@
|
|||||||
--ring: var(--accent-h) var(--accent-s) var(--accent-l);
|
--ring: var(--accent-h) var(--accent-s) var(--accent-l);
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
|
|
||||||
/* Accent vars are set by the inline script in index.html (from localStorage
|
/* Default accent: cyan — safety fallback if inline script fails.
|
||||||
cache or cyan fallback). No CSS defaults here — they would race with the
|
The <style id="umbra-accent"> tag injected by index.html overrides
|
||||||
inline script and cause a flash of wrong color on refresh. */
|
these (unlayered > @layer base), as does useTheme's inline styles. */
|
||||||
|
--accent-h: 187;
|
||||||
|
--accent-s: 85.7%;
|
||||||
|
--accent-l: 53.3%;
|
||||||
|
|
||||||
/* Transitions */
|
/* Transitions */
|
||||||
--transition-fast: 150ms;
|
--transition-fast: 150ms;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user