* add pb models * api rules has updated to view public * pb setup is completed * add migrate script * add pb migrations * ignore storage * add pocketbase SDK dependency * change Tag.id and PageCardDto.id to string for PocketBase * add DocV1 content block types * add PB client singleton and PB record types * rewrite factory for PocketBase record types * rewrite api.ts for PocketBase SDK * remove unused Strapi files, add PB to config * mark Task 7 complete in plan * feat: verify build, tests, and lint pass with PocketBase API layer * move completed plan: 2026-04-06-pocketbase-api-layer.md * scaffold hudozka-writer with Vite 8, React 19, TS 5.9, Tiptap * add PocketBase client and DocV1 types to writer * add Login component for PocketBase superuser auth * add App shell with auth gate and page loader * add DocV1 <-> Tiptap serialization layer * mark Task 5 complete in writer redesign plan * add custom Tiptap nodes for DocV1 block types * add Tiptap editor with toolbar and save to PocketBase * add image picker with browse and upload * feat: verify writer build and complete integration task * move completed plan: 2026-04-06-hudozka-writer-redesign.md * add local env * rm textblock from writer * add writer editor improvements design spec * add writer editor improvements implementation plan * feat: use @tiptap/markdown for text block serialization * feat: add global markdown/rendered toggle * feat: add BlockMenu component for block type selection * feat: add hover + button for block insertion * feat: add slash commands for block insertion * feat: add interactive file block editor with FilePicker * feat: show resolved page titles in card grid block * move completed plan: 2026-04-07-writer-editor-improvements.md * writer ui improved * pages migration * spec: draft/publish workflow for hudozka-writer * spec: rename draft_doc to draft in spec * plan: writer draft/publish implementation * plan has moved * gitignores * plans upd * feat(writer): update PbPage type for draft/publish workflow * feat(writer): add save/publish/discard handlers with dirty tracking * feat(writer): add DraftBanner component * feat(writer): add Publish button and update toolbar layout * feat(writer): add published toggle and update duplicate for new schema * docs: mark manual verification steps as skipped in writer draft/publish plan * move completed plan: 20260407-writer-draft-publish.md * feat(writer): add BlockActions component for inline block menus * feat(writer): add draggable NodeViews for text blocks * feat(writer): use BlockActions in custom block NodeViews * feat(writer): replace floating BlockInsert with inline BlockActions * fix(writer): ensure all block wrappers have position: relative for BlockActions * chore: mark manual verification tasks as skipped in writer block actions plan * move completed plan: 20260408-writer-block-actions.md * writer update * refactor(writer): simplify BlockActions to always-visible delete + drag handle * feat(writer): add BlockInsert component for inserting blocks between nodes * feat(writer): redesign block sidebar with always-visible actions and insert button * move completed plan: 20260408-writer-block-actions-redesign.md * add spec: textblock container redesign for writer editor * feat(writer): add TextBlock container node definition * feat(writer): replace DraggableXxx wrappers with TextBlock container * feat(writer): update Editor extensions for TextBlock container * feat(writer): add split button to BlockActions for text blocks * feat(writer): update serialization for TextBlock container * feat(writer): update BlockMenu and SlashCommands for TextBlock * fix(writer): use Fragment.from() for replaceWith calls in BlockActions and SlashCommands * move completed plan: 20260408-textblock-container.md * add air
2.8 KiB
TextBlock Container Redesign
Problem
The writer editor has a flat document schema where every paragraph, heading, list, etc. is a top-level block with its own sidebar actions (delete, drag) and insert button. This causes two issues:
- List items inside bullet/ordered lists each get their own sidebar actions (because paragraphs inside list items use custom DraggableXxx node views)
- Conceptually related text content (several paragraphs in sequence) appears as many independent blocks instead of one cohesive unit
Solution
Introduce a textBlock container node that groups text-level content. Each textBlock gets one set of sidebar actions. Media blocks (image, document, embed, card-grid) remain standalone top-level blocks as they are today.
Document Schema
Current:
doc → (paragraph | heading | bulletList | ... | imageBlock | documentBlock | ...)+
New:
doc → (textBlock | imageBlock | documentBlock | embedBlock | cardGridBlock)+
textBlock → (paragraph | heading | bulletList | orderedList | blockquote | codeBlock | horizontalRule)+
TextBlock Node
- Tiptap
Node.create()withname: "textBlock",group: "block",draggable: true - Content spec allows standard text-level nodes inside it
- Node view renders the same pattern as other blocks:
BlockActions(delete, split, drag handle) insideNodeViewWrapperNodeViewContentfor the editable areaBlockInsertafter the wrapper
BlockActions Changes
BlockActions gets a new showSplit prop, only passed by textBlock. The sidebar shows three buttons for text blocks:
- Delete (×)
- Split (✂) — splits the text block at cursor position
- Drag handle (⠇)
Custom blocks (image, document, etc.) keep delete + drag only.
Split Operation
When the user clicks Split:
- Find cursor position within the
textBlock - Determine which child node the cursor is in
- Split at the boundary between child nodes — the block divides into two
textBlocknodes - If either half would be empty, don't create it
- Split is disabled when: cursor at the very start/end, or the text block contains only one child node
Split happens at child-node boundaries, not mid-paragraph.
Serialization
The DocV1 format does not change. The serialization/deserialization logic in serialize.ts is updated to work with textBlock container nodes instead of the current buffer-accumulation pattern.
What Gets Removed
- All
DraggableXxxwrappers:DraggableParagraph,DraggableHeading,DraggableBulletList,DraggableOrderedList,DraggableBlockquote,DraggableCodeBlock,DraggableHorizontalRule - Standard StarterKit extensions used instead (no longer disabled in
StarterKit.configure()) - Text-level nodes lose their individual
BlockActionsandBlockInsert - The
textBlocks.tsxfile is replaced with the newTextBlocknode definition