Commit Graph

232 Commits

Author SHA1 Message Date
Luca Rossi
25e03ee2d6 Merge pull request #13 from refactoringhq/task/vault-from-github
feat: vault from GitHub — create or clone a vault from a GitHub repo
2026-02-23 08:35:10 +01:00
lucaronin
077330ec18 fix: resolve pre-existing TS errors in wikilinks.test.ts
Added AnyBlock type alias to cast injectWikilinks() return type in tests.
The function returns unknown[] but tests access .content, .props, .text
properties — this was already broken before this branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 08:34:14 +01:00
lucaronin
5fa1ac09f5 fix: remove unused GithubRepo import in mock-tauri.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 08:34:14 +01:00
lucaronin
a4bdc359ce fix: sync in-memory entries after property/rename changes
Two propagation gaps fixed:

1. Property changes (type, status, color, etc.) now immediately sync to
   the entries state via frontmatterToEntryPatch(), so sidebar, note list,
   and relations panel reflect updates without restart.

2. After renaming a note, all other open tabs reload their content from
   disk, picking up updated wikilinks immediately.

Design decisions:
- Used key-mapping approach (frontmatterToEntryPatch) instead of a new
  parse_md_file Tauri command — simpler, works in both Tauri and mock
  modes, covers all VaultEntry fields.
- Converted useNoteActions to config object to avoid excess arguments.
- Extracted findWikilinkTarget, reloadTabsAfterRename, renameToastMessage
  as standalone functions to reduce hook complexity (cc 10→9).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 08:34:14 +01:00
lucaronin
17c145b865 test: add GitHubVaultModal component tests
12 tests covering:
- Renders nothing when closed
- Shows "connect account" prompt without token
- Opens settings from no-token state
- Shows clone/create tabs with token
- Loads and displays repo list from mock
- Filters repos by search term
- Selects repo and auto-fills clone path
- Disables clone button without selection
- Calls clone_repo and onVaultCloned on successful clone
- Create tab trigger is visible and clickable
- Shows error message on clone failure
- Shows Private/Public badges on repos

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 08:34:14 +01:00
lucaronin
861235981c feat: GitHub vault modal with clone/create flows
New GitHubVaultModal component with two tabs:
- Clone Existing: search/browse user's repos, select one, choose
  local path, clone via HTTPS+token
- Create New: enter repo name, toggle private/public, create via
  GitHub API then clone locally

Integration:
- "Connect GitHub repo" option in vault switcher menu
- GitHub token field added to Settings panel
- Cloned vaults auto-added to vault list and opened
- Mock handlers for github_list_repos, github_create_repo, clone_repo
- All existing tests updated for new github_token field (386 pass)

Product decision: GitHub token stored in settings rather than OAuth
flow — simpler first version, works with personal access tokens.
Users can upgrade to OAuth later.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 08:34:14 +01:00
lucaronin
6e4119c28b feat: add Rust backend for GitHub vault operations
New github.rs module with three commands:
- github_list_repos: lists user's repos via GitHub API (paginated)
- github_create_repo: creates a new repo with auto_init
- clone_repo: git clone with HTTPS+token auth, configures remote

Also extends Settings with github_token field (Rust + TypeScript),
and adds GithubRepo type to shared types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 08:34:14 +01:00
lucaronin
8f5bd68b2e fix: add missing useMemo import in useAppKeyboard.ts 2026-02-22 17:16:20 +01:00
lucaronin
f843b3b640 feat: settings panel — API key management + local config storage 2026-02-22 16:02:30 +01:00
lucaronin
659ca5990f fix: resolve all ESLint errors, enforce lint in CI 2026-02-22 14:31:02 +01:00
lucaronin
728a111f14 fix: resolve TypeScript build errors from any→unknown migration
- Editor.tsx: use targeted eslint-disable for BlockNote block arrays
  (PartialBlock generic type is extremely complex to reference)
- Editor.tsx: cast through unknown for tryParseMarkdownToBlocks result
  which may be sync or async
