import { writable, derived } from 'svelte/store'; import { browser } from '$app/environment'; import { type ThemeColorMap, defaultColorMap } from '$lib/components/tui/utils'; // Import theme JSON files import archTheme from '$lib/assets/themes/arch.theme.json'; import catppuccinTheme from '$lib/assets/themes/catppuccin.theme.json'; export type ColorTheme = 'arch' | 'catppuccin'; export type Mode = 'dark' | 'light'; // Theme JSON structure export interface ThemeJson { name: string; icon: string; dark: { colors: Record; colorMap: ThemeColorMap; }; light: { colors: Record; colorMap: ThemeColorMap; }; } export interface ThemeColors { primary: string; secondary: string; accent: string; background: string; backgroundLight: string; text: string; textMuted: string; border: string; terminal: string; terminalPrompt: string; terminalUser: string; terminalPath: string; colorMap: ThemeColorMap; } // Load themes from JSON files const themes: Record = { arch: archTheme as ThemeJson, catppuccin: catppuccinTheme as ThemeJson }; // Export themes for external access export { themes }; // Build theme colors from JSON function buildThemeColors(theme: ThemeJson, mode: Mode): ThemeColors { const modeData = theme[mode]; return { primary: modeData.colors.primary, secondary: modeData.colors.secondary, accent: modeData.colors.accent, background: modeData.colors.background, backgroundLight: modeData.colors.backgroundLight, text: modeData.colors.text, textMuted: modeData.colors.textMuted, border: modeData.colors.border, terminal: modeData.colors.terminal, terminalPrompt: modeData.colors.terminalPrompt, terminalUser: modeData.colors.terminalUser, terminalPath: modeData.colors.terminalPath, colorMap: modeData.colorMap ?? defaultColorMap }; } // Build the theme colors map from JSON themes const themeColorsMap: Record = Object.fromEntries( Object.entries(themes).map(([key, theme]) => [ key, { dark: buildThemeColors(theme, 'dark'), light: buildThemeColors(theme, 'light') } ]) ) as Record; function getInitialMode(): Mode { if (browser) { const stored = localStorage.getItem('mode'); if (stored === 'dark' || stored === 'light') return stored; return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } return 'dark'; } function getInitialTheme(): ColorTheme { if (browser) { const stored = localStorage.getItem('colorTheme'); if (stored && stored in themeColorsMap) return stored as ColorTheme; } return 'arch'; } export const mode = writable(getInitialMode()); export const colorTheme = writable(getInitialTheme()); export const themeColors = derived([mode, colorTheme], ([$mode, $colorTheme]) => { return themeColorsMap[$colorTheme][$mode]; }); // Subscribe to persist changes if (browser) { mode.subscribe((value) => { localStorage.setItem('mode', value); document.documentElement.setAttribute('data-mode', value); }); colorTheme.subscribe((value) => { localStorage.setItem('colorTheme', value); document.documentElement.setAttribute('data-theme', value); }); } export function toggleMode() { mode.update((m) => (m === 'dark' ? 'light' : 'dark')); } export function setColorTheme(theme: ColorTheme) { colorTheme.set(theme); } // Generate theme options from loaded themes export const themeOptions: { value: ColorTheme; label: string; icon: string }[] = Object.entries(themes).map(([key, theme]) => ({ value: key as ColorTheme, label: theme.name, icon: theme.icon }));