MicProtocol / apps /web /src /lib /theme-toggle.tsx
Benaah's picture
Upload folder using huggingface_hub
fb12607 verified
Raw History Blame Contribute Delete
1.83 kB
"use client";
import { useEffect, useSyncExternalStore } from "react";
import { Moon, Sun } from "lucide-react";
type Theme = "light" | "dark";
const THEME_STORAGE_KEY = "MicProtocol-theme";
const THEME_CHANGE_EVENT = "micprotocol-theme-change";
function getThemeSnapshot(): Theme {
return window.localStorage.getItem(THEME_STORAGE_KEY) === "light"
? "light"
: "dark";
}
function getServerThemeSnapshot(): Theme {
return "dark";
}
function subscribeToTheme(onChange: () => void): () => void {
window.addEventListener("storage", onChange);
window.addEventListener(THEME_CHANGE_EVENT, onChange);
return () => {
window.removeEventListener("storage", onChange);
window.removeEventListener(THEME_CHANGE_EVENT, onChange);
};
}
export function ThemeToggle({ className = "" }: { className?: string }) {
const theme = useSyncExternalStore(
subscribeToTheme,
getThemeSnapshot,
getServerThemeSnapshot,
);
useEffect(() => {
document.documentElement.setAttribute("data-theme", theme);
document
.querySelector('meta[name="theme-color"]')
?.setAttribute("content", theme === "light" ? "#f7f6f2" : "#141516");
}, [theme]);
const toggle = () => {
const next = theme === "light" ? "dark" : "light";
window.localStorage.setItem(THEME_STORAGE_KEY, next);
document.documentElement.setAttribute("data-theme", next);
window.dispatchEvent(new Event(THEME_CHANGE_EVENT));
};
return (
<button
onClick={toggle}
className={`btn btn-ghost ${className}`}
style={{ padding: "var(--space-2)" }}
aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
title={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
>
{theme === "light" ? <Moon size={18} /> : <Sun size={18} />}
</button>
);
}