diff --git a/src/lib/mode-watcher.svelte b/src/lib/mode-watcher.svelte index 8e3eb7f..c38300d 100644 --- a/src/lib/mode-watcher.svelte +++ b/src/lib/mode-watcher.svelte @@ -1,10 +1,10 @@ diff --git a/src/lib/mode.ts b/src/lib/mode.ts index 3439dd2..c16ddf2 100644 --- a/src/lib/mode.ts +++ b/src/lib/mode.ts @@ -1,29 +1,25 @@ // Modified version of the light switch by: https://skeleton.dev -import { derived } from 'svelte/store'; import { persisted } from 'svelte-persisted-store'; /** * Stores */ -const modeOsPrefers = persisted<'light' | 'dark'>('modeOsPrefers', 'dark'); -const modeUserPrefers = persisted<'light' | 'dark' | undefined>('modeUserPrefers', undefined); -const modeCurrent = persisted<'light' | 'dark'>('modeCurrent', 'dark'); - -/** Derived store with either `"light"` or `"dark"` depending on the current mode */ -export const mode = derived(modeCurrent, ($modeCurrent) => $modeCurrent); +const systemPrefersMode = persisted<'dark' | 'light'>('systemPrefersMode', 'dark'); +const userPrefersMode = persisted<'dark' | 'light' | undefined>('userPrefersMode', undefined); +export const mode = persisted<'dark' | 'light'>('mode', 'dark'); /** * Getters */ -/** Get the OS preference */ -export function getModeOsPrefers(): 'light' | 'dark' { +/** Get the operating system preference */ +export function getSystemPrefersMode(): 'dark' | 'light' { const prefersLightMode = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'; - modeOsPrefers.set(prefersLightMode); + systemPrefersMode.set(prefersLightMode); return prefersLightMode; } @@ -32,23 +28,23 @@ export function getModeOsPrefers(): 'light' | 'dark' { */ /** Set the user preference */ -function setModeUserPrefers(value: 'light' | 'dark' | undefined): void { - modeUserPrefers.set(value); +function setUserPrefersMode(value: 'dark' | 'light' | undefined): void { + userPrefersMode.set(value); } /** Set the current mode */ -export function setModeCurrent(value: 'light' | 'dark'): void { +export function setCurrentMode(value: 'dark' | 'light'): void { const htmlEl = document.documentElement; if (value === 'light') { htmlEl.classList.remove('dark'); htmlEl.style.colorScheme = 'light'; - } - if (value === 'dark') { + } else { htmlEl.classList.add('dark'); htmlEl.style.colorScheme = 'dark'; } - modeCurrent.set(value); + + mode.set(value); } /** @@ -56,56 +52,59 @@ export function setModeCurrent(value: 'light' | 'dark'): void { */ /** - * Set the visible light/dark mode on page load + * Set light/dark class based on user/system preference + * + * Should be added to to prevent FOUC * * This function needs to be able to be stringified and thus it cannot use other functions */ export function setInitialClassState() { const htmlEl = document.documentElement; - const userPrefersMode = localStorage.getItem('modeUserPrefers'); - - const systemPrefersMode = window.matchMedia('(prefers-color-scheme: light)').matches - ? 'light' - : 'dark'; - - if (userPrefersMode === 'dark' || systemPrefersMode === 'dark') { - htmlEl.classList.add('dark'); - htmlEl.style.colorScheme = 'dark'; + let userPref: string | null = null; + try { + userPref = JSON.parse(localStorage.getItem('userPrefersMode') || 'null'); + } catch { + // ignore JSON parsing errors } - if (userPrefersMode === 'light' || systemPrefersMode === 'light') { + const systemPref = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'; + + if (userPref === 'light' || (userPref === null && systemPref === 'light')) { htmlEl.classList.remove('dark'); htmlEl.style.colorScheme = 'light'; + } else { + htmlEl.classList.add('dark'); + htmlEl.style.colorScheme = 'dark'; } } /** Toggle between light and dark mode */ export function toggleMode(): void { - modeCurrent.update((curr) => { - const next = curr === 'light' ? 'dark' : 'light'; - setModeUserPrefers(next); - setModeCurrent(next); + mode.update((curr) => { + const next = curr === 'dark' ? 'light' : 'dark'; + setUserPrefersMode(next); + setCurrentMode(next); return next; }); } /** Set the mode to light or dark */ -export function setMode(mode: 'light' | 'dark'): void { - modeCurrent.update((curr) => { - if (curr === mode) return curr; - setModeUserPrefers(mode); - setModeCurrent(mode); - return mode; +export function setMode(next: 'dark' | 'light'): void { + mode.update((curr) => { + if (curr === next) return curr; + setUserPrefersMode(next); + setCurrentMode(next); + return next; }); } -/** Reset the mode to OS preference */ +/** Reset the mode to operating system preference */ export function resetMode(): void { - modeCurrent.update(() => { - setModeUserPrefers(undefined); - const next = getModeOsPrefers(); - setModeCurrent(next); + mode.update(() => { + setUserPrefersMode(undefined); + const next = getSystemPrefersMode(); + setCurrentMode(next); return next; }); }