Commit Graph

30 Commits

Author SHA1 Message Date
lucaronin
af94280e4d refactor: decompose NoteList into focused components and extract helpers
Break up NoteListInner (cc=61, 331 LoC, score 6.94) into:
- NoteItem: extracted item rendering component (score 9.63)
- SortDropdown: extracted into own file (score 9.68)
- noteListHelpers.ts: all utility functions (score 10.0)
  - GroupBuilder class replaces 5-arg addResolvedGroup
  - filterEntries split into filterByKind/filterByFilterType
- PinnedCard: unified entity/type document cards
- RelationshipGroupSection: extracted group rendering
- NoteList.tsx: orchestration only (score 8.79)

NoteListInner reduced from cc=61 to cc=23, 331 → 105 LoC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:18:05 +01:00
lucaronin
2692ca4a8b refactor: extract useTabManagement hook and mock frontmatter helpers from useNoteActions
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>
2026-02-22 10:11:52 +01:00
lucaronin
df3e4a787e feat: git history — clickable commit hashes with diff view 2026-02-22 10:02:35 +01:00
lucaronin
d23ce5a0b5 feat: clickable commit hashes in git history panel open diff view
- Add get_file_diff_at_commit Rust command to show diff at a specific commit
- Make shortHash in GitHistoryPanel a clickable button that opens DiffView
- Show author name below commit message (small, muted)
- Remove disabled "View all revisions" button
- Wire onLoadDiffAtCommit through Editor → Inspector → App.tsx
- Add mock handler for get_file_diff_at_commit in browser mode
- Fix pre-existing missing `order` field on trashed mock entries
- Update Inspector tests for new behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 22:27:18 +01:00
lucaronin
4b75eb46b6 feat: archive button in breadcrumbs bar + cmd+e shortcut
Add archive/unarchive toggle button to the BreadcrumbBar (Archive icon
for normal notes, ArrowUUpLeft icon for archived notes). Add cmd+e
keyboard shortcut to toggle archive state of the active note.

Refactored useAppKeyboard to use action map pattern (reduces cyclomatic
complexity) and extracted BreadcrumbActions from BreadcrumbBar to split
rendering complexity across two functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 18:45:25 +01:00
lucaronin
cc1631c368 feat: draggable section groups in sidebar 2026-02-21 18:36:28 +01:00
lucaronin
66754c2dcd feat: draggable tabs with localStorage persistence 2026-02-21 18:35:13 +01:00
lucaronin
d475143e8a feat: breadcrumb trash/restore buttons and cmd+del shortcut
- Added trash icon button in breadcrumb bar for non-trashed notes
- Added restore (arrow counter-clockwise) button for trashed notes
- Trash button sets trashed=true and trashed_at in frontmatter
- Restore button removes trashed/trashed_at from frontmatter
- Added Cmd+Delete keyboard shortcut to trash active note
- Wired handlers through Editor -> App with vault entry updates
- Toast notifications for trash/restore actions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:37:15 +01:00
lucaronin
1dfbbb8a9e feat: add order property to VaultEntry and install @dnd-kit
- Add `order: number | null` to VaultEntry (TS) and VaultEntry (Rust)
- Add order to Frontmatter struct and SKIP_KEYS in vault.rs
- Update all mock Type documents with order values (0-10)
- Add order: null to all non-Type mock entries and test fixtures
- Install @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:27:19 +01:00
lucaronin
d8283184c1 feat: draggable tabs with localStorage persistence
- TabBar: HTML5 drag-and-drop on tab elements (grab/grabbing cursor,
  0.5 opacity on dragged tab, 2px primary-color drop indicator)
- useNoteActions: handleReorderTabs splices tab array, saves order
  to localStorage under "laputa-tab-order" key
- Tab order auto-persists on every change; restored on mount
- Wired through Editor → App props chain

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:24:01 +01:00
lucaronin
8121bbf468 test: add tests for trash notes filtering and UI
- Added filterEntries tests: trash excluded from all/section/topic/archived,
  trash filter returns only trashed entries
