frontend/src/theme/AppThemeProvider.tsx
2025-04-22 15:05:26 -06:00

61 lines
1.9 KiB
TypeScript

import React, { createContext, useContext, useMemo, useState } from "react";
import { ThemeProvider, createTheme, PaletteMode } from "@mui/material/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
import { getTheme } from "./theme";
// --- You can import your own makePaletteColor() here if needed ---
type ThemeMode = "light" | "dark" | "system";
interface ThemeModeContextType {
mode: ThemeMode;
resolvedMode: PaletteMode; // actual value used
toggleMode: () => void;
setMode: (mode: ThemeMode) => void;
}
const ThemeModeContext = createContext<ThemeModeContextType | undefined>(undefined);
export const useThemeMode = () => {
const context = useContext(ThemeModeContext);
if (!context) {
throw new Error("useThemeMode must be used within ThemeModeProvider");
}
return context;
};
export const AppThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const savedTheme = localStorage.getItem("theme");
const isValidTheme = (theme: string | null): theme is ThemeMode =>
theme === "light" || theme === "dark" || theme === "system";
const [mode, setMode] = useState<ThemeMode>(isValidTheme(savedTheme) ? savedTheme : "system");
const prefersDark = useMediaQuery("(prefers-color-scheme: dark)");
const resolvedMode: PaletteMode = mode === "system" ? (prefersDark ? "dark" : "light") : mode;
const theme = useMemo(() => getTheme(resolvedMode), [resolvedMode]);
const toggleMode = () => {
setMode(prev =>
prev === "light" ? "dark" :
prev === "dark" ? "system" :
"light"
);
};
const contextValue = useMemo(() => ({
mode,
resolvedMode,
toggleMode,
setMode,
}), [mode, resolvedMode]);
return (
<ThemeModeContext.Provider value={contextValue}>
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
</ThemeModeContext.Provider>
);
};