From 79dd56403e436b35d2c001fdf8a8f43c624c4eb3 Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:58:34 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(clock):=20use=20'lume'=20as?= =?UTF-8?q?=20default=20theme=20variant=20instead=20of=20'amber'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'amber' doesn't exist in THEME_VARIANTS - available themes are: lume, nature, stone, ocean Also added proper SSR fallbacks for theme store 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../apps/web/src/lib/stores/theme.svelte.ts | 48 ++++++++++++------- apps/clock/apps/web/src/routes/+layout.svelte | 16 ++++--- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/apps/clock/apps/web/src/lib/stores/theme.svelte.ts b/apps/clock/apps/web/src/lib/stores/theme.svelte.ts index 375177913..0f4789b44 100644 --- a/apps/clock/apps/web/src/lib/stores/theme.svelte.ts +++ b/apps/clock/apps/web/src/lib/stores/theme.svelte.ts @@ -1,6 +1,7 @@ /** * Theme store for Clock app * Manages light/dark mode and theme variants + * SSR-safe implementation */ import { browser } from '$app/environment'; @@ -15,10 +16,15 @@ import { const MODE_KEY = 'clock-theme-mode'; const VARIANT_KEY = 'clock-theme-variant'; -// State -let mode = $state('system'); -let variant = $state('amber'); +// Default values for SSR +const DEFAULT_MODE: ThemeMode = 'system'; +const DEFAULT_VARIANT: ThemeVariant = 'lume'; + +// State (only used client-side, but initialized for SSR) +let mode = $state(DEFAULT_MODE); +let variant = $state(DEFAULT_VARIANT); let isDark = $state(false); +let initialized = $state(false); // Get system preference function getSystemPrefersDark(): boolean { @@ -31,43 +37,49 @@ function applyTheme() { if (!browser) return; // Determine if dark mode - const shouldBeDark = mode === 'system' ? getSystemPrefersDark() : mode === 'dark'; + const currentMode = mode ?? DEFAULT_MODE; + const shouldBeDark = currentMode === 'system' ? getSystemPrefersDark() : currentMode === 'dark'; isDark = shouldBeDark; // Apply to document + const currentVariant = variant ?? DEFAULT_VARIANT; document.documentElement.classList.toggle('dark', shouldBeDark); - document.documentElement.setAttribute('data-theme', variant); + document.documentElement.setAttribute('data-theme', currentVariant); } -// Listen for system preference changes +// Listen for system preference changes (only in browser) if (browser) { window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { - if (mode === 'system') { + if ((mode ?? DEFAULT_MODE) === 'system') { applyTheme(); } }); } export const theme = { - // Getters - get mode() { - return mode; + // Getters (SSR-safe with fallbacks) + get mode(): ThemeMode { + return mode ?? DEFAULT_MODE; }, - get variant() { - return variant; + get variant(): ThemeVariant { + return variant ?? DEFAULT_VARIANT; }, - get isDark() { - return isDark; + get isDark(): boolean { + return isDark ?? false; }, - get variants() { + get variants(): readonly ThemeVariant[] { return THEME_VARIANTS; }, + get initialized(): boolean { + return initialized; + }, /** - * Initialize theme from localStorage + * Initialize theme from localStorage (client-side only) */ initialize() { if (!browser) return; + if (initialized) return; // Load saved preferences const savedMode = localStorage.getItem(MODE_KEY) as ThemeMode | null; @@ -81,6 +93,7 @@ export const theme = { variant = savedVariant; } + initialized = true; applyTheme(); }, @@ -99,7 +112,8 @@ export const theme = { * Toggle between light and dark */ toggleMode() { - const newMode = isDark ? 'light' : 'dark'; + const currentDark = isDark ?? false; + const newMode = currentDark ? 'light' : 'dark'; this.setMode(newMode); }, diff --git a/apps/clock/apps/web/src/routes/+layout.svelte b/apps/clock/apps/web/src/routes/+layout.svelte index 606573e77..cb3c6f5d5 100644 --- a/apps/clock/apps/web/src/routes/+layout.svelte +++ b/apps/clock/apps/web/src/routes/+layout.svelte @@ -30,14 +30,14 @@ // Use theme store's isDark directly let isDark = $derived(theme.isDark); - // Theme variant dropdown items + // Theme variant dropdown items (with SSR fallback) let themeVariantItems = $derived([ - ...theme.variants.map((variant) => ({ + ...(theme.variants || []).map((variant) => ({ id: variant, - label: THEME_DEFINITIONS[variant].label, - icon: THEME_DEFINITIONS[variant].icon, + label: THEME_DEFINITIONS[variant]?.label || variant, + icon: THEME_DEFINITIONS[variant]?.icon || '🎨', onClick: () => theme.setVariant(variant), - active: theme.variant === variant, + active: (theme.variant || 'lume') === variant, })), { id: 'all-themes', @@ -48,8 +48,10 @@ }, ]); - // Current theme variant label - let currentThemeVariantLabel = $derived(THEME_DEFINITIONS[theme.variant].label); + // Current theme variant label (with SSR fallback) + let currentThemeVariantLabel = $derived( + THEME_DEFINITIONS[theme.variant]?.label || THEME_DEFINITIONS.lume?.label || 'Lume' + ); // Language selector items let currentLocale = $derived($locale || 'de');