v2
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
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>;
|
||||
}
|
||||
Reference in New Issue
Block a user