Files
TasGrid/src/components/ThemeProvider.tsx
T

54 lines
1.7 KiB
TypeScript

import { createSignal, createContext, useContext, createEffect, type ParentComponent } from "solid-js";
type Theme = "dark" | "light" | "system";
interface ThemeProviderState {
theme: () => Theme;
setTheme: (theme: Theme) => void;
resolvedTheme: () => "light" | "dark";
}
const ThemeProviderContext = createContext<ThemeProviderState>();
export const ThemeProvider: ParentComponent = (props) => {
const [theme, setTheme] = createSignal<Theme>("system");
const [resolvedTheme, setResolvedTheme] = createSignal<"light" | "dark">("light");
// Load from local storage on mount
const storedTheme = localStorage.getItem("tasgrid-theme") as Theme | null;
if (storedTheme) {
setTheme(storedTheme);
}
createEffect(() => {
const root = window.document.documentElement;
root.classList.remove("light", "dark");
const currentTheme = theme();
let resolved: "light" | "dark";
if (currentTheme === "system") {
resolved = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
root.classList.add(resolved);
} else {
resolved = currentTheme === "dark" ? "dark" : "light";
root.classList.add(resolved);
}
setResolvedTheme(resolved);
localStorage.setItem("tasgrid-theme", currentTheme);
});
return (
<ThemeProviderContext.Provider value={{ theme, setTheme, resolvedTheme }}>
{props.children}
</ThemeProviderContext.Provider>
);
};
export const useTheme = () => {
const context = useContext(ThemeProviderContext);
if (!context) throw new Error("useTheme must be used within a ThemeProvider");
return context;
};