49 lines
1.1 KiB
TypeScript
49 lines
1.1 KiB
TypeScript
import { ref } from "vue";
|
|
|
|
const STORAGE_KEY = "bio-theme";
|
|
const isDark = ref(false);
|
|
|
|
function applyDarkClass(value: boolean) {
|
|
if (typeof document === "undefined") return;
|
|
const root = document.documentElement;
|
|
if (value) root.classList.add("dark");
|
|
else root.classList.remove("dark");
|
|
}
|
|
|
|
function readInitial(): boolean {
|
|
if (typeof window === "undefined") return false;
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (stored === "dark") return true;
|
|
if (stored === "light") return false;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return window.matchMedia?.("(prefers-color-scheme: dark)")?.matches ?? false;
|
|
}
|
|
|
|
/** Call once before mounting the app to avoid a flash of wrong theme. */
|
|
export function initTheme() {
|
|
const dark = readInitial();
|
|
isDark.value = dark;
|
|
applyDarkClass(dark);
|
|
}
|
|
|
|
export function useTheme() {
|
|
function setTheme(dark: boolean) {
|
|
isDark.value = dark;
|
|
applyDarkClass(dark);
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, dark ? "dark" : "light");
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
function toggleTheme() {
|
|
setTheme(!isDark.value);
|
|
}
|
|
|
|
return { isDark, setTheme, toggleTheme };
|
|
}
|