From c04d55cf944ed557c0887f52b207d5c78c64360c Mon Sep 17 00:00:00 2001 From: Orkhan Ahmadov Date: Wed, 13 May 2026 17:41:05 +0200 Subject: [PATCH 1/9] feat: implement block duplication to insert after source block and enhance dark mode preview --- .../clone-after-source-and-action-theme.md | 6 + packages/core/src/block-actions.ts | 30 ++++- packages/core/src/cloud/editor.ts | 22 ++++ packages/core/src/editor.ts | 22 ++++ packages/core/tests/block-actions.test.ts | 114 +++++++++++++++++- packages/core/tests/editor.test.ts | 54 +++++++++ packages/editor/src/components/Canvas.vue | 45 +++++-- .../src/components/blocks/BlockWrapper.vue | 20 ++- .../editor/src/composables/useEditorCore.ts | 6 + packages/editor/src/styles/index.css | 15 ++- .../tests/block-chrome-structure.test.ts | 104 ++++++++++++++++ 11 files changed, 414 insertions(+), 24 deletions(-) create mode 100644 .changeset/clone-after-source-and-action-theme.md create mode 100644 packages/editor/tests/block-chrome-structure.test.ts diff --git a/.changeset/clone-after-source-and-action-theme.md b/.changeset/clone-after-source-and-action-theme.md new file mode 100644 index 0000000..48f50e7 --- /dev/null +++ b/.changeset/clone-after-source-and-action-theme.md @@ -0,0 +1,6 @@ +--- +"@templatical/core": patch +"@templatical/editor": patch +--- + +Block clone now inserts directly after the source block (in the same section column when applicable) instead of appending to the end of the canvas. Action bar now follows the editor's UI theme — appears dark in editor dark mode instead of being forced light by the canvas-wrapper override. Canvas dark-mode preview refactored: filter moved from `.tpl-canvas-wrapper` onto a sibling bg layer + per-block `.tpl-block-content` wrapper, so block chrome (action bar, indicators) is never inside the filter region — no more counter-filter flicker when toggling dark preview. Adds `findBlockLocation(blockId)` to `useEditor` (and the cloud variant) and an optional `findBlockLocation` option on `useBlockActions` to power the new "insert clone after source" behavior. diff --git a/packages/core/src/block-actions.ts b/packages/core/src/block-actions.ts index 1261cef..c19622e 100644 --- a/packages/core/src/block-actions.ts +++ b/packages/core/src/block-actions.ts @@ -6,10 +6,18 @@ export interface UseBlockActionsOptions { block: Block, targetSectionId?: string, columnIndex?: number, + index?: number, ) => void; removeBlock: (blockId: string) => void; updateBlock: (blockId: string, updates: Partial) => void; selectBlock: (blockId: string | null) => void; + /** Locate a block in the tree — used by `duplicateBlock` to insert the + * clone right after the source instead of appending to the end. */ + findBlockLocation?: (blockId: string) => { + targetSectionId?: string; + columnIndex?: number; + index: number; + } | null; blockDefaults?: BlockDefaults; } @@ -35,7 +43,8 @@ export interface UseBlockActionsReturn { export function useBlockActions( options: UseBlockActionsOptions, ): UseBlockActionsReturn { - const { addBlock, removeBlock, updateBlock, selectBlock } = options; + const { addBlock, removeBlock, updateBlock, selectBlock, findBlockLocation } = + options; function createAndAddBlock( type: BlockType, @@ -66,7 +75,24 @@ export function useBlockActions( ); } - addBlock(cloned, targetSectionId, columnIndex); + // Insert directly after the source block. Explicit target args win; + // otherwise, resolve the source's location and bump index by 1. Falls + // back to appending at the end if location is unknown. + if (targetSectionId !== undefined || columnIndex !== undefined) { + addBlock(cloned, targetSectionId, columnIndex); + } else { + const sourceLocation = findBlockLocation?.(block.id) ?? null; + if (sourceLocation) { + addBlock( + cloned, + sourceLocation.targetSectionId, + sourceLocation.columnIndex, + sourceLocation.index + 1, + ); + } else { + addBlock(cloned, targetSectionId, columnIndex); + } + } selectBlock(cloned.id); return cloned; } diff --git a/packages/core/src/cloud/editor.ts b/packages/core/src/cloud/editor.ts index 307ed81..3e776c8 100644 --- a/packages/core/src/cloud/editor.ts +++ b/packages/core/src/cloud/editor.ts @@ -51,6 +51,11 @@ export interface UseEditorReturn { ) => void; savedBlockIds: Ref>; isBlockLocked: (blockId: string) => boolean; + findBlockLocation: (blockId: string) => { + targetSectionId?: string; + columnIndex?: number; + index: number; + } | null; create: (content?: TemplateContent) => Promise