Extract PropertyValueCells, TypeSelector, and AddPropertyForm into dedicated
files. Move shared display-mode constants to utils/propertyTypes to satisfy
react-refresh lint rule. All tests pass, no behavior change.
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Any frontmatter field whose value contains [[wikilinks]] now renders as a
relationship chip automatically. Fields with plain-text values always render
as editable properties, even if they were formerly hardcoded relationship keys.
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>
Add inline color swatch preview next to hex/CSS color property values in
the Properties panel. Clicking the swatch opens the native OS color
picker. Add 'color' property display mode with auto-detection for hex
values and color-related key names (background, primary, etc.).
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>
* fix: tags X button appears on hover without expanding pill width
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: tags in properties — X button doesn't reserve space, fades in on hover without expanding pill
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: parse `type` frontmatter key after is_a→type migration
The migration converts `Is A:` to `type:` in frontmatter, and the
TypeSelector UI writes to key `type`. But the Rust Frontmatter struct
only read `Is A`, so type selection was silently lost after migration
or UI change, falling back to folder inference.
Add serde alias so both `Is A` and `type` keys are parsed. Also add
`type` to SKIP_KEYS so it's not treated as a generic relationship.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: show actual type icons in Properties panel TypeSelector
Replace generic Circle icon with each type's real icon (from
iconRegistry) in the Type dropdown. Icons resolve via getTypeIcon
with custom icon support from Type documents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* design: add tags property type wireframes
Three frames showing the Tags multi-select property:
- Display state: colored pills with X to remove, + button to add
- Input state: dropdown with vault suggestions, checkmarks for selected
- Color picker: per-tag color selection row with accent palette
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add tags (multi-select) property type
Adds a new 'tags' display mode for array-valued frontmatter properties.
Includes TagPill components with deterministic color assignment,
inline tag editing with autocomplete from vault-wide values, and
automatic detection for common tag key patterns (tags, keywords,
categories, labels).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: SearchPanel test — fire ArrowDown on document not window
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- StatusDropdown: change anchor element from <div> to <span> to fix
invalid HTML nesting inside <span> parents. Browsers auto-correct
<div> inside <span> by ripping the element out, breaking
anchorRef.parentElement positioning. JSDOM doesn't auto-correct,
so tests passed but the real app's dropdown failed to position.
- StatusValue: revert shrink-0 back to min-w-0 so the status pill
can truncate in narrow panels instead of overflowing.
- PropertyRow: add min-w-0 and gap-2 for proper flex overflow,
wrap property key in truncate span.
- AddPropertyForm: add flex-wrap, reduce input widths, set
min-w-[60px] on value inputs for narrow panel support.
- InfoRow/TypeSelector/ReadOnlyType: add min-w-0 and gap-2.
- Tests: increase timeout for 3 Radix Select interaction tests
that are slow in JSDOM.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use portal-based positioning for property panel dropdowns
StatusDropdown and DisplayModeSelector used absolute positioning
within the Inspector's overflow-hidden container, causing dropdowns
to be clipped when the Properties panel is narrow (200-280px).
Both now render via createPortal into document.body with fixed
positioning calculated from the trigger element's bounding rect.
This matches the pattern used by existing Radix UI components
(Select, Popover) in the codebase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: property dropdown narrow panel fix — before/after frames
---------
Co-authored-by: Laputa App <laputa@app.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Popover and Select components: add collisionPadding=8 as default
- TypeSelector and AddPropertyForm SelectContent: position=popper, side=left
- DateValue and AddDateInput PopoverContent: side=left
Dropdowns now flip direction when hitting viewport edge instead of clipping.
Bug 1: Replace plain-text Radix Select in AddStatusInput with the same
StatusDropdown component used for existing status properties. Both now
show colored pills, search, and custom status creation.
Bug 2: Add color swatch dot next to each status option in the dropdown.
Clicking it opens an inline palette of 8 accent colors that persist via
localStorage (leveraging existing setStatusColor infrastructure).
Refactor StatusDropdown to extract useStatusFiltering, useStatusKeyboard
hooks and VaultSection/SuggestedSection/CreateSection sub-components to
keep Code Health above 9.2 threshold.
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add color dot indicators to each status option in the dropdown. Clicking
the dot opens an inline palette of 8 accent colors (from the design system).
Color assignments persist in localStorage and override the built-in defaults.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The TypeSelector on existing properties used a colored pill with no
border, while the add-property form used a bordered muted-bg control.
Align both to the add-property style: 26px height, visible border,
muted background, 4px radius.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Property value inputs now adapt to their detected or overridden display mode:
- Date properties show a calendar date picker (inline and add form)
- Boolean properties show a yes/no toggle (handles string "true"/"false")
- Status properties show a dropdown with vault + suggested statuses
- Null/empty values are now routed through display mode instead of defaulting to text
Refactored SmartPropertyValueCell and usePropertyPanelState for code health 10.0.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
SelectValue already renders the icon from the selected SelectItem,
so the explicit Icon in SelectTrigger caused the type icon to appear twice.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Rename Calendar import from lucide-react to CalendarIcon2 to avoid
conflict with Calendar from @/components/ui/calendar
- Add tsc --noEmit and pnpm build steps to CI to catch type/bundler
errors before tests run (prevents this class of bug from reaching main)
Replace the native HTML5 date input (hidden <input type="date"> with
showPicker()) with a proper shadcn/ui date picker using Calendar and
Popover components. The new implementation provides:
- Calendar popup with month navigation and keyboard support
- Clear date button in the popover footer
- Calendar icon in the trigger button
- Proper date parsing via parseDateValue helper
Also adds the design file design/date-picker-shadcn.pen with closed
and open state frames.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace the vertical grey popup with an inline horizontal form that matches
existing property row styling. Fields: [name] [type dropdown] [value] [✓] [×].
Type dropdown uses icon-left design consistent with the app's Select component.
Includes design file with empty and filled state frames.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve search panel freeze by making search_vault async
The search_vault Tauri command was synchronous (fn, not async fn),
blocking the main thread for 30+ seconds during hybrid/semantic
search on large vaults (9200+ files). This caused the macOS beachball.
Changes:
- Make search_vault async with tokio::spawn_blocking (runs qmd off main thread)
- Cache collection name per vault path (avoid repeated qmd collection list calls)
- Cancel inflight searches and debounce timers when panel closes
- Add regression test for stale result cancellation on panel close
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: add status property dropdown wireframes
Three frames: closed pill state, open dropdown with suggested/vault
statuses, and custom status creation flow.
Also bump flaky NoteList 9000-entry test timeout from 15s to 30s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: replace status text edit with Notion-style dropdown
- Extract STATUS_STYLES to shared statusStyles.ts utility
- New StatusDropdown component: filterable popover with colored pills
- StatusPill reusable component for consistent status chip rendering
- Vault-wide status aggregation from entries prop
- Dropdown shows "From vault" and "Suggested" sections
- Custom status creation via type-and-Enter
- Escape/backdrop click cancels without saving
- Keyboard navigation (ArrowUp/Down + Enter)
- 22 new tests covering dropdown behavior + integration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: cargo fmt
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* design: add smart property display wireframes
Frames: date picker, boolean toggle, status badge, display mode override dropdown.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: smart property display — type-aware rendering with display mode override
- Add property type auto-detection (date, boolean, status, url, text) based on value content and property name
- Date properties (ISO strings) show as friendly format (e.g. "Mar 31, 2026") with native date picker on click
- Boolean properties show as toggle buttons
- Status properties auto-detected from key name or known status values, rendered as colored badges
- Each property gets a display mode override dropdown (visible on hover) to force a specific display type
- Display mode overrides persist across sessions via localStorage
- Add mock data with date/boolean fields for testing
- 36 new tests covering type detection, date formatting, localStorage persistence, and UI rendering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: relation chips now display correct type color instead of default blue
Root cause: resolveRef matched entries by path/filename only, while
wiki-links used findEntryByTarget (title, filename, aliases). When a
wikilink target used the note title (differing from filename), resolveRef
failed → null type → default blue.
Changes:
- resolveRef now calls findEntryByTarget first (title/alias match)
- Default color for typeless notes changed from blue to neutral grey
- TypeSelector passes custom color key from Type entries
- DynamicPropertiesPanel refactored to reduce cyclomatic complexity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: add before/after visual for relations type color fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add task completion summary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
ReadOnlyType and TypeSelector containers were missing px-1.5, causing the
Type label to sit flush-left while all other property/info rows were
indented 6px.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Property values (dates, URLs, text) were inheriting the 14px root font
size instead of using the 12px size already applied in InfoRow and other
inspector sections. Standardize all property value and editing input
text to 12px for visual consistency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add UrlValue component: click opens in browser, pencil icon for edit
- URL detection via isUrlValue() (http/https URLs + bare domains)
- URL normalization: prepends https:// to bare domains
- Malformed URLs silently ignored (no open attempt)
- Long URLs truncated visually but full URL opens on click
- Edit mode via pencil icon or keyboard (Enter/Escape/blur)
- 22 new tests covering detection, normalization, and component behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Type field in the Properties panel was read-only. Now it uses a
Radix Select dropdown that lists all vault types (entries where
isA === "Type"), plus a "None" option to clear the type. Wired to
the existing onUpdateProperty('type', ...) flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The DynamicPropertiesPanel had a local countWords that used a regex
(/^---[\s\S]*?---/) which could match dashes inside frontmatter values,
leaving part of the frontmatter in the body and inflating the count.
Replace with the canonical countWords from utils/wikilinks.ts which uses
splitFrontmatter (line-based indexOf) and correctly finds the closing
delimiter on its own line.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rust Frontmatter struct now parses both 'type' (new) and 'Is A'/'is_a' (legacy),
with 'type' taking precedence via resolve_type()
- Added migrate_is_a_to_type() vault-wide migration (runs on startup, also exposed as Tauri command)
- Frontend: buildNoteContent and resolveNewType now emit 'type:' in YAML
- Inspector SKIP_KEYS hides 'is_a', 'Is A', 'type', 'title' from property list
(TypeRow already renders the type with its dedicated UI)
- frontmatterToEntryPatch handles both 'type' and legacy 'is_a' keys
- Mock data updated: all YAML content uses 'type:' instead of 'is_a:'/'Is A:'
- Tests updated to expect 'type:' in generated frontmatter
Product decision: internal VaultEntry field stays as `isA` (TS) / `is_a` (Rust)
to minimize blast radius. The user-facing change is the YAML key and inspector.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The is_a frontmatter key was appearing both as the TypeRow badge and
as a regular editable property. Added both 'is_a' and 'Is A' variants
to SKIP_KEYS to prevent duplication (snake_case used in mock data,
space-separated used in real vault YAML).
Added test verifying is_a is skipped when TypeRow is present.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split the Properties panel into two visually distinct sections:
1. **Properties** (editable): frontmatter properties with interactive
hover background, cursor pointer, and click-to-edit. Includes Type
row, Status, Owner, tags, and all user-defined properties.
2. **Info** (read-only): derived metadata shown below a border
separator with an "Info" header. Uses muted color (--text-muted)
with no hover states or click interaction. Includes:
- Modified date
- Created date (new)
- Word count
- File size (new, formatted as B/KB/MB)
Product decisions:
- Info section uses --text-muted for both labels and values (more
dimmed than the --muted-foreground used by editable labels)
- Editable rows get rounded hover:bg-muted on the full row
- Type row stays at top of Properties as an identity element
- Added Created date and file Size to give more useful metadata
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
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>
Replace vertical EditableList with horizontal TagPillList component.
Array property values now render as inline pill chips with hover X
to remove and a + button to add new items.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Type field in the Inspector's properties panel is now a colored
clickable chip (styled like relationship chips) that navigates to the
type document when clicked. The "Type" key is also excluded from the
relationships panel to avoid duplication.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The panel title already says "Properties" — the section heading was
redundant. Removed from both DynamicPropertiesPanel and EmptyInspector.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update NoteList group headers (RELATED NOTES, EVENTS, etc.) to use
font-mono-label class with bg-muted background bar per design.
Update Inspector section titles (Properties, Relationships, Backlinks,
History) and property labels (Type, Status, Modified, Words) to use
font-mono-overline class. Update status badge to IBM Plex Mono with
border-radius 16px per design spec.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace individual mb-4 margins with a flex column gap-4 on the
container, ensuring consistent 16px spacing between Inspector sections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>