- Added NoteList render tests: trash header, TRASHED badge, 30-day warning
  banner, empty trash state
- Updated all test files with trashed/trashedAt fields on VaultEntry mocks
- Updated useNoteActions to include trashed/trashedAt on new entries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:56:48 +01:00
lucaronin
311c5e434b feat: archive notes — filter sidebar, hide archived, relationship indicators 2026-02-21 16:44:09 +01:00
lucaronin
07e730f172 feat: customize which type sections are shown in sidebar 2026-02-21 16:41:34 +01:00
lucaronin
b73bda1aa9 feat: customize which type sections are shown in sidebar
Adds a "Customize sections" button above section groups in the sidebar.
Clicking it opens a popover with per-type toggle switches. Hidden sections
disappear from the sidebar entirely but notes remain accessible via
All Notes and search. Visibility state is persisted in localStorage.

- New useSectionVisibility hook: manages hidden sections set in localStorage
- Sidebar: "Customize sections" button + popover with toggle UI
- Outside-click closes the popover
- allSectionGroups (built-in + custom) filtered by visibility before render

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:37:00 +01:00
lucaronin
a28e4528bd fix: add archived field to all VaultEntry test fixtures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:36:18 +01:00
lucaronin
b1e15dd5ea feat: implement icon & color customization for types
- Add TypeCustomizePopover component with color swatches (6 accent colors)
  and icon grid (35 curated Phosphor icons)
- Add right-click context menu on sidebar section group headers with
  "Customize icon & color…" option
- Sidebar renders custom icons/colors from type entry frontmatter
- NoteList uses custom icons/colors for type badges and pinned cards
- Wire up onCustomizeType in App.tsx to update type frontmatter
- Add updateEntry to useVaultLoader for instant in-memory updates
- Add --accent-orange-light CSS variable
- typeColors utility now accepts optional custom color key overrides

Product decision: Built-in types can also be customized (override their
defaults), not just custom types. The picker is a simple popover that
appears after right-click → "Customize icon & color…".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:27:33 +01:00
lucaronin
f36cfd1808 feat: add icon and color fields to VaultEntry
- Add icon (string|null) and color (string|null) to VaultEntry interface
- Update Rust VaultEntry struct and frontmatter parsing to read icon/color
- Add icon/color to SKIP_KEYS so they don't appear as relationships
- Set mock data: Recipe type → cooking-pot/orange, Book type → book-open/green
- Update all test files with the new required fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:23:10 +01:00
lucaronin
827ec42d6c feat: add keyboard navigation between tabs and notes
- Tab navigation: Cmd+Option+Left/Right (Tauri), Cmd+Shift+Left/Right (browser)
- Note list navigation: Cmd+Option+Up/Down moves through visible notes
- Navigating notes replaces the current tab content (no new tab opened)
- Wraps around at list boundaries
- New useKeyboardNavigation hook detects Tauri vs browser environment
- Extracted loadNoteContent and replaceTabWithEntry helpers to reduce
  complexity in useNoteActions
- Exported filterEntries, sortByModified, buildRelationshipGroups from
  NoteList for reuse in keyboard navigation

Note: useNoteActions (30→31 CC) and App (143→153 LOC) show minimal
degradation on pre-existing code health issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 10:50:50 +01:00
lucaronin
5f2a6495db feat: AI chat panel 2026-02-21 10:38:41 +01:00
lucaronin
170de2a7e0 feat: implement create new type feature
Core implementation:
- CreateTypeDialog: simple dialog with name field for creating new types
- handleCreateType in useNoteActions: creates Type documents in type/ folder
- Dynamic sidebar sections: custom types (Recipe, Book, etc.) appear as new
  sidebar sections after built-in ones, each with a + button for instances
- Updated CreateNoteDialog: accepts custom types, shows them with blue accent
- handleCreateNote now supports custom types (folder = lowercased type name)

