TheBird

mode.ts

1.6 kB · typescript · 60 lines

1import { MODE_KEY, THEME_COLORS } from "../config/shop.ts";23type Mode = "dark" | "light";45const listeners = new Set<() => void>();67let mode: Mode = "light";89const clean = (value: string | null): Mode | null => (value === "dark" || value === "light" ? value : null);1011const stored = () => {12  try {13    return clean(localStorage.getItem(MODE_KEY));14  } catch {15    return null;16  }17};1819const system = (): Mode => (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");2021function paint(next: Mode) {22  mode = next;23  const root = document.documentElement;24  root.dataset.mode = next;25  const meta = document.querySelector<HTMLMetaElement>('meta[name="theme-color"]');26  if (meta) meta.content = THEME_COLORS[next];27  for (const fn of listeners) fn();28  dispatchEvent(new CustomEvent("mode", { detail: next }));29}3031export const get = () => mode;3233export const server = (): Mode => "light";3435export const none = () => null;3637export function subscribe(fn: () => void) {38  listeners.add(fn);39  return () => void listeners.delete(fn);40}4142function set(next: Mode) {43  try {44    localStorage.setItem(MODE_KEY, next);45  } catch {}46  paint(next);47}4849export const toggle = () => set(mode === "dark" ? "light" : "dark");5051export function start() {52  const dark = matchMedia("(prefers-color-scheme: dark)");53  paint(clean(document.documentElement.dataset.mode ?? null) ?? stored() ?? system());54  dark.addEventListener("change", () => {55    if (!stored()) paint(system());56  });57  addEventListener("storage", (event) => {58    if (event.key === MODE_KEY) paint(stored() ?? system());59  });60}