- useMcpBridge.ts: cast Promise resolve to (value: unknown) => void
- mock-tauri.ts: cast args.path to string for encodeURIComponent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 14:10:42 +01:00
lucaronin
8cb382e3a3 fix: resolve React hooks/compiler ESLint errors
- 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>
2026-02-22 14:06:51 +01:00
lucaronin
50a766504d test: settings panel and useSettings hook tests
- 14 SettingsPanel component tests: render, save, clear, keyboard
  shortcuts, backdrop close, field population, key trimming
- 5 useSettings hook tests: load, save, error handling
- Updated App.test.tsx mocks for settings commands and ai-chat

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:42:20 +01:00
lucaronin
8b67ae53d4 feat: settings panel UI with API key management
- SettingsPanel modal component with masked key fields + reveal/clear
- useSettings hook reads/writes config via Tauri invoke
- Mock handlers for get_settings/save_settings in mock-tauri
- Settings type added to types.ts
- StatusBar gear icon opens settings (was disabled placeholder)
- Cmd+, keyboard shortcut opens settings
- Anthropic key synced to localStorage for AIChatPanel compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:38:18 +01:00
lucaronin
e5d96f97ec fix: suppress react-refresh/only-export-components for valid patterns
Co-located utility exports (constants, helper functions, variant
definitions) alongside their component files. These don't affect
Fast Refresh behavior in practice — targeted eslint-disable comments
explain each case:

- DynamicPropertiesPanel: containsWikilinks, RELATIONSHIP_KEYS
- NoteList: re-exported sort/filter utilities
- NoteItem: getTypeIcon utility
- SidebarParts: isSelectionActive utility
- TypeCustomizePopover: ICON_OPTIONS, resolveIcon
- badge/button/tabs: shadcn/ui variant export pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:11:38 +01:00
lucaronin
8e49af2c0e fix: replace no-explicit-any with proper types
- Test mocks: use { children?: React.ReactNode } and Record<string, unknown>
- Editor.tsx: use unknown[] for BlockNote block arrays
- wikilinks.ts: add BlockLike/InlineItem interfaces for block processing
- useMcpBridge.ts: use unknown for resolve/reject and Record<string, unknown>
- ai-chat.ts: use unknown catch + instanceof Error check
- mock-tauri.ts: type messages array, use Record<string, unknown> for args
  (keep one targeted eslint-disable for heterogeneous handler map)
