"use client"; import React, { createContext, useContext, useEffect, useState, useCallback } from "react"; export type ThemeMode = "auto" | "light" | "dark" | "glass"; export type ResolvedTheme = "light" | "dark" | "glass"; interface ThemeContextType { mode: ThemeMode; resolvedTheme: ResolvedTheme; setMode: (mode: ThemeMode) => void; } const STORAGE_KEY = "dt_theme_mode"; export function getAutoTheme(date: Date = new Date()): "light" | "dark" { const hour = date.getHours(); return hour >= 6 && hour < 18 ? "light" : "dark"; } const ThemeContext = createContext({ mode: "auto", resolvedTheme: "dark", setMode: () => {}, }); export function ThemeProvider({ children }: { children: React.ReactNode }) { const [mode, setModeState] = useState("auto"); const [resolvedTheme, setResolvedTheme] = useState("dark"); const [mounted, setMounted] = useState(false); // Initialize theme from localStorage & system time on mount useEffect(() => { try { const saved = localStorage.getItem(STORAGE_KEY) as ThemeMode | null; const initialMode = saved && ["auto", "light", "dark", "glass"].includes(saved) ? saved : "auto"; setModeState(initialMode); const computed = initialMode === "auto" ? getAutoTheme() : initialMode; setResolvedTheme(computed); document.documentElement.setAttribute("data-theme", computed); } catch { const computed = getAutoTheme(); setResolvedTheme(computed); document.documentElement.setAttribute("data-theme", computed); } setMounted(true); }, []); // Update theme data-theme attribute and interval timer for auto mode useEffect(() => { if (!mounted) return; const computeResolved = (): ResolvedTheme => { if (mode === "auto") { return getAutoTheme(); } return mode; }; const currentResolved = computeResolved(); setResolvedTheme(currentResolved); document.documentElement.setAttribute("data-theme", currentResolved); // If auto mode, poll time boundaries every 30 seconds if (mode === "auto") { const interval = setInterval(() => { const nextResolved = getAutoTheme(); if (nextResolved !== currentResolved) { setResolvedTheme(nextResolved); document.documentElement.setAttribute("data-theme", nextResolved); } }, 30000); return () => clearInterval(interval); } }, [mode, mounted]); const setMode = useCallback((newMode: ThemeMode) => { setModeState(newMode); try { localStorage.setItem(STORAGE_KEY, newMode); } catch { // Storage unavailable } }, []); return ( {children} ); } export function useTheme() { return useContext(ThemeContext); } export const ThemeScript = () => { const code = ` (function() { try { var stored = localStorage.getItem('${STORAGE_KEY}'); var mode = (stored && ['auto', 'light', 'dark', 'glass'].indexOf(stored) !== -1) ? stored : 'auto'; var resolved = mode; if (mode === 'auto') { var hour = new Date().getHours(); resolved = (hour >= 6 && hour < 18) ? 'light' : 'dark'; } document.documentElement.setAttribute('data-theme', resolved); } catch (e) {} })(); `; return