Spaces:
Running
Running
File size: 1,826 Bytes
fb12607 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | "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>
);
}
|