Files
wishlist/src/lib/stores/theme.svelte.ts

71 lines
1.6 KiB
TypeScript

import { browser } from '$app/environment';
type Theme = 'light' | 'dark' | 'system';
type ResolvedTheme = 'light' | 'dark';
class ThemeStore {
current = $state<Theme>('system');
constructor() {
if (browser) {
const stored = localStorage.getItem('theme') as Theme | null;
this.current = stored || 'system';
this.applyTheme();
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', () => {
if (this.current === 'system') {
this.applyTheme();
}
});
}
}
private applyTheme() {
if (!browser) return;
const isDark = this.current === 'dark' ||
(this.current === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
if (isDark) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
getResolvedTheme(): ResolvedTheme {
if (!browser) return 'light';
const isDark = this.current === 'dark' ||
(this.current === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
return isDark ? 'dark' : 'light';
}
toggle() {
// Cycle through: light -> dark -> system -> light
if (this.current === 'light') {
this.current = 'dark';
} else if (this.current === 'dark') {
this.current = 'system';
} else {
this.current = 'light';
}
if (browser) {
localStorage.setItem('theme', this.current);
this.applyTheme();
}
}
set(theme: Theme) {
this.current = theme;
if (browser) {
localStorage.setItem('theme', this.current);
}
this.applyTheme();
}
}
export const themeStore = new ThemeStore();