Files
simo/src/hooks/useTheme.ts

58 lines
1.6 KiB
TypeScript

'use client';
import { useState, useEffect, useCallback } from 'react';
type Theme = 'light' | 'dark' | 'system';
function getSystemTheme(): 'light' | 'dark' {
if (typeof window === 'undefined') return 'light';
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function applyTheme(theme: Theme) {
const resolved = theme === 'system' ? getSystemTheme() : theme;
const root = document.documentElement;
if (resolved === 'dark') {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
}
export function useTheme() {
const [theme, setThemeState] = useState<Theme>('system');
// Read from localStorage on mount
useEffect(() => {
const stored = localStorage.getItem('simo-theme') as Theme | null;
const initial = stored ?? 'system';
setThemeState(initial);
applyTheme(initial);
}, []);
// Listen for system theme changes when in 'system' mode
useEffect(() => {
const mq = window.matchMedia('(prefers-color-scheme: dark)');
const handler = () => {
if (theme === 'system') applyTheme('system');
};
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
}, [theme]);
const setTheme = useCallback((t: Theme) => {
setThemeState(t);
localStorage.setItem('simo-theme', t);
applyTheme(t);
}, []);
const cycle = useCallback(() => {
const order: Theme[] = ['light', 'dark', 'system'];
const idx = order.indexOf(theme);
const next = order[(idx + 1) % order.length];
setTheme(next);
}, [theme, setTheme]);
return { theme, setTheme, cycle };
}