77 lines
2.2 KiB
TypeScript
77 lines
2.2 KiB
TypeScript
import React, { createContext, useContext, useState, useEffect, useMemo, useCallback } from 'react';
|
|
import { ThemeProvider } from '@mui/material/styles';
|
|
import { CssBaseline } from '@mui/material';
|
|
import { lightTheme, darkTheme } from '../theme/theme';
|
|
|
|
type ThemeMode = 'system' | 'light' | 'dark';
|
|
|
|
interface ThemeModeContextValue {
|
|
themeMode: ThemeMode;
|
|
setThemeMode: (mode: ThemeMode) => void;
|
|
resolvedMode: 'light' | 'dark';
|
|
}
|
|
|
|
const ThemeModeContext = createContext<ThemeModeContextValue>({
|
|
themeMode: 'system',
|
|
setThemeMode: () => {},
|
|
resolvedMode: 'light',
|
|
});
|
|
|
|
export function useThemeMode(): ThemeModeContextValue {
|
|
return useContext(ThemeModeContext);
|
|
}
|
|
|
|
function getSystemPreference(): 'light' | 'dark' {
|
|
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
return 'dark';
|
|
}
|
|
return 'light';
|
|
}
|
|
|
|
const STORAGE_KEY = 'themeMode';
|
|
|
|
export const ThemeModeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const [themeMode, setThemeModeState] = useState<ThemeMode>(() => {
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (stored === 'light' || stored === 'dark' || stored === 'system') {
|
|
return stored;
|
|
}
|
|
return 'system';
|
|
});
|
|
|
|
const [systemPreference, setSystemPreference] = useState<'light' | 'dark'>(getSystemPreference);
|
|
|
|
useEffect(() => {
|
|
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
|
const handler = (e: MediaQueryListEvent) => {
|
|
setSystemPreference(e.matches ? 'dark' : 'light');
|
|
};
|
|
mq.addEventListener('change', handler);
|
|
return () => mq.removeEventListener('change', handler);
|
|
}, []);
|
|
|
|
const setThemeMode = useCallback((mode: ThemeMode) => {
|
|
setThemeModeState(mode);
|
|
localStorage.setItem(STORAGE_KEY, mode);
|
|
}, []);
|
|
|
|
const resolvedMode: 'light' | 'dark' =
|
|
themeMode === 'system' ? systemPreference : themeMode;
|
|
|
|
const theme = resolvedMode === 'dark' ? darkTheme : lightTheme;
|
|
|
|
const value = useMemo(
|
|
() => ({ themeMode, setThemeMode, resolvedMode }),
|
|
[themeMode, resolvedMode],
|
|
);
|
|
|
|
return (
|
|
<ThemeModeContext.Provider value={value}>
|
|
<ThemeProvider theme={theme}>
|
|
<CssBaseline />
|
|
{children}
|
|
</ThemeProvider>
|
|
</ThemeModeContext.Provider>
|
|
);
|
|
};
|