Skip to content

feat: redesign note page with Picker system and editor blocks - #114

Merged
h4yfans merged 80 commits into
mainfrom
feat/note-page
Mar 29, 2026
Merged

feat: redesign note page with Picker system and editor blocks#114
h4yfans merged 80 commits into
mainfrom
feat/note-page

Conversation

@h4yfans

@h4yfans h4yfans commented Mar 29, 2026

Copy link
Copy Markdown
Collaborator

What

Redesign note page header, add Picker compound component, introduce new editor blocks, and add property editors with CRUD management.

Why

The note page needed a cohesive design pass — Paper-inspired header, unified popup primitive (Picker), and missing editor functionality (callouts, code highlighting, property editors). This consolidates scattered Popover/DropdownMenu usage into a single composable pattern.

How

  • Picker compound component: Replaces Popover/DropdownMenu across tags, properties, tasks, reminders, inbox filter, vault switcher, and overflow menus
  • Note page header: Compact Paper-inspired layout with full-width toggle and ghost affordance row
  • Editor blocks: Callout block (Obsidian-style), code syntax highlighting, empty line preservation in markdown round-trips
  • Property editors: Select/multiselect/status property types with PropertyDefinitionsService and settings UI
  • Backlinks: Journal page backlinks section with collapsible multi-context cards
  • Navigation: Horizontal sidebar icons, new-tab menu, context-aware note/folder creation
  • Preview cards: Hover previews for wiki-links and note tabs
  • Hash tags: Inline editing plugin with digit-starting tag support (feat: time estimation & tracking #123, #2024)

Type

  • feat — new feature
  • refactor — restructure without behavior change
  • style — visual/UI only
  • test — adding or updating tests

Test plan

  • Unit tests added/updated
  • Manual testing (describe below)

All 5305 desktop tests pass. 4 test files updated for Picker migration (ARIA role changes). Type errors fixed in tab-bar and template-editor. IPC contracts verified up to date.

Checklist

  • Self-reviewed the diff
  • No hardcoded secrets or credentials
  • Files stay under ~500 LOC
  • Follows immutable data patterns

h4yfans added 30 commits March 25, 2026 19:54
… icon generation

- Add 'dev-data/' to .gitignore to exclude development data files.
- Introduce a new script 'seed:notes' in package.json for seeding notes data.
- Update icon generation script to improve SVG rendering with bolder borders and enhanced visual elements.
- Add a new icon variant (v1.1) with updated stroke widths for better visibility.
…layout

Sticky h-11 header bar with back chevron + breadcrumb on left,
bookmark/reminder/more-menu on right. Theme-friendly tokens throughout,
no hardcoded colors or fonts. Adds Bookmark02Icon and FilePasteIcon to
icon library. Replaces MoreHorizontal with MoreVertical, uses size-7
compact icon buttons, and restructures dropdown with new icon mappings.
Playfair Display is sufficient for the display font stack;
Instrument Serif added bundle weight without being used.
…tPopup

Swaps stone-* classes for semantic tokens (border-border, bg-popover,
text-muted-foreground, etc.) so the popup respects dark/white themes.
Replaces the always-visible info toggle header with a hover-to-reveal
pattern: "Add tag" and "Add property" buttons fade in when the metadata
zone is hovered or focused, keeping the default view minimal.

- New GhostAffordanceRow component (opacity-0 → group-hover visible)
- TagsRow gains hideWhenEmpty prop to collapse when no tags exist
- InfoSection gains inline variant (no header, no add button)
- Note page wraps title/tags/props in group/metadata container
Restructure around actual CSS variable groups, add theme comparison
tables, density config reference, and usage examples.
Reusable popover-based selection primitive with compound API
(Picker.Trigger, Content, Item, List, Section, Search, Footer, Empty).
Handles open state, keyboard nav, check indicators, and search filtering
so consuming components don't re-implement these patterns.
Replace pastel background+text palette with single-hue tokens rendered
via withAlpha() for consistent tinting. TagChip gains interactive mode
(onClick, isSelected, isFocused) so TagInputPopup reuses it directly
instead of a separate TagOption. TagInputPopup and TagsRow now wrap
Picker for popover state, removing manual useClickOutside/portal logic.
Backend TAG_COLOR_PALETTE aligned to match new 20-color spectrum.
…cker

AddPropertyPopup wraps Picker with children-as-trigger pattern,
eliminating manual portal rendering and position tracking.
InfoSection and GhostAffordanceRow drop useRef/createPortal/position
state in favor of declarative Picker composition.
Remove inline emoji editing (EmojiButton, picker open/close, keyboard
handlers) from NoteTitle — emoji is now set via other UX flows.
NoteTitle renders NoteIconDisplay when emoji is present, otherwise
hides the icon container. Tests updated to match simplified API.
New ProseMirror plugin handles #tag creation/editing directly in the
editor: typing a space or Enter after "#word" converts to a styled
inline content node. Removes SuggestionMenuController for "#",
getHashTagItems cache, handleHashTagSelect, and the separate
hash-tag-space-plugin. Inline tag extraction is now debounced (300ms)
to avoid feedback loops during editing.
Replace Popover+manual list and Select primitives across 12 task files
with Picker compound component. Eliminates repeated open-state,
click-outside, check-mark, and keyboard shortcut boilerplate.
ProjectSelector extracts ProjectActions sub-component using
usePickerContext for clean dropdown-inside-picker composition.
…g-manager scroll

Collapse multi-line --font-display declaration to single line in both
themes. Migrate ModelSelector from Popover to Picker with theme tokens.
Add overflow-y-auto + max-h-[60vh] to tag-manager list for long lists.
…h trailing extension

Replaces single-char immediate matching (#a) with full-word space-terminated
matching (#tag[space]). Adds Pattern 2: trailing chars after existing hashTag
nodes get absorbed via appendTransaction instead of handleTextInput.
Wires SuggestionMenuController with # trigger, cached tag fetching (5s TTL),
and HashTagMenu component. Also re-colors existing hashTag nodes when
tagColorMap updates.
…er applied tags

Pre-filters currentTagIds from suggestions so click/enter handlers no longer
need guard checks. Replaces manual search input with FilterSearchHeader.
… tag navigation

Replaces DropdownMenu with Picker compound component. Clicking a tag
in TagsRow now navigates to the tag's sidebar drill-down view.
… with Picker

Modifies the app's quit behavior to ensure it only quits on all windows closed for non-macOS platforms. Additionally, replaces DropdownMenu with Picker in the VaultSwitcher component, improving the user interface for vault selection and actions.
…ponent colors

Refines the inline hash-tag styles to ensure proper visibility in dark mode by adding necessary prefixes. Updates the NoteOutlineSidebar component to improve hover effects and color schemes for active states. Additionally, modifies the HashTag component to utilize CSS variables for color management, enhancing maintainability.
…bility

Modifies the color settings for various components to enhance visibility, including updates to the editor and container colors. Introduces typography overrides to align with Notion's style, adjusting font family and spacing for a more cohesive user experience. Additionally, refines text behavior to match Notion's wrapping style.
…variable

Drop -webkit-font-smoothing/antialiased across all components for
native OS text rendering. Add --text-bright theme variable for
high-contrast title text. Refine note title sizing and outline
panel colors to use CSS variables.
Relax hash-tag regex from [a-zA-Z] to [a-zA-Z0-9] so tags like
#2024 and #5 are recognized in the editor. Updates inline plugin,
space plugin, and extraction logic with matching test coverage.
Add persistKey prop to TreeProvider that saves expanded node IDs
to localStorage with debounced writes. Wire notes-tree with
sidebar-tree-expanded key, clear on vault switch. Also open
sidebar clicks as non-preview tabs for tab persistence.
Accept scrollContainerRef in useActiveHeading instead of querying
the DOM for scroll containers. Add bottom-of-page detection and
setActiveHeading for programmatic outline clicks. Widen note
content area to max-w-5xl and reduce header height.
…gistry

Merge incoming viewState into existing tabs on OPEN_TAB so backlink
clicks can pass highlight context. Register tab persistence with
flush registry so Cmd+Q saves state before exit. Add structured
logging for session restore diagnostics.
h4yfans and others added 27 commits March 27, 2026 17:56
New editor components (SelectEditor, MultiselectEditor, StatusEditor,
SelectChip) with inline option creation. Updates PropertyRow to render
select types as always-interactive (no click-to-edit). Moves unique
name generation to property-utils, wires ensurePropertyDefinition on
add, and updates template-editor mapping.
Tighten heading margins, simplify list spacing selectors, add
blockquote border/padding style, and clean up comment labels.
PersistedTab was missing the emoji field, so tab serialization
stripped it on save. Icons reverted to defaults after app restart.
Add remove, rename, update-color, and delete-definition channels
for managing select/status/multiselect property options.
Extend PropertyDefinitionsService with removeOption, updateOptionColor
methods. Wire up IPC handlers and regenerate invoke map.
Add delete buttons to select/multiselect/status editors, wire up
notes-service CRUD methods, and add Properties settings section.
Markdown collapses consecutive blank lines into a single paragraph
break, losing intentional spacing. These utilities split markdown at
3+ newline boundaries (respecting code fences) and reassemble with
correct blank line counts, enabling round-trip fidelity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BlockNote's blocksToMarkdownLossy/tryParseMarkdownToBlocks collapse
consecutive blank lines per markdown spec. Wrap both read and write
paths to split content at blank-line boundaries, parse/serialize each
segment independently, and insert empty paragraph blocks for the gaps.

Affects: CRDT writeback, CRDT seeding, editor load, editor save.
No markers or invisible characters in the markdown file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire @blocknote/code-block (Shiki-powered) into the BlockNote editor:
- Extract shared editor schema to editor-schema.ts (DRY for renderer + converter)
- Override default codeBlock spec with createCodeBlockSpec(codeBlockOptions)
- Update ServerBlockNoteEditor to preserve language metadata during sync
- Fix dark mode CSS: replace wildcard !important rule with CSS variable override
  so Shiki inline token styles work across all themes
- Always-dark code block background (#24292e) matching github-dark theme
- Add 4 converter round-trip tests for language preservation
…ization

Custom BlockNote block with 4 types (info/warning/error/success),
shadcn DropdownMenu type selector, and slash menu integration.

Serializes to Obsidian callout syntax (> [!type]\n> content).
Segment-based save/load preserves callout position in document
order and integrates with blank-line-preserving markdown helpers.
Regenerated via pnpm ipc:generate to reflect current contract state
after worktree merge rebase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New general setting controls whether new notes/folders are created inside
the currently selected folder or always at root. Adds SelectedFolderProvider
context to share folder selection state across sidebar and tab bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Notes and folders are now created inside the selected folder when the
createInSelectedFolder setting is enabled. Target folder persists across
focus changes. Collapsed parent folders auto-expand on creation. Adds
TreeActionsExposer bridge and T523 test suite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace vertical sidebar nav list with compact horizontal icon bar that
shows labels only for the active item. Move graph button from sidebar to
tab bar. Replace plain plus button with dropdown menu offering New Note,
Journal, Inbox, and Tasks. Cmd+T now opens the menu. Add Cmd+Alt+1-4
shortcuts for sidebar pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hovering a note/journal/file tab shows a preview card with title, snippet,
tags, and creation date via HoverCard. Non-previewable tabs (inbox, tasks,
graph) render children directly without wrapper. Includes unit tests for
both TabHoverPreview and TabPreviewCard, plus E2E coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-note full-width mode via frontmatter.fullWidth, toggled from the
more menu with a switch. NoteLayout accepts fullWidth prop and animates
max-width transitions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce block/heading margins for denser Notion-like feel, re-enable font
ligatures in ProseMirror. Command palette closes on backdrop click and
drops blur. Sidebar min-width bumped to 244px. Tab content nudged down
0.5px for vertical centering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@h4yfans
h4yfans merged commit 1e06fe3 into main Mar 29, 2026
4 of 6 checks passed
@h4yfans
h4yfans deleted the feat/note-page branch March 29, 2026 00:18
h4yfans added a commit that referenced this pull request May 6, 2026
* chore(desktop): update .gitignore, add seed:notes script, and enhance icon generation

- Add 'dev-data/' to .gitignore to exclude development data files.
- Introduce a new script 'seed:notes' in package.json for seeding notes data.
- Update icon generation script to improve SVG rendering with bolder borders and enhanced visual elements.
- Add a new icon variant (v1.1) with updated stroke widths for better visibility.

* feat(desktop): redesign note page header with compact Paper-inspired layout

Sticky h-11 header bar with back chevron + breadcrumb on left,
bookmark/reminder/more-menu on right. Theme-friendly tokens throughout,
no hardcoded colors or fonts. Adds Bookmark02Icon and FilePasteIcon to
icon library. Replaces MoreHorizontal with MoreVertical, uses size-7
compact icon buttons, and restructures dropdown with new icon mappings.

* style(desktop): auto-format preview-icon-concepts script

* refactor(desktop): remove Instrument Serif font

Playfair Display is sufficient for the display font stack;
Instrument Serif added bundle weight without being used.

* style(desktop): replace hardcoded colors with theme tokens in TagInputPopup

Swaps stone-* classes for semantic tokens (border-border, bg-popover,
text-muted-foreground, etc.) so the popup respects dark/white themes.

* feat(desktop): add ghost affordance row for note metadata

Replaces the always-visible info toggle header with a hover-to-reveal
pattern: "Add tag" and "Add property" buttons fade in when the metadata
zone is hovered or focused, keeping the default view minimal.

- New GhostAffordanceRow component (opacity-0 → group-hover visible)
- TagsRow gains hideWhenEmpty prop to collapse when no tags exist
- InfoSection gains inline variant (no header, no add button)
- Note page wraps title/tags/props in group/metadata container

* docs: rewrite DESIGN_TOKENS.md with current token inventory

Restructure around actual CSS variable groups, add theme comparison
tables, density config reference, and usage examples.

* feat(desktop): add Picker compound component

Reusable popover-based selection primitive with compound API
(Picker.Trigger, Content, Item, List, Section, Search, Footer, Empty).
Handles open state, keyboard nav, check indicators, and search filtering
so consuming components don't re-implement these patterns.

* refactor(desktop): redesign tag colors and migrate tag system to Picker

Replace pastel background+text palette with single-hue tokens rendered
via withAlpha() for consistent tinting. TagChip gains interactive mode
(onClick, isSelected, isFocused) so TagInputPopup reuses it directly
instead of a separate TagOption. TagInputPopup and TagsRow now wrap
Picker for popover state, removing manual useClickOutside/portal logic.
Backend TAG_COLOR_PALETTE aligned to match new 20-color spectrum.

* refactor(desktop): migrate property popups and ghost affordance to Picker

AddPropertyPopup wraps Picker with children-as-trigger pattern,
eliminating manual portal rendering and position tracking.
InfoSection and GhostAffordanceRow drop useRef/createPortal/position
state in favor of declarative Picker composition.

* refactor(desktop): simplify NoteTitle to display-only emoji

Remove inline emoji editing (EmojiButton, picker open/close, keyboard
handlers) from NoteTitle — emoji is now set via other UX flows.
NoteTitle renders NoteIconDisplay when emoji is present, otherwise
hides the icon container. Tests updated to match simplified API.

* feat(desktop): replace hash-tag autocomplete with inline editing plugin

New ProseMirror plugin handles #tag creation/editing directly in the
editor: typing a space or Enter after "#word" converts to a styled
inline content node. Removes SuggestionMenuController for "#",
getHashTagItems cache, handleHashTagSelect, and the separate
hash-tag-space-plugin. Inline tag extraction is now debounced (300ms)
to avoid feedback loops during editing.

* refactor(desktop): migrate task components to Picker primitive

Replace Popover+manual list and Select primitives across 12 task files
with Picker compound component. Eliminates repeated open-state,
click-outside, check-mark, and keyboard shortcut boilerplate.
ProjectSelector extracts ProjectActions sub-component using
usePickerContext for clean dropdown-inside-picker composition.

* style(desktop): fix CSS formatting, migrate ModelSelector, and add tag-manager scroll

Collapse multi-line --font-display declaration to single line in both
themes. Migrate ModelSelector from Popover to Picker with theme tokens.
Add overflow-y-auto + max-h-[60vh] to tag-manager list for long lists.

* fix(desktop): quit app on all windows closed regardless of platform

* refactor(desktop): change hash-tag plugin to space-based creation with trailing extension

Replaces single-char immediate matching (#a) with full-word space-terminated
matching (#tag[space]). Adds Pattern 2: trailing chars after existing hashTag
nodes get absorbed via appendTransaction instead of handleTextInput.

* style(desktop): use alpha-blended background for inline hash-tag chips

* feat(desktop): add hash-tag autocomplete suggestion menu in content area

Wires SuggestionMenuController with # trigger, cached tag fetching (5s TTL),
and HashTagMenu component. Also re-colors existing hashTag nodes when
tagColorMap updates.

* refactor(desktop): migrate TagInputPopup to Picker primitive and filter applied tags

Pre-filters currentTagIds from suggestions so click/enter handlers no longer
need guard checks. Replaces manual search input with FilterSearchHeader.

* feat(desktop): add onTagClick callback to TagsRow component

* refactor(desktop): migrate ReminderPicker from Popover to Picker primitive

* refactor(desktop): migrate note page overflow menu to Picker and wire tag navigation

Replaces DropdownMenu with Picker compound component. Clicking a tag
in TagsRow now navigates to the tag's sidebar drill-down view.

* refactor(desktop): update app quit behavior and enhance VaultSwitcher with Picker

Modifies the app's quit behavior to ensure it only quits on all windows closed for non-macOS platforms. Additionally, replaces DropdownMenu with Picker in the VaultSwitcher component, improving the user interface for vault selection and actions.

* style(desktop): enhance inline hash-tag styles and update sidebar component colors

Refines the inline hash-tag styles to ensure proper visibility in dark mode by adding necessary prefixes. Updates the NoteOutlineSidebar component to improve hover effects and color schemes for active states. Additionally, modifies the HashTag component to utilize CSS variables for color management, enhancing maintainability.

* style(desktop): update color scheme and typography for improved readability

Modifies the color settings for various components to enhance visibility, including updates to the editor and container colors. Introduces typography overrides to align with Notion's style, adjusting font family and spacing for a more cohesive user experience. Additionally, refines text behavior to match Notion's wrapping style.

* style(desktop): remove antialiased smoothing and add text-bright CSS variable

Drop -webkit-font-smoothing/antialiased across all components for
native OS text rendering. Add --text-bright theme variable for
high-contrast title text. Refine note title sizing and outline
panel colors to use CSS variables.

* feat(desktop): allow digit-starting hash tags (#123, #2024)

Relax hash-tag regex from [a-zA-Z] to [a-zA-Z0-9] so tags like
#2024 and #5 are recognized in the editor. Updates inline plugin,
space plugin, and extraction logic with matching test coverage.

* feat(desktop): persist sidebar tree expand/collapse state

Add persistKey prop to TreeProvider that saves expanded node IDs
to localStorage with debounced writes. Wire notes-tree with
sidebar-tree-expanded key, clear on vault switch. Also open
sidebar clicks as non-preview tabs for tab persistence.

* refactor(desktop): improve active heading tracking and widen note layout

Accept scrollContainerRef in useActiveHeading instead of querying
the DOM for scroll containers. Add bottom-of-page detection and
setActiveHeading for programmatic outline clicks. Widen note
content area to max-w-5xl and reduce header height.

* refactor(desktop): support viewState merge on tab reopen and flush registry

Merge incoming viewState into existing tabs on OPEN_TAB so backlink
clicks can pass highlight context. Register tab persistence with
flush registry so Cmd+Q saves state before exit. Add structured
logging for session restore diagnostics.

* feat(desktop): redesign backlinks with multi-context collapsible cards

Replace single-context backlink cards with collapsible per-note groups
showing all [[wikilink]] mentions. Extract context snippets with regex
for every occurrence in source content. Add inline tag reconciliation
that syncs #tags in content with frontmatter on save. Restyle backlink
UI with compact tree layout, custom link icon, and reference counts.
Update TagChip remove button to span with keyboard support.

* feat(desktop): add wiki-link hover preview card

Add notes:preview-by-title IPC channel that returns note metadata
(title, emoji, snippet, tags, date) for hover previews. Implement
useWikiLinkHover hook with 300ms delay, LRU cache, and smart
positioning. Render WikiLinkPreviewCard via portal on [data-wiki-link]
hover in ContentArea.

* feat(desktop): add backlinks section to journal page

Wire useNoteLinksQuery into journal entries to show incoming
backlinks below content. Transform raw backlink data to component
format with multi-context mentions. Add scroll container ref for
accurate heading tracking. Handle navigation to both notes and
journal entries from backlink clicks.

* docs: add backlinks redesign and select/multiselect property plans

Plan 012: collapsible backlinks with multi-context snippets.
Plan 013: select and multiselect property types for notes.

* style(design): FINDING-001/002 — merge duplicate status group headers

When grouping by status across multiple projects, each project's "To Do"
and "In Progress" statuses had unique IDs creating duplicate section
headers (e.g., "To Do 1", "To Do 2", "To Do 1"). Now merges by
status.type so there's one "To Do" and one "In Progress" group.

* style(design): FINDING-008/009/011/012 — polish detail drawer

- Tighten property label width (90px → 76px) for better proximity
- Soften section labels: remove uppercase + letter-spacing
- Make empty states actionable ("Add a sub-issue…", "Link a note…")
- Fix orphaned created-date: remove mt-auto, reduce to 10px/50% opacity

* style(design): FINDING-014 — stronger selected row indicator

Replace subtle ring-1/ring-primary/30 with a left border accent
(border-l-2 border-l-primary) for clearer active-task indication
when the detail drawer is open.

* style(design): FINDING-013 — polish repeat section

- Match section label style (remove uppercase + letter-spacing)
- Add hover states to Edit/Stop repeating buttons
- Soften button text to text-secondary

* docs: approve select/multiselect properties plan with expanded spec

Add status property type with category groups, named color palette,
visual specs, accessibility notes, interaction states, and review report.

* style(editor): Notion-like heading sizes, list spacing, and table cells

Downscale BlockNote heading defaults (3em/2em/1.3em → 1.875/1.5/1.25em),
tighten consecutive list item gaps, add table cell padding and font size,
enable -webkit-font-smoothing: auto for sharper text rendering.

* style(note): add metadata separator and group backlinks section

Insert subtle hr between metadata zone and editor content, wrap
backlinks + linked tasks in a mt-10 container for visual separation.

* fix(inbox): omit current year in compact date format

Show "15 Mar" for current-year dates, "4 Jul 2024" for past years.
Drop zero-padded day. Update tests to match.

* refactor(inbox): replace DropdownMenu filter with Picker component

Swap Radix DropdownMenu for the project Picker in multi-select mode,
add per-type icons, use custom filter/snoozed button styling with
border states instead of ToolbarButton.

* style(inbox): soften resize handle and use amber for stale items

Lighten detail panel resize border, bump keyboard hint opacity,
change stale timestamp color from red to amber for less alarm.

* style(tasks): polish toolbar, drawer, rows, and repeat section

Downscale tab/filter font to 12px, use ring instead of border-l for
selected rows, uppercase section labels in drawer/repeat, widen
property grid labels, simplify empty sub-issue/note states, wrap
toolbar in PageToolbar component.

* test(sync): add sync-harness infrastructure with Miniflare + crypto

Introduce @memry/sync-harness — a property-based integration test
framework for E2E encrypted sync. Boots real Cloudflare Worker via
Miniflare with D1/R2/Durable Objects, full XChaCha20+Ed25519 crypto,
OracleModel for correctness validation, and seeded ChaosController
for reproducible test runs.

Components: SimulatedServer, SimulatedDevice, OracleModel,
ChaosController, TestAuth, Crypto utilities.

* test(sync): add basic convergence tests — A→B, settings, multi-item, bidirectional

4 tests validating fundamental sync correctness: single task sync,
settings type sync, multi-item batch, and bidirectional push/pull.
All verify against OracleModel for independent correctness validation.

* test(sync): add conflict resolution, multi-device, and edge case suites

23 new tests covering: sequential field edits, same-field LWW, delete
propagation, delete-vs-update races, settings doc-level LWW, 3-device
triangle convergence, 50-item batch, mixed types, rapid-fire updates,
unicode round-trip, nested JSON, null/falsy values, user isolation,
and idempotent pull behavior.

* test(sync): add negative crypto/auth tests from Codex review

5 tests for crypto rejection: wrong vault key, corrupted signature,
tampered ciphertext, invalid JWT, and cross-user isolation. Ensures
XChaCha20+Ed25519 pipeline rejects invalid data at every layer.

* build: add tests/* to pnpm workspace for sync-harness package

* feat(contracts): add status/select/multiselect property types

Extends PropertyTypes with status, select, and multiselect. Adds Zod
schemas for property definitions (SelectOption, StatusCategories),
default status definition, and three new IPC channels
(ensure/addOption/addStatusOption).

* feat(main): add PropertyDefinitionsService for select/status properties

File-backed service (properties.md in .memry/) with serialized write
queue and DB cache sync. Integrates with vault open/close lifecycle,
pull-coordinator reload, and notes-handlers for CRUD + option mutation
IPC. Adds multiselect deserialization in notes query layer. Regenerates
IPC invoke map.

* feat(preload): expose select property IPC channels to renderer

Bridge ensurePropertyDefinition, addPropertyOption, and addStatusOption
through preload + notes-service so renderer can manage select/status
property options.

* feat(renderer): add select/multiselect/status property editors

New editor components (SelectEditor, MultiselectEditor, StatusEditor,
SelectChip) with inline option creation. Updates PropertyRow to render
select types as always-interactive (no click-to-edit). Moves unique
name generation to property-utils, wires ensurePropertyDefinition on
add, and updates template-editor mapping.

* style(editor): refine BlockNote spacing and add quote block styling

Tighten heading margins, simplify list spacing selectors, add
blockquote border/padding style, and clean up comment labels.

* fix(tabs): persist emoji in tab state for icon restoration on reopen

PersistedTab was missing the emoji field, so tab serialization
stripped it on save. Icons reverted to defaults after app restart.

* feat(contracts): add property option CRUD IPC channels

Add remove, rename, update-color, and delete-definition channels
for managing select/status/multiselect property options.

* feat(main): add property option remove/rename/color/delete operations

Extend PropertyDefinitionsService with removeOption, updateOptionColor
methods. Wire up IPC handlers and regenerate invoke map.

* feat(preload): expose property option CRUD channels to renderer

* feat(renderer): add property option management UI with settings page

Add delete buttons to select/multiselect/status editors, wire up
notes-service CRUD methods, and add Properties settings section.

* docs: add property definitions settings plan

* feat(shared): add empty-line-preserving markdown split/assemble utils

Markdown collapses consecutive blank lines into a single paragraph
break, losing intentional spacing. These utilities split markdown at
3+ newline boundaries (respecting code fences) and reassemble with
correct blank line counts, enabling round-trip fidelity.


* feat(editor): preserve empty lines across markdown round-trips

BlockNote's blocksToMarkdownLossy/tryParseMarkdownToBlocks collapse
consecutive blank lines per markdown spec. Wrap both read and write
paths to split content at blank-line boundaries, parse/serialize each
segment independently, and insert empty paragraph blocks for the gaps.

Affects: CRDT writeback, CRDT seeding, editor load, editor save.
No markers or invisible characters in the markdown file.


* feat(renderer): add code block syntax highlighting with language support

Wire @blocknote/code-block (Shiki-powered) into the BlockNote editor:
- Extract shared editor schema to editor-schema.ts (DRY for renderer + converter)
- Override default codeBlock spec with createCodeBlockSpec(codeBlockOptions)
- Update ServerBlockNoteEditor to preserve language metadata during sync
- Fix dark mode CSS: replace wildcard !important rule with CSS variable override
  so Shiki inline token styles work across all themes
- Always-dark code block background (#24292e) matching github-dark theme
- Add 4 converter round-trip tests for language preservation

* feat(renderer): add callout block with Obsidian-style markdown serialization

Custom BlockNote block with 4 types (info/warning/error/success),
shadcn DropdownMenu type selector, and slash menu integration.

Serializes to Obsidian callout syntax (> [!type]\n> content).
Segment-based save/load preserves callout position in document
order and integrates with blank-line-preserving markdown helpers.

* chore: regenerate IPC invoke map after rebase

Regenerated via pnpm ipc:generate to reflect current contract state
after worktree merge rebase.

* chore: regenerate IPC invoke map


* feat(tree): add expand/collapse all APIs to tree provider


* feat(settings): add createInSelectedFolder setting with context provider

New general setting controls whether new notes/folders are created inside
the currently selected folder or always at root. Adds SelectedFolderProvider
context to share folder selection state across sidebar and tab bar.


* feat(renderer): context-aware note/folder creation in notes tree

Notes and folders are now created inside the selected folder when the
createInSelectedFolder setting is enabled. Target folder persists across
focus changes. Collapsed parent folders auto-expand on creation. Adds
TreeActionsExposer bridge and T523 test suite.


* feat(renderer): reorganize nav — horizontal sidebar icons + new-tab menu

Replace vertical sidebar nav list with compact horizontal icon bar that
shows labels only for the active item. Move graph button from sidebar to
tab bar. Replace plain plus button with dropdown menu offering New Note,
Journal, Inbox, and Tasks. Cmd+T now opens the menu. Add Cmd+Alt+1-4
shortcuts for sidebar pages.


* feat(renderer): add tab hover preview card for note tabs

Hovering a note/journal/file tab shows a preview card with title, snippet,
tags, and creation date via HoverCard. Non-previewable tabs (inbox, tasks,
graph) render children directly without wrapper. Includes unit tests for
both TabHoverPreview and TabPreviewCard, plus E2E coverage.


* feat(renderer): add full-width toggle for note pages

Per-note full-width mode via frontmatter.fullWidth, toggled from the
more menu with a switch. NoteLayout accepts fullWidth prop and animates
max-width transitions.


* style(renderer): tighten editor spacing and polish UI details

Reduce block/heading margins for denser Notion-like feel, re-enable font
ligatures in ProseMirror. Command palette closes on backdrop click and
drops blur. Sidebar min-width bumped to 244px. Tab content nudged down
0.5px for vertical centering.


* docs: add Note Page changelog entry

* chore: regenerate IPC invoke map

* fix: resolve type errors in tab-bar and template-editor

* chore: add .worktrees to gitignore

* fix(tasks): prevent click propagation on project badge Picker trigger

* test: update tests for Picker migration and status grouping changes

---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant