theme-selector
Version:
A simple Svelte store library that lets you switch between light and dark themes, with support for system theme by default.
71 lines (70 loc) • 2.09 kB
JavaScript
import { browser } from '$app/environment';
import { writable } from 'svelte/store';
class Theme {
#themeOption;
#themeCurrent;
onThemeChange = (value) => {
if (browser) {
if (value === 'dark') {
document.documentElement.classList.add('dark');
}
else {
document.documentElement.classList.remove('dark');
}
}
};
value;
constructor(onThemeChange) {
if (onThemeChange) {
this.onThemeChange = onThemeChange;
}
this.#themeOption = writable('system');
this.#themeCurrent = writable('light');
this.value = 'light';
if (browser) {
this.initialize();
}
}
initialize() {
const theme = localStorage.getItem('theme');
if (theme) {
this.#themeOption.set(theme);
}
else {
this.#themeOption.set('system');
localStorage.setItem('theme', 'system');
}
this.value = theme;
this.#themeCurrent.set(this.get());
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
this.#themeCurrent.set(this.get());
});
this.#themeOption.subscribe((value) => {
this.value = value;
this.#themeCurrent.set(this.get());
});
this.#themeCurrent.subscribe((value) => {
this.onThemeChange?.(value);
});
this.onThemeChange?.(this.get());
}
get() {
if (this.value === 'system') {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
else {
return this.value;
}
}
set(value) {
this.#themeOption.set(value);
localStorage.setItem('theme', value);
}
subscribe(run, invalidate) {
return this.#themeCurrent.subscribe(run, invalidate);
}
}
export const createThemeStore = (calledFunc) => {
return new Theme(calledFunc);
};
export const theme = new Theme();