Files
wikideck/src/ThemePicker.tsx
T
2026-10-19 12:16:49 -04:00

35 lines
1.4 KiB
TypeScript

import { useEffect, useState } from 'react';
import { Palette } from 'lucide-react';
import { applyTheme, isTheme, resolveTheme, THEMES, THEME_STORAGE_KEY } from './theme.ts';
export function ThemePicker() {
const [theme, setTheme] = useState(() => resolveTheme(document.documentElement.dataset.theme));
useEffect(() => {
const sync = (event: StorageEvent) => {
if (event.key !== THEME_STORAGE_KEY && event.key !== null) return;
const next = resolveTheme(event.newValue);
applyTheme(next);
setTheme(next);
};
window.addEventListener('storage', sync);
return () => window.removeEventListener('storage', sync);
}, []);
const choose = (value: string) => {
// Saved preferences are untrusted: only known palette identifiers may reach the DOM.
if (!isTheme(value)) return;
applyTheme(value);
setTheme(value);
try { localStorage.setItem(THEME_STORAGE_KEY, value); }
catch { /* Theme switching still works for this page when storage is blocked. */ }
};
return <label className="theme-picker" title="Choose your Catppuccin flavor">
<Palette size={15} aria-hidden="true" />
<select aria-label="Catppuccin theme" value={theme} onChange={event => choose(event.target.value)}>
{THEMES.map(option => <option key={option.id} value={option.id}>{option.label}</option>)}
</select>
</label>;
}