(null)
- const { activeFilePath, activeFileContent, setContent, annotations, fontSize } = useEditorStore()
+ const { activeFilePath, activeFileContent, setContent, annotations, fontSize, theme } = useEditorStore()
// Initialize CodeMirror once
useEffect(() => {
@@ -120,7 +120,7 @@ export function MarkdownEditor(): JSX.Element {
markdown(),
syntaxHighlighting(defaultHighlightStyle),
annotationField,
- themeCompartment.of(buildTheme(fontSize)),
+ themeCompartment.of(buildTheme(fontSize, theme === 'dark')),
EditorView.lineWrapping,
EditorView.updateListener.of((update) => {
if (update.docChanged) {
@@ -161,12 +161,12 @@ export function MarkdownEditor(): JSX.Element {
view.dispatch({ effects: setAnnotationsEffect.of(annotations) })
}, [annotations])
- // Reconfigure theme when font size changes
+ // Reconfigure theme when font size or colour theme changes
useEffect(() => {
const view = viewRef.current
if (!view) return
- view.dispatch({ effects: themeCompartment.reconfigure(buildTheme(fontSize)) })
- }, [fontSize])
+ view.dispatch({ effects: themeCompartment.reconfigure(buildTheme(fontSize, theme === 'dark')) })
+ }, [fontSize, theme])
return (
diff --git a/src/renderer/store/editorStore.ts b/src/renderer/store/editorStore.ts
index 4c1735a..de45f0d 100644
--- a/src/renderer/store/editorStore.ts
+++ b/src/renderer/store/editorStore.ts
@@ -42,6 +42,10 @@ interface EditorState {
// Editor font size
fontSize: number
setFontSize: (size: number) => void
+
+ // Theme
+ theme: 'dark' | 'light'
+ toggleTheme: () => void
}
export const useEditorStore = create((set, get) => ({
@@ -133,5 +137,15 @@ export const useEditorStore = create((set, get) => ({
const clamped = Math.max(11, Math.min(24, size))
localStorage.setItem('editorFontSize', String(clamped))
set({ fontSize: clamped })
+ },
+
+ theme: (localStorage.getItem('editorTheme') as 'dark' | 'light') || 'dark',
+ toggleTheme: () => {
+ set((s) => {
+ const next = s.theme === 'dark' ? 'light' : 'dark'
+ localStorage.setItem('editorTheme', next)
+ document.documentElement.classList.toggle('light', next === 'light')
+ return { theme: next }
+ })
}
}))
diff --git a/src/renderer/styles/app.css b/src/renderer/styles/app.css
index b8b9327..676c12f 100644
--- a/src/renderer/styles/app.css
+++ b/src/renderer/styles/app.css
@@ -28,6 +28,25 @@
text-transform: uppercase;
}
+.app-titlebar-theme-btn {
+ position: absolute;
+ right: 12px;
+ background: none;
+ border: none;
+ color: var(--text-muted);
+ font-size: 13px;
+ cursor: pointer;
+ padding: 2px 4px;
+ border-radius: 4px;
+ line-height: 1;
+ -webkit-app-region: no-drag;
+ transition: color 0.15s;
+}
+
+.app-titlebar-theme-btn:hover {
+ color: var(--text-primary);
+}
+
/* ─── Sidebar ──────────────────────────────────────────────────── */
.sidebar {
background: var(--sidebar-bg);
diff --git a/src/renderer/styles/global.css b/src/renderer/styles/global.css
index 4f3987e..55db3d3 100644
--- a/src/renderer/styles/global.css
+++ b/src/renderer/styles/global.css
@@ -38,6 +38,30 @@
--font-sans: -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
}
+/* ─── Light mode token overrides (sepia) ──────────────────────── */
+html.light {
+ --bg-base: #f2ead8;
+ --sidebar-bg: #e8dfc8;
+ --toolbar-bg: #ddd4bc;
+ --editor-bg: #f2ead8;
+ --message-bg: #e8dfc8;
+ --user-message-bg:#ddd4bc;
+ --input-bg: #e8dfc8;
+
+ --border: #c4b89a;
+ --hover-bg: rgba(120,88,40,0.08);
+ --active-bg: rgba(120,88,40,0.15);
+
+ --text-primary: #241c0e;
+ --text-secondary: #52401e;
+ --text-muted: #7a6640;
+
+ --heading-color: #3c2c0e;
+
+ --accent: #7a5c28;
+ --accent-hover: #9a7030;
+}
+
/* ─── Base ─────────────────────────────────────────────────────── */
html, body, #root {
height: 100%;