feat: scaffold MUI theme, providers, color mode and i18n

This commit is contained in:
MrFrostDev
2026-05-23 13:58:27 +02:00
parent cb662553d8
commit 4598f2c736
7 changed files with 1030 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
'use client';
import React, {
createContext,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
import { ThemeProvider, createTheme, CssBaseline } from '@mui/material';
import getDesignTokens from '../config/theme';
type Mode = 'light' | 'dark';
interface ColorModeContextValue {
mode: Mode;
toggleColorMode: () => void;
setColorMode: (mode: Mode) => void;
}
const STORAGE_KEY = 'patchpilot:color-mode';
const ColorModeContext = createContext<ColorModeContextValue>({
mode: 'light',
toggleColorMode: () => {},
setColorMode: () => {},
});
export const useColorMode = () => useContext(ColorModeContext);
function detectInitialMode(): Mode {
if (typeof window === 'undefined') return 'light';
const stored = window.localStorage.getItem(STORAGE_KEY);
if (stored === 'light' || stored === 'dark') return stored;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
export const ColorModeProvider = ({ children }: { children: React.ReactNode }) => {
const [mode, setMode] = useState<Mode>('light');
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
setMode(detectInitialMode());
setHydrated(true);
}, []);
useEffect(() => {
if (!hydrated) return;
window.localStorage.setItem(STORAGE_KEY, mode);
}, [mode, hydrated]);
const value = useMemo<ColorModeContextValue>(
() => ({
mode,
toggleColorMode: () => setMode((p) => (p === 'light' ? 'dark' : 'light')),
setColorMode: (next) => setMode(next),
}),
[mode]
);
const theme = useMemo(() => createTheme(getDesignTokens(mode)), [mode]);
return (
<ColorModeContext.Provider value={value}>
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
</ColorModeContext.Provider>
);
};