Write on the margins of the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
at main 79 lines 2.0 kB view raw
1import { atom, onMount } from "nanostores"; 2 3export type Theme = "light" | "dark" | "system"; 4export type Layout = "sidebar" | "compact"; 5 6export const $theme = atom<Theme>("system"); 7export const $layout = atom<Layout>("sidebar"); 8 9onMount($theme, () => { 10 if (typeof window !== "undefined") { 11 const stored = localStorage.getItem("theme") as Theme | null; 12 if (stored && ["light", "dark", "system"].includes(stored)) { 13 $theme.set(stored); 14 } 15 applyTheme($theme.get()); 16 } 17 18 return $theme.subscribe((theme) => { 19 if (typeof window !== "undefined") { 20 localStorage.setItem("theme", theme); 21 applyTheme(theme); 22 } 23 }); 24}); 25 26onMount($layout, () => { 27 if (typeof window !== "undefined") { 28 const stored = localStorage.getItem("layout_preference") as Layout | null; 29 if (stored && ["sidebar", "compact"].includes(stored)) { 30 $layout.set(stored); 31 } 32 } 33 34 return $layout.subscribe((layout) => { 35 if (typeof window !== "undefined") { 36 localStorage.setItem("layout_preference", layout); 37 } 38 }); 39}); 40 41function applyTheme(theme: Theme) { 42 const root = window.document.documentElement; 43 root.classList.remove("light", "dark"); 44 delete root.dataset.theme; 45 46 if (theme === "system") { 47 const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") 48 .matches 49 ? "dark" 50 : "light"; 51 root.dataset.theme = systemTheme; 52 } else { 53 root.dataset.theme = theme; 54 } 55} 56 57if (typeof window !== "undefined") { 58 const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); 59 mediaQuery.addEventListener("change", () => { 60 if ($theme.get() === "system") { 61 applyTheme("system"); 62 } 63 }); 64} 65 66export function setTheme(theme: Theme) { 67 $theme.set(theme); 68} 69 70export function setLayout(layout: Layout) { 71 $layout.set(layout); 72} 73 74export function cycleTheme() { 75 const current = $theme.get(); 76 const next: Theme = 77 current === "system" ? "light" : current === "light" ? "dark" : "system"; 78 $theme.set(next); 79}