Vault scanner now includes all files (not just .md). Each VaultEntry has a
fileKind field ("markdown", "text", or "binary") that controls how the
frontend handles it:
- Folder view shows all file kinds; other views (All Notes, type sections)
continue to show only markdown files
- Text files (.yml, .json, .txt, .py, etc.) open in the raw CodeMirror editor
- Binary files (.png, .jpg, .pdf, etc.) appear grayed out and are not clickable
- Non-markdown files use filename as title, skip frontmatter parsing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the multi-tab model with single-note navigation. One note is
open at a time; clicking any note (sidebar, wikilink, relationship)
replaces the current note in the editor. Back/Forward history still
works via Cmd+[/].
Removed: TabBar component, useClosedTabHistory, tab reorder/close/
reopen logic, Cmd+W/Cmd+Shift+T shortcuts, Close Tab and Reopen
Closed Tab menu items, tabLayout utility, and all related tests.
Simplified: useTabManagement (single-note), useAppNavigation (no tab
lookup), useKeyboardNavigation (note nav only), useNoteCreation (no
close-tab cleanup), useDeleteActions (deselect instead of close tab),
Editor (no TabBar render), Rust menu (removed 2 menu items).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
handleSelectNote skipped syncNoteTitle for tabs already open (early
return). Moved sync call into handleSelectNoteWithSync so it always
runs, even when switching to an existing tab via Cmd+P. Also removes
H1 fallback from extract_title — title now comes from frontmatter or
filename only, per the title/filename contract.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- handleSelectNote syncs title frontmatter before loading content
- handleSelectNoteWithSync reloads entry after open to update display title
- Added sync_note_title to mock handlers
- Fixed rapid-switching test to flush sync microtask
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Refactor useClosedTabHistory to store full VaultEntry (not stub) for reliable reopening
- Add data-tab-path attribute to TabItem for precise Playwright selectors
- Add 2 Playwright smoke tests: single close/reopen and empty-history no-op
- Update ARCHITECTURE.md and ABSTRACTIONS.md with closed tab history docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce useClosedTabHistory hook (LIFO stack, 20-entry cap, dedup)
and integrate it into useTabManagement so handleCloseTab records entries
and handleReopenClosedTab pops them to reopen at original position.
Co-Authored-By: Claude Opus 4.6 <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>
Verifies that searching "Writing" in Quick Open shows the exact title
match first, followed by prefix matches. Also adds Refactoring test
entries to mock data and demo vault.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handleSelectNote and handleReplaceActiveTab now check the in-memory
allContent cache before issuing a Tauri IPC call. Cache hits open the
tab synchronously (zero latency). Cache misses fall back to the disk
read and populate allContent via onContentLoaded so subsequent opens
of the same note are instant.
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>
Break up the monolithic useNoteActions hook (cc=37, 232 LoC, score 6.89) into:
- useTabManagement: owns tab state and all tab operations (score 9.53)
- mockFrontmatterHelpers: extracted and simplified YAML manipulation (score 9.09+)
- useNoteActions: now focused on note creation and frontmatter operations (score 9.22)
Key improvements:
- Extracted entryMatchesTarget() to reduce wikilink matching complexity
- Deduplicated replaceKeyInLines/removeKeyFromLines into processKeyInLines
- Converted buildNewEntry to use object param (was 5 positional args)
- Overall complexity reduced from cc=37 to cc=11 in useNoteActions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>