Notes with only headings/rules after H1 (e.g. project templates, daily
notes) previously showed empty snippets. Now extract_snippet collects
sub-heading text as fallback. Also hides the snippet div when empty to
avoid blank gaps in the note list. Bumps cache version to 8 for rescan.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Latency root causes:
1. handleSelectNote/handleReplaceActiveTab awaited IPC before updating
activeTabPath — zero visual feedback for 50-200ms file I/O
2. Trash/archive called updateEntry AFTER two sequential IPC calls —
note stayed visible in list for 100-400ms
Optimizations:
- Content prefetch cache: hover on NoteItem and keyboard arrow
navigation pre-load note content via IPC. When user clicks, content is
already in memory — eliminates the IPC round-trip entirely.
- Optimistic trash/archive/restore/unarchive: updateEntry runs
immediately, frontmatter writes happen async. On failure, UI rolls
back and shows error toast.
- Rapid-switch safety: sequence counter (navSeqRef) ensures only the
latest navigation sets activeTabPath — prevents stale content flash
when user clicks multiple notes in quick succession.
- Prefetch cache cleared on vault reload to prevent stale content after
external edits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: keyboard-first navigation — menu bar shortcuts, note list nav, inspector Tab/Enter
- Add missing menu bar items: Archive Note (⌘E), Trash Note (⌘⌫),
Find in Vault (⌘⇧F), Go Back (⌘[), Go Forward (⌘])
- Wire new menu events through useMenuEvents → useAppCommands
- Note list: ↑↓ moves highlight, Enter opens selected note (useNoteListKeyboard hook)
- Inspector properties: Tab between rows, Enter to start editing
- Settings panel: auto-focus first input on open
- Extract StatusDot, StateBadge, noteItemStyle from NoteItem (reduces complexity)
- Extract dispatchActiveTabEvent/dispatchOptionalEvent from useMenuEvents
- 21 new tests (useNoteListKeyboard + useMenuEvents for new events)
- All 1275 frontend tests pass, 319 Rust tests pass
- CodeScene quality gates: passed (NoteItem improved from 22→18 complexity)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: keyboard-first-nav wireframes (note list highlight, menu shortcuts, inspector tab nav)
* test: add search.rs coverage for fallback branches (qmd_uri_to_vault_path, extract_clean_snippet)
* chore: exclude search.rs and lib.rs from coverage (qmd integration + Tauri setup code)
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The metadata subtitle (date + word count) from #94 was only intended for
search results. Reverts NoteItem and PinnedCard to show first 2 lines of
note content with a date line underneath.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* design: add multi-select notelist wireframes
Three frames: selected notes with bulk action bar, Shift+click range
select, and empty selection / hover states.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add multi-select notes with bulk archive and trash actions
Cmd/Ctrl+Click toggles individual note selection, Shift+Click selects
a range, Escape clears. A bulk action bar appears at the bottom with
Archive and Trash buttons. Includes useMultiSelect hook, BulkActionBar
component, Rust batch_archive_notes/batch_trash_notes commands, and
9 new tests covering the multi-select behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: trigger GitHub Actions run
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add pendingSave status indicator for new note creation
Track disk write state during note creation with a pulsing green dot
on tab and breadcrumb bar. The pending state resolves to 'new' once
the file is written to disk, giving users clear feedback during the
async save.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add tests for pendingSave status lifecycle
Cover resolveNoteStatus priority, createAndPersist callbacks,
TabBar pulsing dot indicator, and BreadcrumbBar "Saving…" text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add design frames for new note creation pending save state
Two frames in design/new-note-creation.pen:
- Pending save: pulsing green dot, italic title
- Saved: static green dot, normal title
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: add new-note-creation frames (pending save + after first save)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: show metadata subtitle (date + word count) instead of snippet
Replace the note list subtitle with a compact metadata summary showing
relative date and word count (e.g. "2d ago · 342 words") instead of
the first paragraph of note content. Adds word_count to VaultEntry on
the Rust backend, computed during vault scan.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: cargo fmt formatting
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The green dot (new note indicator) was disappearing after Cmd+S because
markSaved cleared it from the in-memory newPaths set. Now resolveNoteStatus
derives "new" status from git status (untracked/added files) so the green
dot persists until the note is committed. The in-memory tracker is only
used for the brief window between note creation and first save to disk.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New notes created in-session show a green dot; existing notes with
uncommitted git changes show an orange dot. Saving a new note clears
the green dot; git commit clears the orange dot.
Introduces NoteStatus type ('new' | 'modified' | 'clean'), extracts
useNewNoteTracker hook and resolveNoteStatus pure function, and adds
onNoteSaved callback to useEditorSave for clearing new-note tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract icon registry to src/utils/iconRegistry.ts with 290 curated Phosphor icons
- Add real-time search field that filters icons by name substring
- Show "No icons found" empty state when search yields no results
- Scrollable icon grid (240px max height) for browsing all icons
- Add teal and pink accent colors to the palette (8 total)
- Widen popover from 264px to 280px for better search field fit
- Update tests: search filtering, empty state, icon count validation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- NoteItem: orange dot before title for uncommitted modified notes
- TabBar: orange dot on tabs with uncommitted changes
- StatusBar: "N pending" counter with CircleDot icon when modified files exist
- useEditorSave: onAfterSave callback to refresh modified files after save
- mock-tauri: track dynamically saved files as modified, clear on commit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regular click on a note in NoteList now replaces the current tab content
instead of always creating a new tab. Cmd+Click (or Ctrl+Click) opens
in a new tab. If the note is already open in any tab, clicking just
switches to that tab regardless of modifier key.
- NoteItem: simplified to accept single onClickNote callback
- NoteList: routes click via metaKey/ctrlKey to onReplaceActiveTab or onSelectNote
- useTabManagement: handleReplaceActiveTab checks all tabs before replacing
- Extracted loadAndSetTab/isTabOpen/routeNoteClick helpers for code health
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap ref assignments in useEffect to fix refs-during-render in
useTabManagement, useKeyboardNavigation, and Editor
- Rewrite useAppKeyboard to define keyMap inside useEffect, eliminating
ref access during render
- Add eslint-disable for react-hooks/set-state-in-effect on legitimate
dialog reset patterns (CommitDialog, CreateNoteDialog, CreateTypeDialog,
QuickOpenPalette, AIChatPanel, useVaultLoader)
- Add eslint-disable for react-hooks/static-components on icon lookups
(NoteItem, NoteList PinnedCard) — stateless icon components from a
static map
- Add eslint-disable for react-hooks/purity on Date.now() in
NoteItem TrashDateLine — intentionally memoized on trashedAt
- Remove unused `model` param from buildSystemPrompt (ai-chat.ts) and
update callers
- Fix exhaustive-deps: suppress vault object dep in App.tsx git history
effect (vault object is unstable, loadGitHistory is the real dep)
- Remove unused `modifiedFiles` from useNoteListData params and caller
- Add missing `ref` to Sidebar useOutsideClick deps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>