d14c629778
Co-authored-by: Cursor <cursoragent@cursor.com>
72 lines
2.2 KiB
JavaScript
72 lines
2.2 KiB
JavaScript
/** 中控主题:暗色(默认)/ 亮色,localStorage hub-theme */
|
|
(function (global) {
|
|
const KEY = "hub-theme";
|
|
const META = { dark: "#0b0e18", light: "#d4dde8" };
|
|
|
|
function normalize(theme) {
|
|
return theme === "light" ? "light" : "dark";
|
|
}
|
|
|
|
function get() {
|
|
try {
|
|
return normalize(localStorage.getItem(KEY));
|
|
} catch (_) {
|
|
return "dark";
|
|
}
|
|
}
|
|
|
|
function broadcastThemeToInstances() {
|
|
const msg = { type: "hub-theme-sync", theme: get() };
|
|
document.querySelectorAll("iframe#instance-frame, iframe.instance-frame").forEach((frame) => {
|
|
try {
|
|
if (frame.contentWindow) frame.contentWindow.postMessage(msg, "*");
|
|
} catch (_) {}
|
|
});
|
|
}
|
|
|
|
function apply(theme) {
|
|
const t = normalize(theme);
|
|
const root = document.documentElement;
|
|
root.setAttribute("data-theme", t);
|
|
try {
|
|
localStorage.setItem(KEY, t);
|
|
} catch (_) {}
|
|
const meta = document.querySelector('meta[name="theme-color"]');
|
|
if (meta) meta.setAttribute("content", META[t]);
|
|
root.style.colorScheme = t;
|
|
document.dispatchEvent(new CustomEvent("hub-theme-change", { detail: { theme: t } }));
|
|
broadcastThemeToInstances();
|
|
return t;
|
|
}
|
|
|
|
function toggle() {
|
|
return apply(get() === "dark" ? "light" : "dark");
|
|
}
|
|
|
|
function syncToggleUI(root) {
|
|
const scope = root || document;
|
|
scope.querySelectorAll(".theme-toggle-btn[data-theme-value]").forEach((btn) => {
|
|
const on = btn.getAttribute("data-theme-value") === get();
|
|
btn.classList.toggle("is-active", on);
|
|
btn.setAttribute("aria-pressed", on ? "true" : "false");
|
|
});
|
|
}
|
|
|
|
function initToggleUI(root) {
|
|
const scope = root || document;
|
|
syncToggleUI(scope);
|
|
scope.querySelectorAll(".theme-toggle-btn[data-theme-value]").forEach((btn) => {
|
|
if (btn.dataset.themeBound === "1") return;
|
|
btn.dataset.themeBound = "1";
|
|
btn.addEventListener("click", () => {
|
|
apply(btn.getAttribute("data-theme-value"));
|
|
syncToggleUI(scope);
|
|
});
|
|
});
|
|
document.addEventListener("hub-theme-change", () => syncToggleUI(scope));
|
|
}
|
|
|
|
apply(get());
|
|
global.HubTheme = { KEY, get, apply, toggle, syncToggleUI, initToggleUI };
|
|
})(typeof window !== "undefined" ? window : globalThis);
|