import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode, } from "react"; type Theme = "light" | "dark"; interface ThemeContextValue { theme: Theme; setTheme: (theme: Theme) => void; toggleTheme: () => void; } const THEME_STORAGE_KEY = "paperclip.theme"; const DARK_THEME_COLOR = "#18181b"; const LIGHT_THEME_COLOR = "#ffffff"; const ThemeContext = createContext(undefined); function resolveThemeFromDocument(): Theme { if (typeof document === "undefined") return "dark"; return document.documentElement.classList.contains("dark") ? "dark" : "light"; } function applyTheme(theme: Theme) { if (typeof document === "undefined") return; const isDark = theme === "dark"; const root = document.documentElement; root.classList.toggle("dark", isDark); root.style.colorScheme = isDark ? "dark" : "light"; const themeColorMeta = document.querySelector('meta[name="theme-color"]'); if (themeColorMeta instanceof HTMLMetaElement) { themeColorMeta.setAttribute("content", isDark ? DARK_THEME_COLOR : LIGHT_THEME_COLOR); } } export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setThemeState] = useState(() => resolveThemeFromDocument()); const setTheme = useCallback((nextTheme: Theme) => { setThemeState(nextTheme); }, []); const toggleTheme = useCallback(() => { setThemeState((current) => (current === "dark" ? "light" : "dark")); }, []); useEffect(() => { applyTheme(theme); try { localStorage.setItem(THEME_STORAGE_KEY, theme); } catch { // Ignore local storage write failures in restricted environments. } }, [theme]); const value = useMemo( () => ({ theme, setTheme, toggleTheme, }), [theme, setTheme, toggleTheme], ); return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error("useTheme must be used within ThemeProvider"); } return context; }