Files
homelab-optimized/dashboard/ui/components/theme-provider.tsx
Gitea Mirror Bot 11d496f233
Some checks failed
Documentation / Build Docusaurus (push) Failing after 17m32s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-19 08:46:29 UTC
2026-04-19 08:46:29 +00:00

104 lines
2.3 KiB
TypeScript

"use client";
import {
createContext,
useContext,
useState,
useEffect,
useCallback,
type ReactNode,
} from "react";
import { themes, getTheme, DEFAULT_THEME, type Theme } from "@/lib/themes";
interface ThemeContextValue {
theme: Theme;
themeName: string;
setTheme: (name: string) => void;
}
const ThemeContext = createContext<ThemeContextValue>({
theme: themes[0],
themeName: DEFAULT_THEME,
setTheme: () => {},
});
export function useTheme() {
return useContext(ThemeContext);
}
// Unique ID for the dynamic style element
const STYLE_ID = "theme-gradient-style";
function applyTheme(theme: Theme) {
const root = document.documentElement;
// Toggle dark class based on theme
if (theme.isDark) {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
// Set all CSS custom properties from the theme
for (const [key, value] of Object.entries(theme.vars)) {
root.style.setProperty(key, value);
}
// Set the body background
document.body.style.background = theme.bodyBg;
// Set the gradient via a style element (body::before can't be styled inline)
let styleEl = document.getElementById(STYLE_ID) as HTMLStyleElement | null;
if (!styleEl) {
styleEl = document.createElement("style");
styleEl.id = STYLE_ID;
document.head.appendChild(styleEl);
}
styleEl.textContent = `
body::before {
background: ${theme.bgGradient} !important;
}
`;
// Store in localStorage
try {
localStorage.setItem("homelab-theme", theme.name);
} catch {
// ignore storage errors
}
}
export function ThemeProvider({ children }: { children: ReactNode }) {
const [themeName, setThemeName] = useState(DEFAULT_THEME);
const theme = getTheme(themeName);
// Load saved theme on mount
useEffect(() => {
try {
const saved = localStorage.getItem("homelab-theme");
if (saved && themes.some((t) => t.name === saved)) {
setThemeName(saved);
}
} catch {
// ignore
}
}, []);
// Apply theme whenever it changes
useEffect(() => {
applyTheme(theme);
}, [theme]);
const setTheme = useCallback((name: string) => {
if (themes.some((t) => t.name === name)) {
setThemeName(name);
}
}, []);
return (
<ThemeContext.Provider value={{ theme, themeName, setTheme }}>
{children}
</ThemeContext.Provider>
);
}