new features, bookstack
This commit is contained in:
76
frontend/src/contexts/ThemeContext.tsx
Normal file
76
frontend/src/contexts/ThemeContext.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useMemo } 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 = (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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user