Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e47f145
docs: post-release sync for v1.19.0
Feb 23, 2026
2025831
docs: optimize CLAUDE.md (-36%, 744→475 lines)
Feb 23, 2026
06bde7e
docs: add orchestration plan for session timer removal
Feb 24, 2026
b6fae80
refactor: remove session timer, consolidate to Pomodoro
Feb 24, 2026
47d685d
chore: reduce default editor font size from 18px to 15px
Feb 24, 2026
b0bc526
docs: add brainstorm and spec for Quarto code chunk styling
Feb 24, 2026
ee8eab5
docs: update docs and remove orphaned CSS after session timer removal
Feb 24, 2026
e843b12
docs(spec): approve Quarto code chunk spec after review
Feb 24, 2026
6dc3a4a
feat: settings improvements — components, shortcuts registry, prefere…
Data-Wise Feb 24, 2026
8375189
docs: post-merge sync for PR #47 settings improvements
Feb 24, 2026
e9ccd64
docs: post-merge guides, refcard, and test summary updates for PR #47
Feb 24, 2026
1a37508
fix: remaining stale test count references (2,255 → 2,282)
Feb 24, 2026
4c56938
docs: update features guide and index for current settings tabs
Feb 24, 2026
615f3ca
fix: address PR #48 code review issues
Feb 24, 2026
59d4b83
chore: merge dev into feature branch, resolve CHANGELOG conflict
Feb 24, 2026
cb8cdea
Merge pull request #48 from Data-Wise/feature/remove-session-timer
Data-Wise Feb 24, 2026
52a58a1
docs: post-merge sync for PR #48 (session timer removal)
Feb 24, 2026
71e1a43
docs: update roadmap session timer entry to Pomodoro (done)
Feb 24, 2026
3660c00
chore: bump version to v1.20.0 for release
Feb 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions .STATUS
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
---
status: active
priority: P1
version: 1.19.0
version: 1.20.0
sprint: 37
started: 2026-01-08
updated: 2026-02-23
released: 2026-02-23
updated: 2026-02-24
released: 2026-02-24
editor: hybrid-markdown++
next_focus: Settings Infrastructure Improvements (feature/settings-improvements)
tests: 2255
unit_tests: 2255
next_focus: Fix 67 test file TypeScript errors
tests: 2280
unit_tests: 2280
e2e_tests: 109
test_file_errors: 67 (non-blocking, documented in docs/planning/TEST-FILE-TYPESCRIPT-ERRORS-2026-01-24.md)
tags:
Expand All @@ -26,10 +26,6 @@ tags:

## Current Focus (Sprint 37)

### In Progress

1. **Settings Infrastructure Improvements** (WIP) — Extract reusable SettingsToggle, shortcut registry, usePreferences hook, pre-commit ORCHESTRATE guard. Branch: `feature/settings-improvements`. Spec: `docs/specs/SPEC-settings-improvements-2026-02-23.md`. ~3.5h total.

### Next Up

1. **Fix 67 test file TypeScript errors** (~2.5h) — Non-blocking but noisy. Documented in `docs/planning/TEST-FILE-TYPESCRIPT-ERRORS-2026-01-24.md`
Expand All @@ -49,14 +45,30 @@ tags:

## Recently Completed

### Pomodoro Focus Timer (2026-02-23) — PR #45 merged to dev
### Session Timer Removal (2026-02-24) — PR #48

- Removed legacy session timer from breadcrumb bar (⏸/▶/↺ controls)
- Removed `sessionStartTime` prop chain from 5 components
- StatsPanel Duration card → Pomodoro count from `usePomodoroStore`
- Cleaned 4 localStorage keys and ~50 lines orphaned CSS
- Net: -95 lines, 2,280 tests (2 session-duration tests removed)

### Settings Infrastructure Improvements (2026-02-24) — PR #47

- Reusable `SettingsToggle` component with full accessibility
- `usePreferences` hook with cached state + event-based sync
- `SHORTCUTS` registry (25 shortcuts) with `matchesShortcut()` helper
- Migrated `SettingsModal.tsx` to `usePreferences` hook
- 27 new tests (2,282 total)

### v1.19.0 (2026-02-23) — Pomodoro Focus Timer (Released)

- Pomodoro timer in editor status bar (start/pause click, reset right-click)
- Zustand store with symmetric callbacks: `tick(onComplete, onBreakComplete)`
- Auto-save on work completion, gentle break toasts
- Focus Timer settings in General tab (5 new preferences)
- Auto-pin new projects to sidebar
- 62 new tests (2,255 total)
- 62 new tests (2,282 total)