Product decisions:
- The + on Types section opens CreateTypeDialog (not CreateNoteDialog)
- Custom type sections use FileText icon and blue accent color by default
- Section labels are pluralized (e.g., "Recipes", "Books")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 09:41:46 +01:00
lucaronin
7d235d723f feat(ai-chat): WebSocket bridge for MCP vault ops
Add WebSocket bridge connecting MCP server tools to the frontend:
- mcp-server/ws-bridge.js: WebSocket server exposing vault tools
  (read_note, create_note, search_notes, append_to_note)
- src/hooks/useMcpBridge.ts: React hook for typed tool invocations
  with lazy connection, request/response correlation, timeouts
- Vite MCP bridge info endpoint (/api/mcp/info)

Protocol: client sends {id, tool, args}, server responds {id, result}
Default port: 9710 (configurable via WS_PORT env var)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:59:00 +01:00
lucaronin
f4ca64f229 feat(ai-chat): context picker + Anthropic API
Rewrite AIChatPanel with:
- Context picker: current note auto-added, search to add more notes,
  removable context pills, token estimation badge
- Real Anthropic API integration via Vite dev server proxy (SSE streaming)
- API key stored in localStorage, configurable via dialog
- Model selector: Haiku 3.5, Sonnet 4, Opus 4
- Mock fallback when no API key is configured
- Extracted useAIChat hook and ai-chat utilities for clean separation

Decision: Using Vite middleware proxy for dev mode to avoid CORS issues
with direct browser-to-Anthropic calls. Phase 2 will add Rust backend.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:52:56 +01:00
lucaronin
238edaa6a9 refactor: extract useAppKeyboard hook from App.tsx
Moves global keyboard shortcut handling into a dedicated hook.
App.tsx now scores 10.0 code health.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 19:59:05 +01:00
lucaronin
663f7b199b feat: add vault API middleware for browser testing with real vault files
Add a Vite dev server middleware plugin that serves vault data over HTTP,
allowing the browser version of the app to read real markdown files instead
of hardcoded mock data. The mock layer now checks for API availability at
load time and falls back to hardcoded data when the API is unavailable.

- GET /api/vault/ping — health check
- GET /api/vault/list?path=<dir> — scan dir, parse frontmatter → VaultEntry[]
- GET /api/vault/content?path=<file> — raw file content
- GET /api/vault/all-content?path=<dir> — all .md files content map
- gray-matter added as dev dependency for frontmatter parsing
- useVaultLoader now passes vaultPath to mock invoke calls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 10:39:45 +01:00
lucaronin
7da76688d2 feat: use generic relationships map in NoteList context view
Updates buildRelationshipGroups to use the new relationships map from
VaultEntry instead of only belongsTo/relatedTo. Now shows Has, Topics,
and all other wikilink-containing frontmatter fields as groups. Group
order: Has, Children, Events, Topics, other fields alphabetically,
Referenced By, Backlinks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 19:11:01 +01:00
lucaronin
b239de3719 fix: prevent crash when opening notes
Move setActiveTabPath after tab content is loaded to prevent Editor's
useEffect from firing before the tab exists in the tabs array. Add
try/catch around editor.replaceBlocks for defensive error handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:52:10 +01:00
lucaronin
829cd2ad95 feat: add vault switcher in status bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:45:31 +01:00
lucaronin
0714184e3c perf: keep tab editors mounted for instant switching (Obsidian pattern)
Instead of unmounting/remounting BlockNoteTab on every tab switch
(via key={activeTabPath}), render all open tabs simultaneously and
toggle visibility with CSS display:none/block. This eliminates
editor recreation and markdown re-parsing on switch. Also adds a
loading skeleton for new tabs and uses a ref for tabs to avoid
stale closures in handleSelectNote.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:32:57 +01:00
lucaronin
47deb6f3b7 refactor: extract useVaultLoader and useNoteActions hooks from App.tsx 2026-02-17 12:10:21 +01:00
lucaronin
405d5f39fc feat: comprehensive theme.json config with live hot-reload for editor styling 2026-02-16 08:04:06 +01:00