"use client"; // Light / dark / system theme state. The actual `.dark` class is set on // by an inline script in the root layout (before paint) and kept in sync here. // Preference persists in localStorage. import { createContext, useCallback, useContext, useEffect, useRef, useState, } from "react"; export const THEME_STORAGE_KEY = "aram_theme"; export type Theme = "light" | "dark" | "system"; interface ThemeApi { theme: Theme; resolved: "light" | "dark"; toggle: () => void; setTheme: (t: Theme) => void; } const ThemeContext = createContext(null); function isSystemDark(): boolean { if (typeof window === "undefined") return false; return window.matchMedia("(prefers-color-scheme: dark)").matches; } function applyClass(resolved: "light" | "dark") { document.documentElement.classList.toggle("dark", resolved === "dark"); } function readStorage(): Theme { if (typeof window === "undefined") return "system"; try { const t = localStorage.getItem(THEME_STORAGE_KEY); if (t === "light" || t === "dark" || t === "system") return t; } catch { /* private mode */ } return "system"; } function resolve(theme: Theme): "light" | "dark" { return theme === "system" ? (isSystemDark() ? "dark" : "light") : theme; } export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setThemeState] = useState("system"); const [resolved, setResolved] = useState<"light" | "dark">("light"); const mqRef = useRef(null); // Apply theme to and update resolved state. const apply = useCallback((t: Theme) => { const r = resolve(t); applyClass(r); setResolved(r); }, []); // On mount: read preference, apply, listen to system changes. useEffect(() => { const t = readStorage(); setThemeState(t); apply(t); const mq = window.matchMedia("(prefers-color-scheme: dark)"); mqRef.current = mq; const handler = () => { // Re-read theme from state (via ref won't work for closures, so re-read localStorage). const current = readStorage(); if (current === "system") { apply("system"); } }; mq.addEventListener("change", handler); return () => mq.removeEventListener("change", handler); }, [apply]); const setTheme = useCallback( (t: Theme) => { setThemeState(t); apply(t); try { localStorage.setItem(THEME_STORAGE_KEY, t); } catch { /* private mode */ } }, [apply], ); const toggle = useCallback(() => { const order: Theme[] = ["light", "dark", "system"]; const next = order[(order.indexOf(theme) + 1) % order.length]; setTheme(next); }, [theme, setTheme]); return ( {children} ); } export function useTheme(): ThemeApi { const ctx = useContext(ThemeContext); if (!ctx) throw new Error("useTheme must be used within "); return ctx; }