69 lines
2.1 KiB
TypeScript
69 lines
2.1 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
|
|
export type Appearance = 'light' | 'dark' | 'system';
|
|
|
|
export function useAppearance(): { appearance: Appearance; updateAppearance: (mode: Appearance) => void } {
|
|
const [appearance, setAppearance] = useState<Appearance>('system');
|
|
|
|
useEffect(() => {
|
|
const stored = localStorage.getItem('theme') as Appearance | null;
|
|
if (stored) {
|
|
setAppearance(stored);
|
|
} else {
|
|
setAppearance('system');
|
|
}
|
|
}, []);
|
|
|
|
const updateAppearance = (mode: Appearance) => {
|
|
setAppearance(mode);
|
|
localStorage.setItem('theme', mode);
|
|
if (mode === 'dark') {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (appearance === 'system') {
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
if (mediaQuery.matches) {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
const listener = (e: MediaQueryListEvent) => {
|
|
if (e.matches) {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
};
|
|
mediaQuery.addEventListener('change', listener);
|
|
return () => mediaQuery.removeEventListener('change', listener);
|
|
} else if (appearance === 'dark') {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
}, [appearance]);
|
|
|
|
return { appearance, updateAppearance };
|
|
}
|
|
|
|
export function initializeTheme() {
|
|
const stored = localStorage.getItem('theme') as Appearance | null;
|
|
if (stored) {
|
|
if (stored === 'dark') {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
} else {
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
if (mediaQuery.matches) {
|
|
document.documentElement.classList.add('dark');
|
|
}
|
|
}
|
|
}
|