From 081c2bffb329182d92cf0534dd42b11826a87c39 Mon Sep 17 00:00:00 2001 From: memdmp Date: Wed, 28 Jan 2026 01:06:31 +0100 Subject: feat: more theme work --- src/lib/theme.svelte.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/lib/theme.svelte.ts (limited to 'src/lib/theme.svelte.ts') diff --git a/src/lib/theme.svelte.ts b/src/lib/theme.svelte.ts new file mode 100644 index 0000000..956738b --- /dev/null +++ b/src/lib/theme.svelte.ts @@ -0,0 +1,49 @@ +import { onDestroy, onMount } from 'svelte'; +import { themeStorage } from './storage'; +import { page } from '$app/state'; + +export enum Theme { + Light = 'light', + Dark = 'dark', +} +const oppositeThemeMappings: Record = { + [Theme.Light]: Theme.Dark, + [Theme.Dark]: Theme.Light +}; +export class CTheme { + public rawTheme = $state(null as null | Theme); + public theme = $derived(this.rawTheme ?? Theme.Dark); + public opposite = $derived(oppositeThemeMappings[this.theme]); + /** + * Marks the page a component renders on as fully compatible/tested with theming. + * + * Call during component init. + */ + public themeCompatible() { + onMount(() => { + const t = + page.url.searchParams.get('theme') ?? themeStorage.getItem('theme'); + if (theme.isThemeValid(t)) theme.set(t); + }); + $effect(() => { + document.documentElement.setAttribute('data-blog-theme', theme.theme); + page.url.searchParams.delete('theme'); + }); + onDestroy(() => { + if (typeof document !== 'undefined') + document.documentElement.removeAttribute('data-blog-theme'); + }); + } + public isThemeValid(theme: string | null): theme is Theme { + return Object.values(Theme).includes(theme as unknown as Theme); + } + public set(theme: Theme) { + themeStorage.setItem('theme', theme); + this.theme = theme; + } + public flip() { + this.set(this.opposite); + } +}; +export const theme = new CTheme(); +export default theme; -- cgit v1.2.3