Files
2026-07-13 12:52:40 +08:00

57 lines
1.6 KiB
TypeScript

export const HUB_THEME_STORAGE_KEY = "cline-hub-theme";
export type HubTheme = "light" | "dark";
export function readStoredHubTheme(): HubTheme | null {
const stored = window.localStorage.getItem(HUB_THEME_STORAGE_KEY);
return stored === "light" || stored === "dark" ? stored : null;
}
export function readSystemHubTheme(): HubTheme {
const kind = document.body.dataset.vscodeThemeKind;
if (kind) {
return kind === "vscode-dark" || kind === "vscode-high-contrast"
? "dark"
: "light";
}
return window.matchMedia?.("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}
export function applyHubTheme(theme: HubTheme): HubTheme {
document.documentElement.classList.toggle("dark", theme === "dark");
document.documentElement.dataset.clineHubTheme = theme;
return theme;
}
export function syncHubTheme(): HubTheme {
return applyHubTheme(readStoredHubTheme() ?? readSystemHubTheme());
}
export function setStoredHubTheme(theme: HubTheme): HubTheme {
window.localStorage.setItem(HUB_THEME_STORAGE_KEY, theme);
return applyHubTheme(theme);
}
/**
* Follow OS light/dark changes while the user has no stored preference.
* Returns a cleanup function that removes the listener.
*/
export function watchSystemHubTheme(
onChange?: (theme: HubTheme) => void,
): () => void {
const media = window.matchMedia?.("(prefers-color-scheme: dark)");
if (!media) {
return () => {};
}
const handle = () => {
if (readStoredHubTheme() !== null) {
return;
}
onChange?.(applyHubTheme(readSystemHubTheme()));
};
media.addEventListener("change", handle);
return () => media.removeEventListener("change", handle);
}