(null)
@@ -102,6 +137,7 @@ export function MarkdownEditor(): JSX.Element {
annPlugin,
themeCompartment.of(buildTheme(fontSize, isDark)),
fontSizeCompartment.of([]),
+ showInvisiblesCompartment.of(buildInvisiblesPlugin(false)),
EditorView.lineWrapping,
EditorView.updateListener.of((update) => {
if (update.docChanged) {
@@ -161,6 +197,11 @@ export function MarkdownEditor(): JSX.Element {
viewRef.current?.dispatch({ effects: themeCompartment.reconfigure(buildTheme(fontSize, theme === 'dark')) })
}, [theme, fontSize])
+ // Update show invisibles
+ useEffect(() => {
+ viewRef.current?.dispatch({ effects: showInvisiblesCompartment.reconfigure(buildInvisiblesPlugin(showInvisibles)) })
+ }, [showInvisibles])
+
if (!activeStoryId) {
return Select a story or create a new one
}
diff --git a/src/renderer/store/borgesStore.ts b/src/renderer/store/borgesStore.ts
index 3cece33..28947fd 100644
--- a/src/renderer/store/borgesStore.ts
+++ b/src/renderer/store/borgesStore.ts
@@ -72,6 +72,8 @@ interface BorgesState {
toggleTheme: () => void
fontSize: number
setFontSize: (size: number) => void
+ showInvisibles: boolean
+ toggleInvisibles: () => void
initPrefs: () => Promise
// Session
@@ -230,6 +232,8 @@ export const useBorgesStore = create((set, get) => ({
window.api.writeConfig({ fontSize: clamped })
set({ fontSize: clamped })
},
+ showInvisibles: false,
+ toggleInvisibles: () => set((s) => ({ showInvisibles: !s.showInvisibles })),
initPrefs: async () => {
const cfg = await window.api.readConfig()
const fontSize = Math.max(11, Math.min(24, cfg.fontSize ?? 15))
diff --git a/src/renderer/styles/app.css b/src/renderer/styles/app.css
index 99837e8..3211953 100644
--- a/src/renderer/styles/app.css
+++ b/src/renderer/styles/app.css
@@ -303,7 +303,8 @@ textarea { resize: vertical; }
.cm-editor.cm-focused { outline: none; }
.cm-scroller { font-family: 'Georgia', 'Times New Roman', serif; line-height: 1.8; }
.cm-content { max-width: 680px; margin: 0 auto; padding: 0 24px; }
-.cm-line { padding: 0; }
+.cm-line { padding: 0; margin-bottom: 0.75em; }
+.cm-line:last-child { margin-bottom: 0; }
.cm-cursor { border-left-color: var(--accent) !important; }
.cm-selectionBackground { background: rgba(200, 169, 110, 0.25) !important; }
.cm-focused .cm-selectionBackground { background: rgba(200, 169, 110, 0.35) !important; }
@@ -318,6 +319,12 @@ textarea { resize: vertical; }
}
.ann-highlight:hover { background: rgba(200, 169, 110, 0.28); }
+.cm-space-dot {
+ color: var(--text3);
+ pointer-events: none;
+ user-select: none;
+}
+
/* Dashboard */
.dashboard {
flex: 1;