import { useEffect, useState } from 'react'; import './theme.css'; export type ThemePreference = 'light' | 'dark' | 'system'; type ThemeMode = 'light' | 'dark'; export const THEME_STORAGE_KEY = 'uptime.theme'; export function readThemePreference(): ThemePreference { try { const saved = window.localStorage.getItem(THEME_STORAGE_KEY); if (saved === 'light' || saved === 'dark') return saved; } catch { // Storage may be disabled; the system preference still works. } return 'system'; } export function applyThemePreference(preference: ThemePreference) { const dark = preference === 'dark' || (preference === 'system' && window.matchMedia?.('(prefers-color-scheme: dark)').matches); document.documentElement.dataset.theme = dark ? 'dark' : 'light'; } function currentTheme(): ThemeMode { const theme = document.documentElement.dataset.theme; if (theme === 'light' || theme === 'dark') return theme; const preference = readThemePreference(); return preference === 'dark' || (preference === 'system' && window.matchMedia?.('(prefers-color-scheme: dark)').matches) ? 'dark' : 'light'; } export function ThemeControl() { const [preference, setPreference] = useState(readThemePreference); const [theme, setTheme] = useState(currentTheme); useEffect(() => { applyThemePreference(preference); setTheme(currentTheme()); if (preference !== 'system') return; const media = window.matchMedia?.('(prefers-color-scheme: dark)'); if (!media) return; const onChange = () => { applyThemePreference('system'); setTheme(currentTheme()); }; media.addEventListener('change', onChange); return () => media.removeEventListener('change', onChange); }, [preference]); useEffect(() => { const onThemeChange = (event: Event) => { const next = (event as CustomEvent).detail; setPreference(next); setTheme(next); }; window.addEventListener('uptime:theme-change', onThemeChange); return () => window.removeEventListener('uptime:theme-change', onThemeChange); }, []); const nextTheme = theme === 'dark' ? 'light' : 'dark'; const action = `Switch to ${nextTheme} theme`; return ( ); }