Files
kan/apps/web/src/providers/theme.tsx
2024-12-12 14:34:10 +00:00

70 lines
2.1 KiB
TypeScript

import React, {
createContext,
useContext,
useEffect,
useState,
type ReactNode,
} from "react";
interface ThemeContextProps {
themePreference: "light" | "dark" | "system";
activeTheme: "light" | "dark";
switchTheme: (theme: "light" | "dark" | "system") => void;
}
const ThemeContext = createContext<ThemeContextProps | undefined>(undefined);
export const ThemeProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
const [themePreference, setThemePreference] = useState<
"light" | "dark" | "system"
>("system");
const [activeTheme, setActiveTheme] = useState<"light" | "dark">("light");
const switchTheme = (theme: "light" | "dark" | "system") => {
if (theme === "system") {
localStorage.removeItem("theme");
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
setActiveTheme(isDark ? "dark" : "light");
document.documentElement.classList.toggle("dark", isDark);
} else {
const isDark = theme === "dark";
document.documentElement.classList.toggle("dark", isDark);
localStorage.theme = theme;
setActiveTheme(isDark ? "dark" : "light");
}
setThemePreference(theme);
};
useEffect(() => {
if (!("theme" in localStorage)) {
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
document.documentElement.classList.toggle("dark", isDark);
setActiveTheme(isDark ? "dark" : "light");
setThemePreference("system");
} else {
const isDark = localStorage.theme === "dark";
document.documentElement.classList.toggle("dark", isDark);
setActiveTheme(isDark ? "dark" : "light");
setThemePreference(localStorage.theme as "light" | "dark");
}
}, []);
return (
<ThemeContext.Provider
value={{ switchTheme, themePreference, activeTheme }}
>
{themePreference.length ? children : null}
</ThemeContext.Provider>
);
};
export const useTheme = (): ThemeContextProps => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};