### v1.18.0 (2026-02-22) — Sidebar Vault Expansion Fix + DexieError2 Fix

Expand Down Expand Up @@ -127,8 +139,8 @@ tags:

| Spec | Status | Target |
|------|--------|--------|
| Pomodoro Timer | Implemented (PR #45) | v1.19.0 |
| Settings Improvements | In Progress | v1.19.0 |
| Pomodoro Timer | Released | v1.19.0 |
| Settings Improvements | In Progress | v1.20.0 |
| Three-Tab Sidebar | Design Approved | v1.17.0 |
| Quarto Enhancements | Partially Implemented | v1.15+ |
| LaTeX Editor | Proposal | v2.0 |
Expand Down
11 changes: 11 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env sh

# Guard: Block ORCHESTRATE files on dev/main branches
if git diff --cached --name-only | grep -q '^ORCHESTRATE-'; then
branch=$(git branch --show-current)
if [ "$branch" = "dev" ] || [ "$branch" = "main" ]; then
echo "⚠️ ORCHESTRATE files should not be committed to $branch"
echo " Remove with: git rm ORCHESTRATE-*.md"
exit 1
fi
fi
184 changes: 184 additions & 0 deletions BRAINSTORM-quarto-code-chunks-2026-02-24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Brainstorm: VS Code-Style Quarto Code Chunks

> **Date:** 2026-02-24
> **Mode:** max | feat | save
> **Duration:** ~12 min (research + 2 agents)
> **Topic:** Implement VS Code Quarto-style code chunks with distinct background and code font

## Problem Statement

Scribe's code chunks (`\`\`\`{r}`, `\`\`\`{python}`) are nearly invisible. The current `rgba(0,0,0,0.04)` background blends into prose, making it hard to scan between text and code in long `.qmd` documents. VS Code's Quarto extension uses clear visual separation — distinct background color, monospace font, language indicators — that lets writers instantly identify code regions while editing.

## Current State (Scribe)

| Aspect | Current Implementation |
|--------|----------------------|
| **Background** | `rgba(0,0,0,0.04)` / `rgba(255,255,255,0.04)` — barely visible |
| **Font** | JetBrains Mono via CSS, hardcoded in `index.css` |
| **Detection** | CSS `:has(.tok-codeFence)` selectors (no ViewPlugin) |
| **Left border** | 2px solid accent color |
| **Theme integration** | `.dark` class override — not wired to theme CSS variables |
| **Settings** | No code font preference (only prose font is configurable) |
| **Chunk options** | `#| lines` styled via `:has(.tok-comment):has(.tok-monospace)` |
| **Language badge** | None |
| **Files** | `index.css:6231-6276`, `CodeMirrorEditor.tsx` (no dedicated plugin) |

## VS Code Quarto Reference

| Aspect | VS Code Implementation |
|--------|----------------------|
| **Background** | `#E1E1E166` light / `#40404066` dark — clearly visible |
| **Font** | Fixed-width from `--vscode-editor-font-family` |
| **Detection** | Markdown engine token parser via `background.ts` |
| **Decoration** | `TextEditorDecorationType` with `isWholeLine: true` |
| **CodeLens** | "Run Cell", "Run Next Cell", "Run Above" buttons above chunks |
| **Theme** | Uses `notebook.selectedCellBackground` / `notebook.cellEditorBackground` |
| **Config** | Background mode: default, theme-based, or off |

Sources:
- [Quarto VS Code Extension](https://marketplace.visualstudio.com/items?itemName=quarto.quarto)
- [Quarto HTML Code Blocks docs](https://quarto.org/docs/output-formats/html-code.html)
- [VS Code Notebook Editor](https://quarto.org/docs/tools/vscode/notebook.html)
- [quarto-dev/quarto GitHub: background.ts](https://github.com/quarto-dev/quarto/blob/main/apps/vscode/src/providers/background.ts)
- [quarto-dev/quarto GitHub: cell/codelens.ts](https://github.com/quarto-dev/quarto/blob/main/apps/vscode/src/providers/cell/codelens.ts)
- [quarto-dev/quarto GitHub: theme.ts](https://github.com/quarto-dev/quarto/blob/main/apps/vscode-editor/src/theme.ts)

## Quick Wins (< 30 min each)

1. **Bump background opacity** — Change `rgba(0,0,0,0.04)` to `rgba(0,0,0,0.08)` in CSS. Zero-risk, immediate improvement.
2. **Increase left border to 3px** — Thicker accent stripe improves scannability.
3. **Add top/bottom margin on fence lines** — 8-12px spacing creates visual "breathing room" around chunks.

## Medium Effort (1-2 hours each)

4. **Add `--nexus-code-bg` CSS variable** — Computed in `applyTheme()` from existing `bgTertiary` values. Auto-adapts to all 10 themes.
5. **Add `--code-font-family` CSS variable** — Separate code font from prose font, applied via `applyFontSettings()`.
6. **Create `CodeChunkDecorationPlugin`** — ViewPlugin using `Decoration.line()` pattern (identical to existing callout system at line 554-597 of CodeMirrorEditor.tsx).

## Long-term (Future sessions)

7. **Language badge widget** — Small `[R]` / `[PY]` pill on fence lines. Uses existing `WidgetType` pattern.
8. **Code font Settings UI** — Picker in Settings > Editor tab, filtered to mono fonts.
9. **Chunk option collapsing** — Fold `#|` lines when cursor isn't on them (like heading mark hiding).
10. **Code chunk line numbers** — Optional gutter numbers inside chunks only.

## Architecture Decision: ViewPlugin vs CSS `:has()`

**Decision: ViewPlugin for Quarto chunks, CSS `:has()` fallback for plain fences.**

| Approach | Pros | Cons |
|----------|------|------|
| CSS `:has()` only | Simple, no JS | Can't extend bg beyond text, no badge widgets, browser compat edge cases |
| ViewPlugin only | Full control, proven pattern in callouts | More code, need sort order discipline |
| **Hybrid (recommended)** | Best of both — ViewPlugin for Quarto, CSS fallback for `\`\`\`js` | Two code paths |

The hybrid approach matches how the codebase already works: callouts use `Decoration.line()` for rich treatment, while basic blockquotes use CSS.

## Color Strategy

**Approach: Derive `--nexus-code-bg` from `bgTertiary` in `applyTheme()`**

For dark themes: `rgba(bgTertiary, 0.45)` — subtle but clearly distinct from `bgPrimary`
For light themes: `rgba(bgTertiary, 0.5)` — visible tint without harsh contrast

This auto-adapts to all 10 themes + custom themes without per-theme configuration.

**Alternative considered:** `color-mix(in srgb, var(--nexus-bg-tertiary) 60%, var(--nexus-bg-primary) 40%)` — cleaner CSS but computed in CSS, not JS. Works in modern browsers but CSS `color-mix()` requires Chromium 111+ / Safari 16.2+.

## Font Strategy

| Element | Font | Size | Line Height |
|---------|------|------|-------------|
| Prose | User's choice (default: system sans, 15px) | `--editor-font-size` | 1.8 |
| Code content | User's choice from mono fonts (default: JetBrains Mono) | `calc(editor-size * 0.88)` → ~13px | 1.5 |
| Chunk options (`#|`) | Same as code, but smaller | `calc(editor-size * 0.82)` → ~12px | 1.5 |
| Fence lines | Same as code | Same as code | 1.5 |

The font size reduction (88%) plus line-height change (1.8→1.5) creates clear visual separation without being jarring.

## What NOT to Include

| VS Code Feature | Why Skip for Scribe |
|----------------|---------------------|
| Run Cell / CodeLens buttons | Scribe is for writing, not execution. VS Code handles running. |
| Output cells | Quarto renders outputs separately. No inline output. |
| Cell toolbar | Adds IDE complexity. Scribe is distraction-free. |
| Gutter line numbers in chunks | Adds visual noise. Maybe as future opt-in. |
| Drag handles | Not applicable to writing flow. |
| Cell execution status | Scribe doesn't execute code. |

## Agent Analysis Summary

### Frontend Architect Agent

Key findings:
- The existing `RichMarkdownPlugin` (line 440-658) is the exact pattern to follow
- `FencedCode` → `CodeInfo` syntax tree nodes provide language detection
- `Decoration.line()` requires `range(line.from)` not a range — critical detail
- Decorations MUST be sorted by `.from` position before `Decoration.set()`
- `createEditorTheme()` is the canonical place for decoration class styles
- `hexToRgb()` already exists at line 585 for color computation
- `--nexus-code-bg` must be a complete `rgba()` string (CSS can't apply alpha to a variable)

### UX Designer Agent

Key findings:
- Current `rgba(0,0,0,0.04)` is invisible — needs 4-8x increase
- `color-mix()` approach auto-adapts to all themes without JS
- Code font should be `--editor-font-size - 1px` (14px at default 15)
- Chunk options (`#|`) should be italic + slightly smaller for hierarchy
- Left border should increase from 2px→3px at 40% accent opacity
- Language badge: `[R]`/`[PY]`/`[JL]` pill, 11px uppercase, always visible at 70% opacity
- ADHD consideration: badge is "wayfinding anchor" for scanning — answers "what kind?" at a glance
- Avoid all IDE chrome (run buttons, toolbars, status indicators)

## Implementation Phases

### Phase 1: CSS Variables Foundation (themes.ts)
- Add `--nexus-code-bg` and `--nexus-code-border` in `applyTheme()`
- Add `codeFamily`/`codeSize` to `FontSettings`
- Add `--code-font-family` and `--code-font-size-ratio` in `applyFontSettings()`
- Add `'jetbrains-mono'` to `FONT_FAMILIES` registry

### Phase 2: ViewPlugin Core (CodeMirrorEditor.tsx)
- Add `LanguageBadgeWidget extends WidgetType`
- Add `CodeChunkDecorationPlugin` with `computeDecorations()`
- Register in extensions array

### Phase 3: Theme Styles (CodeMirrorEditor.tsx)
- Add `.cm-quarto-*` classes in `createEditorTheme()`
- Test across 4+ themes (dark + light)

### Phase 4: CSS Cleanup (index.css)
- Replace lines 6231-6276 with simplified plain-fence fallback
- Remove `.dark` overrides

### Phase 5: Settings UI (EditorSettingsTab.tsx)
- Add Code Font section with mono-filtered picker
- Add size ratio slider (0.75-1.0)

### Phase 6: Validation
- Cursor-on-fence behavior
- Theme switching with visible chunks
- Nested/adjacent chunks
- Full test suite

## Files Affected

| File | Changes |
|------|---------|
| `src/renderer/src/lib/themes.ts` | `FontSettings` interface, `DEFAULT_FONT_SETTINGS`, `FONT_FAMILIES`, `applyTheme()`, `applyFontSettings()` |
| `src/renderer/src/components/CodeMirrorEditor.tsx` | New `CodeChunkDecorationPlugin`, `LanguageBadgeWidget`, `createEditorTheme()` styles, extensions array |
| `src/renderer/src/index.css` | Replace lines 6231-6276 with fallback-only CSS |
| `src/renderer/src/components/Settings/EditorSettingsTab.tsx` | Add Code Font picker section |

## Recommended Path

> Start with Phase 1 (CSS variables) + Phase 4 (CSS cleanup) as a single commit. This alone makes code chunks visibly distinct across all themes with zero new JS. Then Phase 2+3 in a second commit for the ViewPlugin. Phase 5 (settings UI) can be a separate PR.

## Open Questions

1. Should `color-mix()` (CSS-only) or `rgba()` computation (JS in applyTheme) be used? The JS approach is more compatible but requires the `hexToRgb()` helper.
2. Should language badges be cursor-reveal (hide when editing fence line) like heading marks?
3. Should chunk option `#|` lines collapse when cursor isn't on them?
4. What about inline executable code (`\`{r} 1+1\``)? The VS Code extension styles these too.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [v1.20.0] - 2026-02-24 — Settings Infrastructure & Timer Cleanup

### Added

- **`SettingsToggle` component** — Reusable toggle switch with `role="switch"`, `aria-checked`, and `aria-label` accessibility attributes. Used by GeneralSettingsTab and EditorSettingsTab.
- **`usePreferences` hook** — Cached preferences via React state with `preferences-changed` event listener for cross-component sync. Provides `prefs`, `updatePref()`, and `togglePref()`.
- **`SHORTCUTS` registry** — Single source of truth for 25 keyboard shortcuts with `matchesShortcut(event, id)` helper for event matching. Replaces manual `e.metaKey && e.key` checks.

### Changed

- **StatsPanel Session section** — Duration card replaced with Pomodoro count card showing today's completed sessions from `usePomodoroStore`.
- **WritingProgress** — No longer displays session elapsed time; shows word delta, progress bar, and streak only.
- Migrated `SettingsModal.tsx` to use `usePreferences` hook (removed raw `loadPreferences` calls)

### Removed

- **Session timer** — Removed the legacy session timer from the breadcrumb bar (⏸/▶/↺ controls). Raw elapsed time persisted via localStorage causing confusing values like "2296:20" across restarts.
- **sessionStartTime prop chain** — Removed from App.tsx, EditorOrchestrator, HybridEditor, WritingProgress, and StatsPanel interfaces.
- **4 localStorage keys** — `sessionStart`, `timerPaused`, `pausedDuration`, `pauseStart`.
- **~50 lines of CSS** — Orphaned `.focus-timer`, `.timer-btn`, `.timer-value` styles.

---

## [v1.19.0] - 2026-02-23 — Pomodoro Focus Timer

### Added
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
> **ADHD-Friendly Distraction-Free Writer**

[![Status](https://img.shields.io/badge/status-active-brightgreen)]()
[![Version](https://img.shields.io/badge/version-1.19.0-blue)]()
[![Version](https://img.shields.io/badge/version-1.20.0-blue)]()
[![Progress](https://img.shields.io/badge/progress-100%25-brightgreen)]()
[![Tests](https://img.shields.io/badge/tests-2255%20passing-brightgreen)]()
[![Tests](https://img.shields.io/badge/tests-2280%20passing-brightgreen)]()
[![Tauri](https://img.shields.io/badge/tauri-2-blue)]()
[![React](https://img.shields.io/badge/react-18-blue)]()

Expand Down Expand Up @@ -240,7 +240,7 @@ scribe/

## Test Coverage

**2,255 tests passing** across test files:
**2,280 tests passing** across test files:

| Test File | Tests |
|-----------|-------|
Expand Down
44 changes: 44 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,45 @@ graph TD

---

## Preferences System

The preferences system provides lightweight, event-driven state management
for user settings that persist to `localStorage`. It operates alongside
the Zustand store but uses a simpler read/write model suited to key-value
preferences.

```mermaid
flowchart LR
LS[localStorage] -->|loadPreferences| HP[usePreferences hook]
HP -->|React state| C[Components]
UP[updatePreferences / togglePref] -->|write-through| LS
UP -->|dispatch| E["preferences-changed event"]
E -->|listener| HP
```

### Key Modules

| Module | File | Purpose |
|--------|------|---------|
| `preferences.ts` | `src/renderer/src/lib/preferences.ts` | Load, save, merge preferences to localStorage |
| `usePreferences()` | `src/renderer/src/hooks/usePreferences.ts` | React hook — cached reads, event-based sync across components |
| `shortcuts.ts` | `src/renderer/src/lib/shortcuts.ts` | `SHORTCUTS` registry — single source of truth for all 27 keyboard shortcuts |
| `matchesShortcut()` | `src/renderer/src/lib/shortcuts.ts` | Registry-based `KeyboardEvent` matching (cmd/shift/alt modifiers) |
| `SettingsToggle` | `src/renderer/src/components/Settings/SettingsToggle.tsx` | Reusable toggle switch component for boolean settings |

### How It Works

1. **`loadPreferences()`** reads from `localStorage`, merges with defaults so new fields get sensible values on upgrade.
2. **`usePreferences()`** calls `loadPreferences()` once on mount and caches the result in React state. It listens for the `preferences-changed` custom event to stay in sync with other components.
3. **`updatePreferences()` / `togglePref()`** write-through to `localStorage` and dispatch `preferences-changed`, triggering all mounted hooks to re-read.
4. **`SHORTCUTS`** defines every keyboard shortcut with `key`, `mod`, and `label`. UI components reference `SHORTCUTS.xxx.label` for display; handlers call `matchesShortcut(event, shortcutId)` instead of manual key checks.

### Pre-commit ORCHESTRATE Guard

A husky `pre-commit` hook prevents accidental commits of `ORCHESTRATE-*.md` planning files to protected branches. These files belong on feature branches during development and are cleaned up on merge.

---

## Data Flow

```mermaid
Expand Down Expand Up @@ -206,8 +245,13 @@ scribe/
│ │ ├── SimpleTagAutocomplete.tsx
│ │ └── CitationAutocomplete.tsx
│ │
│ ├── hooks/
│ │ └── usePreferences.ts # Cached prefs hook (event sync)
│ │
│ ├── lib/
│ │ ├── api.ts # Tauri IPC wrapper
│ │ ├── preferences.ts # localStorage preferences R/W
│ │ ├── shortcuts.ts # SHORTCUTS registry + matcher
│ │ ├── themes.ts # Theme definitions
│ │ └── mathjax.ts # KaTeX processing
│ │
Expand Down
Loading