- vite.config.ts: use http.IncomingMessage/ServerResponse, typed messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:10:26 +01:00
lucaronin
a77d5ff451 fix: simple ESLint errors — regex, unused vars, unused expressions
- eslint.config.js: ignore coverage/ directory (generated files)
- frontmatter.ts: no-regex-spaces — use {2} instead of literal spaces
- wikilinks.ts: no-useless-escape — remove unnecessary \[ escape
- ai-chat.ts: remove unused _model param from getContextLimit
- noteListHelpers.ts: remove unused _modifiedFiles param from filterEntries
- NoteList.tsx: replace ternary expression statement with if/else
- useTabManagement.ts: remove stale eslint-disable-next-line comment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:08:16 +01:00
lucaronin
c55ffad4b7 feat: frontend test coverage 47% → 86% — 362 tests across 17 new test files 2026-02-22 13:02:56 +01:00
lucaronin
ee4faa1874 feat: border between macOS title bar and sidebar content 2026-02-22 12:31:51 +01:00
lucaronin
679e1e2372 feat: OTA updater plugin + GitHub Releases release pipeline 2026-02-22 12:31:42 +01:00
lucaronin
4d0840c6c6 feat: add border between macOS title bar and sidebar content
The macOS window frame (transparent title bar, 38px) and the sidebar
share the same background color (#F7F6F3), making them visually
indistinguishable. Replace the sidebar's paddingTop: 38 with a
dedicated spacer div that has a bottom border (1px solid var(--border)),
matching the border style used between all other panels. The spacer
also serves as a drag region for window movement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:11:39 +01:00
lucaronin
190b7d0075 feat: add OTA updater plugin with startup update check
- Install @tauri-apps/plugin-updater + plugin-process (npm + cargo)
- Configure tauri.conf.json: updater endpoint pointing to GitHub Releases,
  signing pubkey, createUpdaterArtifacts enabled
- Register updater + process plugins in Rust (desktop-only, #[cfg(desktop)])
- Add updater:default + process:default capabilities
- Add useUpdater hook: checks for updates 3s after startup, shows native
  confirm dialog, downloads+installs+relaunches on accept
- Silently catches errors so update failures never block the app
- Add comprehensive tests for the useUpdater hook (5 test cases)

Product decision: Using window.confirm() for the update dialog rather than
a custom React modal. This keeps the implementation simple and the native
dialog is appropriate for a system-level action like app restart. Can be
upgraded to a custom UI later if desired.

Private key generated at ~/.tauri/laputa.key — NOT committed.
For CI: set TAURI_SIGNING_PRIVATE_KEY + TAURI_SIGNING_PRIVATE_KEY_PASSWORD
as GitHub Secrets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:10:24 +01:00
lucaronin
f64d941b0e feat: rename note by double-clicking its tab — inline edit, updates filename + wiki-links
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:10:17 +01:00
lucaronin
e1cdd86ab2 test: add component tests — StatusBar, CommitDialog, DiffView, QuickOpenPalette, ResizeHandle, CreateNoteDialog, EditableValue, TypeCustomizePopover, DynamicPropertiesPanel, InspectorPanels
251 tests covering:
- StatusBar: note count, vault menu interactions
- CommitDialog: file count badge, submit via click/Cmd+Enter, validation
- DiffView: line rendering, color coding, line numbers
- QuickOpenPalette: search, sorting, fuzzy filtering, keyboard navigation
- ResizeHandle: drag with rAF batching, delta accumulation, cursor reset
- CreateNoteDialog: title input, submit, validation, defaultType
- EditableValue: view/edit modes, Enter/Escape/blur, TagPillList CRUD
- TypeCustomizePopover: resolveIcon, color/icon selection
- DynamicPropertiesPanel: properties, status pills, boolean toggle, tags,
  add property form, value coercion, delete
- InspectorPanels: relationships, backlinks, git history, navigation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:02:44 +01:00
lucaronin
63c3bc3b1f test: add wikilinks.ts unit tests — preProcess, inject, splitFrontmatter, countWords
22 tests covering:
- preProcessWikilinks: single/multiple/pipe alias/nested wikilinks
- injectWikilinks: text expansion, nested children, no-content blocks
- splitFrontmatter: with/without frontmatter, unclosed frontmatter
- countWords: with frontmatter, markdown stripping, empty/whitespace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:02:29 +01:00
lucaronin
a36bcd6d43 test: add unit tests for hooks — useNoteActions, useEntryActions, useTabManagement, useVaultLoader, useKeyboardNavigation, mockFrontmatterHelpers
89 tests covering:
- useNoteActions: slugify, buildNewEntry, entryMatchesTarget, buildNoteContent,
  resolveNewNote/Type, createNote, createType, navigateWikilink, frontmatter ops
- useEntryActions: trash/restore, archive/unarchive, customizeType, reorderSections
- useTabManagement: tab selection, close, switch, reorder, replace, localStorage
- useVaultLoader: vault loading, modified files, addEntry, updateContent,
  updateEntry, git history, diff, commitAndPush
- useKeyboardNavigation: Cmd+Shift+Arrow tab switching, Cmd+Alt+Arrow note nav
- mockFrontmatterHelpers: updateMockFrontmatter, deleteMockFrontmatterProperty

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:02:19 +01:00
lucaronin
c67ba46062 refactor: export pure functions from useNoteActions + update coverage config
Export buildNewEntry, slugify, entryMatchesTarget, buildNoteContent,
resolveNewNote, resolveNewType as public functions for direct unit testing.

Add coverage exclusions for untestable files: shadcn/ui primitives,
AI modules (useAIChat, useMcpBridge, ai-chat, AIChatPanel), and types.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:02:07 +01:00
lucaronin
08bcab17c0 feat: leaner note creation — immediate Untitled note, no dialog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:38:03 +01:00
lucaronin
5bbd1469e2 fix: resolve TypeScript build errors in refactored code and test mocks
- Remove unused cn import from NoteList.tsx
- Fix SidebarSelection type narrowing in NoteList entity view
- Fix SortableSection onToggle type in Sidebar Omit type
- Fix TypeRow isA prop to accept null
- Align useEntryActions handleUpdateFrontmatter value type
- Add missing trashed/trashedAt/order to test mock VaultEntry objects

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:00:07 +01:00
lucaronin
65d1c753ef refactor: improve code health across 6 more files
- DynamicPropertiesPanel.tsx: extract PropertyValueCell, TypeRow, AddPropertyForm (9.06 → 9.68)
- useKeyboardNavigation.ts: extract classifyShortcut and useLatestRef (9.09 → 9.63)
- frontmatter.ts: extract parseScalar, parseInlineArray, isBlockScalar helpers (9.24 → 9.6)
- StatusBar.tsx: extract VaultMenu and VaultMenuItem components (9.23 → 10.0)
- useVaultLoader.ts: extract tauriCall helper and loadVaultData (9.35 → 10.0)
- useNoteActions.ts: extract resolveNewNote, resolveNewType, executeFrontmatterOp (9.22 → 9.38)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:55:45 +01:00
lucaronin
54fe2793fc refactor: reduce complexity in App, DiffView, Editor, InspectorPanels, NoteList
- App.tsx: extract useEntryActions hook and useLayoutPanels hook (8.92 → 9.28)
- DiffView.tsx: extract classifyDiffLine and DiffLine component (9.09 → 10.0)
- Editor.tsx: extract findEntryByTarget and lookupColorForEntry (9.09 → 10.0)
- InspectorPanels.tsx: extract entryStatusTitle and StatusSuffix (8.87 → 10.0)
- NoteList.tsx: extract EntityView, ListView, useNoteListData (8.79 → 9.68)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:48:13 +01:00
lucaronin
178d0784d1 refactor: decompose TabBar and Sidebar for reduced complexity
TabBar (8.50 → 9.38):
- Extract useTabDrag hook for drag state management
- Extract computeDropTarget/computeInsertIndex helpers
- Extract TabItem, DropIndicator, TabBarActions sub-components
- TabBar main function reduced from cc=23/176 LoC to ~25 LoC

Sidebar (8.57 → 9.38, SidebarParts 10.0):
- Create SidebarParts.tsx with NavItem, SectionContent, VisibilityPopover
- Extract useSidebarSections hook for section computation
- Extract useEntryCounts hook consolidating 3 useMemos into 1
- Extract useOutsideClick hook (eliminates 3 duplicate useEffect patterns)
- Extract buildCustomizeArgs, computeReorder pure helpers
- Extract CommitButton, ContextMenuOverlay, CustomizeOverlay
- isSelectionActive extracted as pure function (was closure)
- Sidebar reduced from 604 LoC/cc=34 to ~120 LoC/cc=11

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:37:33 +01:00
lucaronin
c3415e3ce0 refactor: extract Inspector sub-panels into InspectorPanels.tsx
Split Inspector.tsx (score 7.78) into:
- Inspector.tsx: slim shell with header, layout, prop wiring (score 9.6)
- InspectorPanels.tsx: DynamicRelationshipsPanel, BacklinksPanel,
  GitHistoryPanel, LinkButton, RelationshipGroup (score 8.87)

Extracted LinkButton as reusable component for both relationship
refs and backlinks. Moved resolveRefProps to simplify RelationshipGroup.
Extracted AddRelationshipForm and extractRelationshipRefs as focused units.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:22:26 +01:00
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
b0657bc3f5 feat: archive notes button + cmd+e shortcut 2026-02-22 10:02:17 +01:00
lucaronin
cc6d9e4799 fix: prevent double-fire of rename handler on Enter + blur
When pressing Enter in the inline tab rename input, handleSave was
called twice: once from the keydown handler and again from the blur
event triggered when React unmounted the input (editingPath → null).

The second rename call found the old path already deleted/moved,
producing empty content that overwrote the correctly renamed file
in MOCK_CONTENT — causing the editor to show a blank note.

Added a committedRef guard to InlineTabEdit so handleSave only
executes once per edit session.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:53:35 +01:00
lucaronin
abf838640d fix: + buttons for note creation pass MouseEvent as type, causing crash
onClick={onCreateNote} passes the React MouseEvent as the first arg
to handleCreateNoteImmediate(type?), which treats it as a truthy type
string. generateUntitledName then calls .toLowerCase() on the event
object, throwing a TypeError and silently aborting note creation.

Wrap both NoteList and TabBar onClick handlers to call with no args.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:50:54 +01:00
lucaronin
ccf7a440f4 fix: add back-to-editor navigation from commit diff view
When viewing a commit diff from git history, the GitBranch toggle in the
breadcrumb bar was disabled if the file had no unstaged changes, leaving
no way to return to the editor. Now the toggle stays active whenever
diffMode is true, and a visible "Back to editor" button appears at the
top of the diff view for better discoverability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:47:41 +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
7effa256b4 feat: enable adding new relationships from the properties panel 2026-02-21 22:14:15 +01:00
lucaronin
5a8eb6a5d0 feat: rename note via double-click on tab — frontend wiring
- TabBar: inline edit on double-click (Enter saves, Escape cancels)
- Extracted TabItem component + tabStyle helper for code health
- useNoteActions: handleRenameNote invokes backend, updates tabs & vault
- useVaultLoader: replaceEntry handles path-changing renames
- mock-tauri: rename_note mock with wiki link updates
- App/Editor: wire onRenameTab prop through to TabBar

Code health: TabBar improved (CC 23→18). useNoteActions/App/useVaultLoader
show minor degradation on pre-existing high-CC functions — proper fix
requires splitting the monolithic useNoteActions hook (separate concern).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:22:44 +01:00
lucaronin
2bf38bda36 fix: add missing VaultEntry properties in test fixtures and mock data
Add trashed, trashedAt, and order properties that were missing from
test entry objects after those fields were added to the VaultEntry type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:15:45 +01:00
lucaronin
0b6713df14 feat: immediate note creation — skip dialog, create Untitled note on click
Replace the CreateNoteDialog flow with immediate creation. Clicking + or
pressing Cmd+N now instantly creates an "Untitled note" (type=Note) and
opens it as the active tab. Sidebar section + buttons create "Untitled
<type>" for that section's type. Editor auto-focuses after creation so
the user can start typing immediately.

Product decisions:
- Title naming: "Untitled note", "Untitled note 2", etc. for conflicts
- Sidebar section +: creates with that section's type directly
- Editor focus via custom event to avoid stealing focus on regular tab switches

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:15:39 +01:00
lucaronin
d9a406e926 fix: truncate long property values with ellipsis instead of wrapping
Add `truncate` and `min-w-0` Tailwind classes to property value elements
in the properties panel so long text is shown on a single line with
ellipsis. The full value is visible via the title attribute on hover.

Affected elements:
- EditableValue display span (main property values)
- Status pill in DynamicPropertiesPanel
- Type button in DynamicPropertiesPanel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:07:41 +01:00
lucaronin
cadc284432 feat: improve customize sections design — Sections label with icon right-aligned 2026-02-21 19:01:41 +01:00
lucaronin
8bcae95e3f feat: wiki-links in editor inherit type color instead of always blue 2026-02-21 19:00:12 +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
6e20244078 fix: properties panel fills full window height
The Inspector aside element was missing flex-1, so it only grew to
its content height instead of filling the full height of its parent
flex-col container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 18:40:45 +01:00