feat(web): add theme system with Obsidian, Paper, and Midnight themes
Three holistic design directions with CSS custom properties, a theme store persisted to localStorage, and a live switcher in both the header (cycle button) and settings page (card selector). Also fixes checkbox checkmark alignment and adds back navigation from settings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
/** @typedef {'obsidian' | 'paper' | 'midnight'} ThemeName */
|
||||
|
||||
const STORAGE_KEY = 'opal-theme';
|
||||
|
||||
/** @type {ThemeName} */
|
||||
const DEFAULT_THEME = 'obsidian';
|
||||
|
||||
/** @type {ThemeName[]} */
|
||||
export const THEMES = ['obsidian', 'paper', 'midnight'];
|
||||
|
||||
/**
|
||||
* Read stored theme, falling back to default
|
||||
* @returns {ThemeName}
|
||||
*/
|
||||
function getInitial() {
|
||||
if (!browser) return DEFAULT_THEME;
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored && THEMES.includes(/** @type {ThemeName} */ (stored))) {
|
||||
return /** @type {ThemeName} */ (stored);
|
||||
}
|
||||
return DEFAULT_THEME;
|
||||
}
|
||||
|
||||
function createThemeStore() {
|
||||
const { subscribe, set, update } = writable(getInitial());
|
||||
|
||||
/** Apply theme to the document */
|
||||
function apply(/** @type {ThemeName} */ theme) {
|
||||
if (browser) {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
localStorage.setItem(STORAGE_KEY, theme);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply on every change
|
||||
subscribe(apply);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
/** @param {ThemeName} theme */
|
||||
set(theme) {
|
||||
set(theme);
|
||||
},
|
||||
/** Cycle to the next theme */
|
||||
cycle() {
|
||||
update(current => {
|
||||
const idx = THEMES.indexOf(current);
|
||||
return THEMES[(idx + 1) % THEMES.length];
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const themeStore = createThemeStore();
|
||||
Reference in New Issue
Block a user