44 lines
1.0 KiB
TypeScript
44 lines
1.0 KiB
TypeScript
|
|
import { useCallback, useEffect, useState } from 'react';
|
||
|
|
|
||
|
|
import {
|
||
|
|
applyTheme,
|
||
|
|
getStoredTheme,
|
||
|
|
readEffectiveDark,
|
||
|
|
resolveDark,
|
||
|
|
toggleStoredTheme,
|
||
|
|
} from '../lib/theme';
|
||
|
|
|
||
|
|
export function useTheme(): { isDark: boolean; toggle: () => void } {
|
||
|
|
const [isDark, setIsDark] = useState(() => readEffectiveDark());
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||
|
|
|
||
|
|
const sync = () => {
|
||
|
|
const stored = getStoredTheme();
|
||
|
|
const dark = resolveDark(stored, mq.matches);
|
||
|
|
applyTheme(dark);
|
||
|
|
setIsDark(dark);
|
||
|
|
};
|
||
|
|
|
||
|
|
sync();
|
||
|
|
|
||
|
|
const onPreferenceChange = () => {
|
||
|
|
if (getStoredTheme() !== null) return;
|
||
|
|
const dark = resolveDark(null, mq.matches);
|
||
|
|
applyTheme(dark);
|
||
|
|
setIsDark(dark);
|
||
|
|
};
|
||
|
|
|
||
|
|
mq.addEventListener('change', onPreferenceChange);
|
||
|
|
return () => mq.removeEventListener('change', onPreferenceChange);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const toggle = useCallback(() => {
|
||
|
|
const nextDark = toggleStoredTheme();
|
||
|
|
setIsDark(nextDark);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return { isDark, toggle };
|
||
|
|
}
|