"use client"; import { useEffect } from "react"; export function FaviconUpdater() { useEffect(() => { let isDisposed = false; const mediaQuery = window.matchMedia?.("(prefers-color-scheme: dark)"); const getFaviconUrl = () => { const html = document.documentElement; const hasDarkClass = html.classList.contains("dark"); const hasLightClass = html.classList.contains("light"); const prefersDark = Boolean(mediaQuery?.matches); const isDark = hasDarkClass || (!hasLightClass && prefersDark); return isDark ? "/api/favicon?theme=dark" : "/api/favicon"; }; const updateFavicon = () => { if (isDisposed) return; const urlWithTheme = getFaviconUrl(); const iconType = urlWithTheme.includes("theme=dark") ? "image/png" : "image/x-icon"; const href = `${urlWithTheme}${urlWithTheme.includes("?") ? "&" : "?"}v=${Date.now()}`; const managedSelector = 'link[rel="icon"],link[rel="shortcut icon"],link[rel="apple-touch-icon"]'; const existingLinks = document.querySelectorAll( managedSelector ); existingLinks.forEach((link) => { link.href = href; link.setAttribute("data-managed-favicon", "true"); if (link.rel === "icon" || link.rel === "shortcut icon") { link.type = iconType; link.setAttribute("sizes", "any"); } }); const ensureLink = (rel: string, type?: string) => { let link = document.querySelector( `link[rel="${rel}"]` ) as HTMLLinkElement | null; if (!link) { link = document.createElement("link"); link.rel = rel; document.head.appendChild(link); } link.href = href; link.setAttribute("data-managed-favicon", "true"); if (type) { link.type = type; } if (rel === "icon") { link.setAttribute("sizes", "any"); } }; ensureLink("icon", iconType); ensureLink("apple-touch-icon"); ensureLink("shortcut icon", iconType); }; const observer = new MutationObserver(updateFavicon); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"], }); mediaQuery?.addEventListener?.("change", updateFavicon); Promise.resolve().then(() => { updateFavicon(); }); return () => { isDisposed = true; observer.disconnect(); mediaQuery?.removeEventListener?.("change", updateFavicon); }; }, []); return null; }