Wires the dark-mode plumbing: - New $lib/theme module: themePreference + resolvedTheme stores plus initTheme() / setThemePreference(). Owns localStorage persistence, <html data-theme=...> mirroring, and the matchMedia listener that re-resolves "system" when the OS preference flips. Storage-agnostic (no Supabase coupling) so the caller persists to public.users.theme separately. - Inline anti-FOUC script in app.html reads localStorage + matchMedia synchronously and writes data-theme before the first paint — refresh in dark mode no longer flashes white. - Tailwind switched to darkMode: ['selector', '[data-theme="dark"]'] so all existing `dark:` utilities resolve from the same attribute. - :root and :root[data-theme=light] share the light token set; dark tokens move into :root[data-theme=dark]. Tokens stay as RGB triplets (rgb(var(--token) / <alpha>)) per the repo gotcha — no hsl(). - ThemeToggle.svelte: three-way radiogroup (Light / Dark / System) with paraglide messages in EN + ES. Tests (TDD): 8 new unit specs in src/lib/theme.test.ts cover defaults, localStorage round-trip, data-theme reflection, system resolution against matchMedia, invalid-value fallback, and OS preference change propagation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
45 lines
1.7 KiB
HTML
45 lines
1.7 KiB
HTML
<!doctype html>
|
|
<html lang="%paraglide.lang%">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta name="theme-color" content="#0f172a" />
|
|
<!-- iOS PWA install hints (Fase 6.2). -->
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
<meta name="apple-mobile-web-app-title" content="Colectivo" />
|
|
<link rel="apple-touch-icon" href="/icons/icon-180.png" />
|
|
<!--
|
|
Fase 9.1: anti-FOUC theme bootstrapping.
|
|
Runs synchronously before the first paint so the page never
|
|
renders a light frame and then flashes dark on refresh.
|
|
localStorage.theme is one of 'light' | 'dark' | 'system' (default
|
|
'system'). For 'system' we read prefers-color-scheme. The result is
|
|
written to <html data-theme="..."> — Tailwind's `dark:` utilities
|
|
and the :root[data-theme=...] tokens both resolve from this attr.
|
|
-->
|
|
<script>
|
|
(function () {
|
|
try {
|
|
var stored = localStorage.getItem('theme');
|
|
var pref = stored === 'light' || stored === 'dark' ? stored : 'system';
|
|
var resolved =
|
|
pref === 'system'
|
|
? (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
? 'dark'
|
|
: 'light')
|
|
: pref;
|
|
document.documentElement.setAttribute('data-theme', resolved);
|
|
} catch (_) {
|
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
}
|
|
})();
|
|
</script>
|
|
%sveltekit.head%
|
|
</head>
|
|
<body data-sveltekit-preload-data="hover">
|
|
<div style="display: contents">%sveltekit.body%</div>
|
|
</body>
|
|
</html>
|