import { useEffect } from "preact/hooks"; const THEME_KEY = "cyberhybrid-theme-preference"; function applyTheme(root: Element, mode: string): void { root.setAttribute("data-theme-mode", mode); } function syncToggleLabels(root: Element): void { const isDark = root.getAttribute("data-theme-mode") !== "light"; const label = isDark ? "Switch to light mode" : "Switch to dark mode"; const toggles = root.querySelectorAll("[data-theme-toggle]"); toggles.forEach((el) => { el.setAttribute("aria-label", label); el.setAttribute("title", label); }); } const THEME_COOKIE = "cyberhybrid-theme"; const COOKIE_MAX_AGE = 365 * 24 * 60 * 60; // 1 year function setThemeCookie(mode: string): void { try { document.cookie = `${THEME_COOKIE}=${mode}; path=/; max-age=${COOKIE_MAX_AGE}; SameSite=Lax`; } catch { // ignore } } function persistTheme(mode: string): void { try { localStorage.setItem(THEME_KEY, mode); setThemeCookie(mode); } catch { // ignore } } /** * Client-only island that applies saved theme and wires up theme toggle clicks. * Renders nothing; runs theme logic in useEffect to avoid dangerouslySetInnerHTML. */ export default function ThemeHydration() { useEffect(() => { const root = document.documentElement; // Trust server-rendered theme (from cookie) on first paint; do not overwrite // with localStorage to avoid flicker. Sync storage to match so next load is correct. const serverTheme = root.getAttribute("data-theme-mode") === "light" ? "light" : "dark"; persistTheme(serverTheme); syncToggleLabels(root); const handleClick = (event: Event) => { const target = event.target as Node; if (!target || !(target instanceof Element)) return; const toggle = target.closest("[data-theme-toggle]"); if (!toggle) return; event.preventDefault(); event.stopPropagation(); const current = root.getAttribute("data-theme-mode") === "light" ? "light" : "dark"; const next = current === "dark" ? "light" : "dark"; applyTheme(root, next); persistTheme(next); syncToggleLabels(root); }; document.addEventListener("click", handleClick, true); return () => document.removeEventListener("click", handleClick, true); }, []); return null; }