Add Ctrl+Tab block-level indent for all block types
Details
New feature: Ctrl+Tab indents the entire block (any type), Ctrl+Shift+Tab
outdents. Range 0–5 levels, 24px per level applied as left margin on
the BlockWrapper's outer border.
Model:
- Add IndentLevel property to PageBlock (serialized as "block_indent",
omitted when 0, clamped to 0–5 on read)
Serialization:
- PageBlockConverter.Read: parse "block_indent" from JSON
- PageBlockConverter.Write: emit "block_indent" when > 0
View:
- NotesView.OnKeyDown: Ctrl+Tab increments IndentLevel on the
top-level block, Ctrl+Shift+Tab decrements. Uses FindTopLevelBlock
to resolve the correct block even inside nested containers.
- Add FindParentOfType<T> helper for visual tree traversal
BlockWrapper:
- ApplyBlockIndentMargin: sets left margin on _outerBorder based on
PageBlock.IndentLevel, called on both OnLoaded and OnDataContextChanged
This is independent of ParagraphBlock.IndentLevel (Tab indent) which
applies a separate margin inside the block wrapper. Both can coexist.
Fix slash command inserting above blockquotes instead of after
Details
When "/" is typed inside a blockquote (or callout/group), FindParentBlock
returns the inner child PageBlock which isn't in CurrentBlocks, causing
IndexOf to return -1. The slash insert index falls back to stale
_savedBlockIndex, placing the new block at the wrong position.
Add FindTopLevelBlock helper that walks up the visual tree and returns
the first PageBlock found in CurrentBlocks. For nested containers, this
correctly resolves to the outer blockquote/callout block. For regular
blocks, it behaves identically to FindParentBlock.
The slash handler now uses FindTopLevelBlock instead of FindParentBlock
for index resolution.
Remove group block and fix definition list Enter key + focus
Details
Group block removal:
- Remove group from the block type picker, command routing, and
CreateBlockFromTypeId factory
- Remove AddGroupBlock command and GroupSelectedBlocks multi-select action
- Remove "Group Selected" context menu item from BlockWrapper
- Keep GroupBlock model, deserializer, and renderer for backwards
compatibility with existing pages that contain group blocks
Definition list Enter key + auto-focus:
- Add Enter key handler to DefinitionListEditor — pressing Enter in a
term TextBox inserts a new definition under that term; pressing Enter
in a definition TextBox inserts a new definition after it
- Tag each TextBox with (ItemIndex, DefIndex) tuple to identify its
position in the definition list model
- Add _pendingFocusIndex mechanism: set before RebuildItems(), applied
after rebuild via Dispatcher.Post at Loaded priority
- "Add term" and "Add definition" buttons now auto-focus the newly
created TextBox after rebuild
Fix block insertion position and auto-focus reliability
Details
Slash command ("/"):
- Capture the source block index at "/" time into _slashBlockIndex,
independent of _savedBlockIndex which can become stale during debounce
- Pass the captured index to the VM via SetSlashInsertIndex() before
opening the block picker
- InsertBlockAtSelection now checks _slashInsertIndex first (highest
priority), then _savedBlockIndex, then SelectedBlockIndex
- Reduce slash debounce from 500ms to 250ms for snappier response
"+" Add block button:
- ToggleBlockPicker now calls ClearBlockSelection() before opening,
ensuring _savedBlockIndex = -1 and SelectedBlockIndex = -1
- This makes InsertBlockAtSelection fall through to the append-at-end
branch, which is the expected behavior for the bottom-of-page button
Auto-focus after insertion:
- ScrollToBlock now retries up to 2 times instead of 1 — first at
Loaded priority, then at Background priority
- The lower Background priority gives the visual tree more time to
materialize inner controls in virtualized ItemsControl containers
Fix nested child blocks rendering as ToString() instead of proper editors
Details
The ChildBlocksHost ItemsControl in BlockWrapper.axaml had a bare
ContentControl with no DataTemplates registered, so any block nested
as a child (via tree indentation or GroupBlock) would fall through to
ToString() rendering — showing raw type names like
"DefinitionListBlock { Type = definition_list, Items = ... }".
Replace the inline template-less AXAML DataTemplate with
BlockTemplateFactory.CreateBlockTemplate() set in code-behind,
which provides the full set of block content DataTemplates for all
block types including proper editor controls, Loaded/Unloaded wiring,
and drag handle support.
Get notified about new releases