diff --git a/index.html b/index.html
index 58f06d7..b3f7687 100644
--- a/index.html
+++ b/index.html
@@ -4,6 +4,16 @@
+
margin
diff --git a/src/components/EditorView.tsx b/src/components/EditorView.tsx
index 3c38e9e..b5173be 100644
--- a/src/components/EditorView.tsx
+++ b/src/components/EditorView.tsx
@@ -7,6 +7,7 @@ import { Settings } from "./Settings";
import { Editor } from "../editor/Editor";
import { FloatingToolbar } from "../editor/FloatingToolbar";
import { useBook } from "../store/useBook";
+import { useTheme } from "../store/useTheme";
import type { Book } from "../model/book";
import { saveBook } from "../library";
import { isDesktop } from "../ipc";
@@ -22,6 +23,8 @@ export function EditorView() {
const setChapterContent = useBook((s) => s.setChapterContent);
const setChapterTitle = useBook((s) => s.setChapterTitle);
const markSaved = useBook((s) => s.markSaved);
+ const theme = useTheme((s) => s.theme);
+ const toggleTheme = useTheme((s) => s.toggle);
const [editor, setEditor] = useState(null);
const [dock, setDock] = useState(true);
@@ -99,6 +102,16 @@ export function EditorView() {
>
)}
+
diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx
index dbcd7ff..bc60a57 100644
--- a/src/components/Icon.tsx
+++ b/src/components/Icon.tsx
@@ -1,9 +1,12 @@
+import type { ReactNode } from "react";
+
interface IconProps {
- d: string;
+ d?: string;
size?: number;
+ children?: ReactNode;
}
-export function Icon({ d, size = 16 }: IconProps) {
+export function Icon({ d, size = 16, children }: IconProps) {
return (
);
}
diff --git a/src/store/useTheme.ts b/src/store/useTheme.ts
new file mode 100644
index 0000000..e96818f
--- /dev/null
+++ b/src/store/useTheme.ts
@@ -0,0 +1,16 @@
+import { create } from "zustand";
+import { applyTheme, initialTheme, type Theme } from "../theme";
+
+interface ThemeState {
+ theme: Theme;
+ toggle: () => void;
+}
+
+export const useTheme = create((set, get) => ({
+ theme: initialTheme(),
+ toggle: () => {
+ const next: Theme = get().theme === "dark" ? "light" : "dark";
+ applyTheme(next);
+ set({ theme: next });
+ },
+}));
diff --git a/src/theme.ts b/src/theme.ts
new file mode 100644
index 0000000..9f3eab0
--- /dev/null
+++ b/src/theme.ts
@@ -0,0 +1,16 @@
+export type Theme = "light" | "dark";
+
+const KEY = "margin-theme";
+
+export function initialTheme(): Theme {
+ const attr = document.documentElement.getAttribute("data-theme");
+ if (attr === "light" || attr === "dark") return attr;
+ const saved = localStorage.getItem(KEY);
+ if (saved === "light" || saved === "dark") return saved;
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+}
+
+export function applyTheme(theme: Theme) {
+ document.documentElement.setAttribute("data-theme", theme);
+ localStorage.setItem(KEY, theme);
+}