Write on the margins of the internet. Powered by the AT Protocol.
margin.at
extension
web
atproto
comments
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}