import { computed, onMounted, onUnmounted, ref, unref, watch } from "vue"; import { mapIterable, toList } from "../helpers/iterators"; import { useLocalStorage } from "./useLocalStorage"; type Theme = "light" | "dark"; type Callback = (mode: Theme) => void; const cm = new Set(); if (window.matchMedia) { window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => { toList(mapIterable(cm.values(), (cb) => cb(e.matches ? "dark" : "light"))); }); } const init = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; const browserTheme = ref(init); const savedTheme = useLocalStorage("theme"); export function useTheme(_cb?: Callback) { const theme = computed(() => { return savedTheme.value ? savedTheme.value : browserTheme.value; }); const cb = (theme: Theme) => { browserTheme.value = theme; _cb?.(theme); }; function toggleTheme() { savedTheme.value = theme.value === "light" ? "dark" : theme.value === "dark" ? "light" : "light"; } watch(theme, (v) => { _cb?.(unref(v)); }); onMounted(() => { cm.add(cb); }); onUnmounted(() => { cm.delete(cb); }); return [theme, toggleTheme] as const; }