blob: 956738b9970c8aa3bb7c44807a723ca296b4cc06 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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, Theme> = {
[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;
|