@aswin.dev/editor 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +56 -0
- package/README.md +3 -3
- package/dist/{AccessibilityPanel-CvQGLdu6.js → AccessibilityPanel-EmQ19wiS.js} +37 -37
- package/dist/{AiChatSidebar-B3SJIKG_.js → AiChatSidebar-DeB0w_32.js} +67 -81
- package/dist/{AiFeatureMenu-BLLKoOos.js → AiFeatureMenu-DoLD5Cde.js} +22 -22
- package/dist/{BlockA11yBadge-CXDLqkcJ.js → BlockA11yBadge-DkNbDvJA.js} +12 -12
- package/dist/CloudEditor-zo9PjjvY.js +1214 -0
- package/dist/{CollaboratorBar-DuPYW5iF.js → CollaboratorBar-BsXMY-8e.js} +21 -21
- package/dist/CommentsSidebar-DIWIa4rS.js +436 -0
- package/dist/CountdownBlock-BCi7-DAM.js +92 -0
- package/dist/CountdownToolbar-BuS8p5ju.js +210 -0
- package/dist/{DesignReferenceSidebar-B8V_F2yF.js → DesignReferenceSidebar-RDlnhL-6.js} +58 -58
- package/dist/{LoadingTrack-B0CWFHXQ.js → LoadingTrack-BJ59h9ok.js} +2 -2
- package/dist/ModuleBrowserModal-b7HbpByz.js +206 -0
- package/dist/ModulePreviewCanvas-D__YlOLS.js +108 -0
- package/dist/{NumberWithSuffix-DkXUez9t.js → NumberWithSuffix-Ca3vNY84.js} +87 -87
- package/dist/{ParagraphEditor-D75wl3BX.js → ParagraphEditor-B1aYPO-6.js} +182 -182
- package/dist/{RichTextEditorContent-DYkIauIk.js → RichTextEditorContent-BmEVMrkJ.js} +38 -38
- package/dist/{SaveModuleDialog-FZ9lxY7_.js → SaveModuleDialog-ClovqI6h.js} +28 -28
- package/dist/{SnapshotHistory-BR3eV120.js → SnapshotHistory-DoqtH0cw.js} +45 -50
- package/dist/{TemplateScoringPanel-4GTNHej5.js → TemplateScoringPanel-DQv2ZAiL.js} +75 -75
- package/dist/{TestEmailModal--ue5w9fT.js → TestEmailModal-iIeYJYsj.js} +28 -28
- package/dist/{TitleEditor-fStSADI-.js → TitleEditor-CTDIwRF_.js} +68 -68
- package/dist/{TplModal-BwSfxIHf.js → TplModal-CBq1J1pG.js} +14 -14
- package/dist/{accessibility-e8JYu_zd.js → accessibility-BU09xZrQ.js} +1 -1
- package/dist/{blockTypeIcons-BcTrDjmH.js → blockTypeIcons-QkC6f5UE.js} +19 -5
- package/dist/bundle-stats.json +7 -7
- package/dist/cdn/chunks/{AccessibilityPanel-B6DOjojm.js → AccessibilityPanel-BeU8nz7A.js} +28 -28
- package/dist/cdn/chunks/{AccessibilityPanel-B6DOjojm.js.map → AccessibilityPanel-BeU8nz7A.js.map} +1 -1
- package/dist/cdn/chunks/{AiFeatureMenu-qEdB2fZJ.js → AiFeatureMenu-B2mhscyP.js} +21 -21
- package/dist/cdn/chunks/AiFeatureMenu-B2mhscyP.js.map +1 -0
- package/dist/cdn/chunks/{BlockA11yBadge-DcEZftf6.js → BlockA11yBadge-C4g77gF0.js} +11 -11
- package/dist/cdn/chunks/{BlockA11yBadge-DcEZftf6.js.map → BlockA11yBadge-C4g77gF0.js.map} +1 -1
- package/dist/{CloudEditor-BCz1ZTYC.js → cdn/chunks/CloudEditor-Btyr0b0_.js} +486 -475
- package/dist/cdn/chunks/CloudEditor-Btyr0b0_.js.map +1 -0
- package/dist/cdn/chunks/{CollaboratorBar--nO7TX6b.js → CollaboratorBar-YBiIjiRh.js} +15 -15
- package/dist/cdn/chunks/CollaboratorBar-YBiIjiRh.js.map +1 -0
- package/dist/cdn/chunks/CountdownBlock-B06UZoWe.js +93 -0
- package/dist/cdn/chunks/CountdownBlock-B06UZoWe.js.map +1 -0
- package/dist/cdn/chunks/CountdownToolbar-C9XZr33O.js +212 -0
- package/dist/cdn/chunks/CountdownToolbar-C9XZr33O.js.map +1 -0
- package/dist/{ModuleBrowserModal-DrUFMTDx.js → cdn/chunks/ModuleBrowserModal-C2CDWKW6.js} +51 -62
- package/dist/cdn/chunks/ModuleBrowserModal-C2CDWKW6.js.map +1 -0
- package/dist/cdn/chunks/ModulePreviewCanvas-Drt8Evai.js +109 -0
- package/dist/cdn/chunks/ModulePreviewCanvas-Drt8Evai.js.map +1 -0
- package/dist/cdn/chunks/{NumberWithSuffix-CE3NrZhH.js → NumberWithSuffix-Ty1bp9vB.js} +64 -64
- package/dist/cdn/chunks/{NumberWithSuffix-CE3NrZhH.js.map → NumberWithSuffix-Ty1bp9vB.js.map} +1 -1
- package/dist/cdn/chunks/{ParagraphEditor-B6Ygu-Mq.js → ParagraphEditor-BA1WbHI7.js} +188 -188
- package/dist/cdn/chunks/{ParagraphEditor-B6Ygu-Mq.js.map → ParagraphEditor-BA1WbHI7.js.map} +1 -1
- package/dist/cdn/chunks/{RichTextEditorContent-DL_y2SrR.js → RichTextEditorContent-BtWCA_Oc.js} +30 -30
- package/dist/cdn/chunks/{RichTextEditorContent-DL_y2SrR.js.map → RichTextEditorContent-BtWCA_Oc.js.map} +1 -1
- package/dist/cdn/chunks/{SaveModuleDialog-B0TnO_o9.js → SaveModuleDialog-AwL0tkCV.js} +21 -21
- package/dist/cdn/chunks/SaveModuleDialog-AwL0tkCV.js.map +1 -0
- package/dist/cdn/chunks/{TitleEditor-BHpfxvwy.js → TitleEditor-DbSyeixS.js} +65 -65
- package/dist/cdn/chunks/TitleEditor-DbSyeixS.js.map +1 -0
- package/dist/cdn/chunks/blockTypeIcons-pQIkxJzc.js +23 -0
- package/dist/cdn/chunks/blockTypeIcons-pQIkxJzc.js.map +1 -0
- package/dist/cdn/chunks/{de-D8CnZxV9.js → de-_tooy3Q8.js} +250 -2
- package/dist/cdn/chunks/de-_tooy3Q8.js.map +1 -0
- package/dist/cdn/chunks/{draggable-Bcb86AsV.js → draggable-C-1_gch3.js} +2 -2
- package/dist/cdn/chunks/{draggable-Bcb86AsV.js.map → draggable-C-1_gch3.js.map} +1 -1
- package/dist/cdn/chunks/{en-8FHaQv4V.js → en-CNqLoIm9.js} +250 -2
- package/dist/cdn/chunks/en-CNqLoIm9.js.map +1 -0
- package/dist/cdn/chunks/{extensions-DIxF31tA.js → extensions-BVKQw_sp.js} +107 -107
- package/dist/cdn/chunks/extensions-BVKQw_sp.js.map +1 -0
- package/dist/cdn/chunks/{features-DEMb13KS.js → features-DIBEo4xl.js} +3388 -2289
- package/dist/cdn/chunks/features-DIBEo4xl.js.map +1 -0
- package/dist/cdn/chunks/{icons-CsLTcirh.js → icons-C1Gg-ov-.js} +346 -54
- package/dist/cdn/chunks/icons-C1Gg-ov-.js.map +1 -0
- package/dist/cdn/chunks/{media-library-CVaNvhpM.js → media-library-BTF_Ko70.js} +985 -985
- package/dist/cdn/chunks/media-library-BTF_Ko70.js.map +1 -0
- package/dist/cdn/chunks/{quality-BaBfc54_.js → quality-C5AmotmP.js} +312 -312
- package/dist/cdn/chunks/quality-C5AmotmP.js.map +1 -0
- package/dist/cdn/chunks/{renderer-CUxvx7ro.js → renderer-D0L44Vlp.js} +236 -142
- package/dist/cdn/chunks/renderer-D0L44Vlp.js.map +1 -0
- package/dist/cdn/chunks/{src-CRaqN-p8.js → src-RKexlYjA.js} +161 -161
- package/dist/cdn/chunks/src-RKexlYjA.js.map +1 -0
- package/dist/cdn/chunks/styleConstants-PgmvNBzQ.js +57 -0
- package/dist/cdn/chunks/styleConstants-PgmvNBzQ.js.map +1 -0
- package/dist/cdn/chunks/styles-CQR6ed13.js +4976 -0
- package/dist/cdn/chunks/styles-CQR6ed13.js.map +1 -0
- package/dist/cdn/chunks/{tiptap-ZhwKyFp7.js → tiptap-CDzAbF2j.js} +43 -43
- package/dist/cdn/chunks/{tiptap-ZhwKyFp7.js.map → tiptap-CDzAbF2j.js.map} +1 -1
- package/dist/cdn/editor.css +1 -1
- package/dist/cdn/editor.js +211 -123
- package/dist/cdn/editor.js.map +1 -1
- package/dist/{check-Da05j8yl.js → check-DJrpDKO_.js} +1 -1
- package/dist/{chevron-down-R2uY34iD.js → chevron-down-C5oBUhT8.js} +1 -1
- package/dist/chevron-right-BqCptpdp.js +10 -0
- package/dist/{circle-alert-DZuGWPX-.js → circle-alert-ZQQc98HC.js} +1 -1
- package/dist/{clock-CRp2sIub.js → clock-ik2pRJKG.js} +1 -1
- package/dist/{cloud-DEk_b4CR.js → cloud-DJG4tb4_.js} +485 -427
- package/dist/{createLucideIcon-C3pa2siy.js → createLucideIcon-ClREiSx3.js} +6 -6
- package/dist/{de-Brqvgr43.js → de-2LEvILeZ.js} +249 -1
- package/dist/{dist-Cp0zXPAD.js → dist-BHAeXaUY.js} +1 -1
- package/dist/{dist-BaQIYPsn.js → dist-BSJvAvH3.js} +1 -1
- package/dist/{dist-wzMIGj-D.js → dist-BeFnymxK.js} +1 -1
- package/dist/dist-Bmir0gYb.js +1167 -0
- package/dist/{dist-DDJIWTRY.js → dist-BvPgo-UK.js} +1 -1
- package/dist/{dist-BFawx6IS.js → dist-CPVBKMmd.js} +51 -51
- package/dist/dist-CivF9P8b.js +382 -0
- package/dist/{dist-D6uC2xhi.js → dist-Df4ie7vZ.js} +1 -1
- package/dist/{dist-us-RpCWN.js → dist-DxOoemkW.js} +1 -1
- package/dist/{dist-KoBJjK1G.js → dist-HEQ52gTJ.js} +1 -1
- package/dist/{dist-DjviJBCi.js → dist-b-XUqAoF.js} +1 -1
- package/dist/{dist-D90y8dvT.js → dist-kZfaVUpW.js} +3 -3
- package/dist/{dist-aRzjfSRN.js → dist-wfAedlzi.js} +1 -1
- package/dist/{en-WDVp87TE.js → en-D2RU2Poj.js} +249 -1
- package/dist/{extensions-CUcl9Ok4.js → extensions-BQ1xXx3d.js} +103 -103
- package/dist/{image-up-MBZKKg9p.js → image-up-DT7gcJLN.js} +1 -1
- package/dist/index.d.ts +102 -14
- package/dist/{info-CJEC7piy.js → info-BSPGcsSM.js} +1 -1
- package/dist/keys-CvX8D-8C.js +10 -0
- package/dist/{loader-circle-DsY5Yg33.js → loader-circle-Balo8p3d.js} +1 -1
- package/dist/{message-circle-yElBbR2C.js → message-circle-B39qAHxs.js} +1 -1
- package/dist/pencil-BZJPNYWR.js +10 -0
- package/dist/{refresh-cw-CE_AGtn8.js → refresh-cw-DwDqGUM0.js} +1 -1
- package/dist/{scan-line-D0vcUekt.js → scan-line-DlghmhNf.js} +1 -1
- package/dist/{send-DH4oDQqC.js → send-DDdhIRj8.js} +1 -1
- package/dist/{shield-check-CfJgs2Hd.js → shield-check-OSQ-JVTX.js} +1 -1
- package/dist/{sparkles-CvRXGqFs.js → sparkles-BN4a-CoF.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/styleConstants-wWRbcuEK.js +55 -0
- package/dist/styles-CavWjvol.js +5487 -0
- package/dist/templatical-editor.js +211 -119
- package/dist/{text-align-start-BT9VUDxK.js → text-align-start-D1weisjS.js} +1 -1
- package/dist/{trash-2-DbP2Y6t2.js → trash-2-CMWvQ5KX.js} +1 -1
- package/dist/{triangle-alert-aOXceTSe.js → triangle-alert-DyidRNX_.js} +1 -1
- package/dist/undo-2-Cg8I7obC.js +16 -0
- package/dist/{useCloudI18n-BuIwR6OE.js → useCloudI18n-BTTNBk5i.js} +2 -2
- package/dist/{useEditorCore-C6ost42Q.js → useEditorCore-BGnzcT7p.js} +2424 -2249
- package/dist/{useI18n-lb2DHDiu.js → useI18n-C2xQZ6K9.js} +2 -2
- package/dist/{useMergeTag-CBwKnnNB.js → useMergeTag-CfuZq2fF.js} +4 -4
- package/dist/{vue.runtime.esm-bundler-DpvJL-nX.js → vue.runtime.esm-bundler-CjauPXjj.js} +1 -1
- package/dist/{x-u2oVmjN_.js → x-CgIhNcT9.js} +1 -1
- package/package.json +15 -15
- package/dist/CommentsSidebar-B1pvJdqF.js +0 -441
- package/dist/CountdownBlock-BNSj1jvJ.js +0 -92
- package/dist/CountdownToolbar-ClJr2GzL.js +0 -210
- package/dist/ModulePreviewCanvas-CHdOwV_4.js +0 -106
- package/dist/cdn/chunks/AiFeatureMenu-qEdB2fZJ.js.map +0 -1
- package/dist/cdn/chunks/CloudEditor-D2GsEC_n.js +0 -1143
- package/dist/cdn/chunks/CloudEditor-D2GsEC_n.js.map +0 -1
- package/dist/cdn/chunks/CollaboratorBar--nO7TX6b.js.map +0 -1
- package/dist/cdn/chunks/CountdownBlock-5YdT1uUu.js +0 -93
- package/dist/cdn/chunks/CountdownBlock-5YdT1uUu.js.map +0 -1
- package/dist/cdn/chunks/CountdownToolbar-DXPXrbAA.js +0 -212
- package/dist/cdn/chunks/CountdownToolbar-DXPXrbAA.js.map +0 -1
- package/dist/cdn/chunks/ModuleBrowserModal-DxoPp81s.js +0 -195
- package/dist/cdn/chunks/ModuleBrowserModal-DxoPp81s.js.map +0 -1
- package/dist/cdn/chunks/ModulePreviewCanvas-CoLdb4ar.js +0 -107
- package/dist/cdn/chunks/ModulePreviewCanvas-CoLdb4ar.js.map +0 -1
- package/dist/cdn/chunks/SaveModuleDialog-B0TnO_o9.js.map +0 -1
- package/dist/cdn/chunks/TitleEditor-BHpfxvwy.js.map +0 -1
- package/dist/cdn/chunks/blockTypeIcons-BzzY9_kA.js +0 -22
- package/dist/cdn/chunks/blockTypeIcons-BzzY9_kA.js.map +0 -1
- package/dist/cdn/chunks/de-D8CnZxV9.js.map +0 -1
- package/dist/cdn/chunks/en-8FHaQv4V.js.map +0 -1
- package/dist/cdn/chunks/extensions-DIxF31tA.js.map +0 -1
- package/dist/cdn/chunks/features-DEMb13KS.js.map +0 -1
- package/dist/cdn/chunks/icons-CsLTcirh.js.map +0 -1
- package/dist/cdn/chunks/media-library-CVaNvhpM.js.map +0 -1
- package/dist/cdn/chunks/quality-BaBfc54_.js.map +0 -1
- package/dist/cdn/chunks/renderer-CUxvx7ro.js.map +0 -1
- package/dist/cdn/chunks/src-CRaqN-p8.js.map +0 -1
- package/dist/cdn/chunks/styleConstants-DP1VOca8.js +0 -57
- package/dist/cdn/chunks/styleConstants-DP1VOca8.js.map +0 -1
- package/dist/cdn/chunks/styles-BHJULjNR.js +0 -2947
- package/dist/cdn/chunks/styles-BHJULjNR.js.map +0 -1
- package/dist/dist-B1IR0bpH.js +0 -326
- package/dist/dist-DJmnUmW9.js +0 -362
- package/dist/keys-ciNfSSGj.js +0 -10
- package/dist/styleConstants-fWzlIIwN.js +0 -55
- package/dist/styles-DEXEkBvg.js +0 -3176
- /package/dist/{_plugin-vue_export-helper-B0hnzhyu.js → _plugin-vue_export-helper-Bwh4ceeO.js} +0 -0
- /package/dist/{de-DCaaCE5s.js → de-D2npYjrZ.js} +0 -0
- /package/dist/{dist-iLBdeBDR.js → dist-DvHLtWVP.js} +0 -0
- /package/dist/{emojiData-PQyVa4bU.js → emojiData-DvQBBzmO.js} +0 -0
- /package/dist/{en-DXCyK4-X.js → en-ib-4h3_o.js} +0 -0
- /package/dist/{formatRelativeTime-BOEf47hq.js → formatRelativeTime-CFDZnEIs.js} +0 -0
- /package/dist/{liquid.browser-CdMv1BTn.js → liquid.browser-7Rv0QDiO.js} +0 -0
- /package/dist/{readableTextColor-CY3SiRnt.js → readableTextColor-C_9OpzBw.js} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ModulePreviewCanvas-CoLdb4ar.js","names":[],"sources":["../../../src/components/blocks/PreviewSectionBlock.vue","../../../src/components/blocks/PreviewSectionBlock.vue","../../../src/cloud/components/ModulePreviewCanvas.vue","../../../src/cloud/components/ModulePreviewCanvas.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ButtonBlock from \"./ButtonBlock.vue\";\nimport CustomBlock from \"./CustomBlock.vue\";\nimport DividerBlock from \"./DividerBlock.vue\";\nimport HtmlBlock from \"./HtmlBlock.vue\";\nimport ImageBlock from \"./ImageBlock.vue\";\nimport MenuBlock from \"./MenuBlock.vue\";\nimport SocialIconsBlock from \"./SocialIconsBlock.vue\";\nimport SpacerBlock from \"./SpacerBlock.vue\";\nimport TableBlock from \"./TableBlock.vue\";\nimport TitleBlock from \"./TitleBlock.vue\";\nimport ParagraphBlock from \"./ParagraphBlock.vue\";\nimport VideoBlock from \"./VideoBlock.vue\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n} from \"../../utils/blockComponentResolver\";\nimport type {\n Block,\n SectionBlock as SectionBlockType,\n} from \"@templatical/types\";\nimport { computed, inject, type Component } from \"vue\";\nimport { BLOCK_REGISTRY_KEY } from \"../../keys\";\n\nconst previewBlockComponentMap: Record<string, Component> = {\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n};\n\nconst props = defineProps<{\n block: SectionBlockType;\n viewport: \"desktop\";\n}>();\n\ndefineOptions({ name: \"PreviewSectionBlock\" });\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY, null);\n\nconst columnWidths = computed(() => {\n switch (props.block.columns) {\n case \"2\":\n return [\"50%\", \"50%\"];\n case \"3\":\n return [\"33.33%\", \"33.33%\", \"33.33%\"];\n case \"1-2\":\n return [\"33.33%\", \"66.67%\"];\n case \"2-1\":\n return [\"66.67%\", \"33.33%\"];\n default:\n return [\"100%\"];\n }\n});\n\nconst columns = computed(() => {\n const count = columnWidths.value.length;\n const children = [...props.block.children];\n while (children.length < count) {\n children.push([]);\n }\n return children.slice(0, count);\n});\n\nfunction getColumnBlocks(colIndex: number): Block[] {\n return columns.value[colIndex] || [];\n}\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, previewBlockComponentMap);\n}\n</script>\n\n<template>\n <div class=\"tpl:w-full\">\n <div class=\"tpl:flex tpl:gap-0\">\n <div\n v-for=\"(_, colIndex) in columns\"\n :key=\"colIndex\"\n :style=\"{ width: columnWidths[colIndex] }\"\n >\n <div\n v-for=\"childBlock in getColumnBlocks(colIndex)\"\n :key=\"childBlock.id\"\n :style=\"getBlockWrapperStyle(childBlock)\"\n >\n <!-- Recursive self-reference for nested sections -->\n <PreviewSectionBlock\n v-if=\"childBlock.type === 'section'\"\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n <component\n :is=\"getBlockComponent(childBlock)\"\n v-else\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ButtonBlock from \"./ButtonBlock.vue\";\nimport CustomBlock from \"./CustomBlock.vue\";\nimport DividerBlock from \"./DividerBlock.vue\";\nimport HtmlBlock from \"./HtmlBlock.vue\";\nimport ImageBlock from \"./ImageBlock.vue\";\nimport MenuBlock from \"./MenuBlock.vue\";\nimport SocialIconsBlock from \"./SocialIconsBlock.vue\";\nimport SpacerBlock from \"./SpacerBlock.vue\";\nimport TableBlock from \"./TableBlock.vue\";\nimport TitleBlock from \"./TitleBlock.vue\";\nimport ParagraphBlock from \"./ParagraphBlock.vue\";\nimport VideoBlock from \"./VideoBlock.vue\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n} from \"../../utils/blockComponentResolver\";\nimport type {\n Block,\n SectionBlock as SectionBlockType,\n} from \"@templatical/types\";\nimport { computed, inject, type Component } from \"vue\";\nimport { BLOCK_REGISTRY_KEY } from \"../../keys\";\n\nconst previewBlockComponentMap: Record<string, Component> = {\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n};\n\nconst props = defineProps<{\n block: SectionBlockType;\n viewport: \"desktop\";\n}>();\n\ndefineOptions({ name: \"PreviewSectionBlock\" });\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY, null);\n\nconst columnWidths = computed(() => {\n switch (props.block.columns) {\n case \"2\":\n return [\"50%\", \"50%\"];\n case \"3\":\n return [\"33.33%\", \"33.33%\", \"33.33%\"];\n case \"1-2\":\n return [\"33.33%\", \"66.67%\"];\n case \"2-1\":\n return [\"66.67%\", \"33.33%\"];\n default:\n return [\"100%\"];\n }\n});\n\nconst columns = computed(() => {\n const count = columnWidths.value.length;\n const children = [...props.block.children];\n while (children.length < count) {\n children.push([]);\n }\n return children.slice(0, count);\n});\n\nfunction getColumnBlocks(colIndex: number): Block[] {\n return columns.value[colIndex] || [];\n}\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, previewBlockComponentMap);\n}\n</script>\n\n<template>\n <div class=\"tpl:w-full\">\n <div class=\"tpl:flex tpl:gap-0\">\n <div\n v-for=\"(_, colIndex) in columns\"\n :key=\"colIndex\"\n :style=\"{ width: columnWidths[colIndex] }\"\n >\n <div\n v-for=\"childBlock in getColumnBlocks(colIndex)\"\n :key=\"childBlock.id\"\n :style=\"getBlockWrapperStyle(childBlock)\"\n >\n <!-- Recursive self-reference for nested sections -->\n <PreviewSectionBlock\n v-if=\"childBlock.type === 'section'\"\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n <component\n :is=\"getBlockComponent(childBlock)\"\n v-else\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ButtonBlock from \"../../components/blocks/ButtonBlock.vue\";\nimport CustomBlock from \"../../components/blocks/CustomBlock.vue\";\nimport DividerBlock from \"../../components/blocks/DividerBlock.vue\";\nimport HtmlBlock from \"../../components/blocks/HtmlBlock.vue\";\nimport ImageBlock from \"../../components/blocks/ImageBlock.vue\";\nimport MenuBlock from \"../../components/blocks/MenuBlock.vue\";\nimport PreviewSectionBlock from \"../../components/blocks/PreviewSectionBlock.vue\";\nimport SocialIconsBlock from \"../../components/blocks/SocialIconsBlock.vue\";\nimport SpacerBlock from \"../../components/blocks/SpacerBlock.vue\";\nimport TableBlock from \"../../components/blocks/TableBlock.vue\";\nimport TitleBlock from \"../../components/blocks/TitleBlock.vue\";\nimport ParagraphBlock from \"../../components/blocks/ParagraphBlock.vue\";\nimport VideoBlock from \"../../components/blocks/VideoBlock.vue\";\nimport { BLOCK_REGISTRY_KEY } from \"../../keys\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n} from \"../../utils/blockComponentResolver\";\nimport type { Block } from \"@templatical/types\";\nimport { inject, type Component } from \"vue\";\n\ndefineProps<{\n blocks: Block[];\n}>();\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY);\n\nconst modulePreviewComponentMap: Record<string, Component> = {\n section: PreviewSectionBlock,\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n};\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, modulePreviewComponentMap);\n}\n</script>\n\n<template>\n <div\n class=\"tpl:pointer-events-none tpl:mx-auto tpl:w-[600px] tpl:select-none tpl:rounded-lg\"\n style=\"\n background-color: var(--tpl-canvas-bg);\n box-shadow: var(--tpl-shadow-sm);\n \"\n >\n <div\n v-for=\"block in blocks\"\n :key=\"block.id\"\n :style=\"getBlockWrapperStyle(block)\"\n >\n <component\n :is=\"getBlockComponent(block)\"\n :block=\"block\"\n viewport=\"desktop\"\n />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ButtonBlock from \"../../components/blocks/ButtonBlock.vue\";\nimport CustomBlock from \"../../components/blocks/CustomBlock.vue\";\nimport DividerBlock from \"../../components/blocks/DividerBlock.vue\";\nimport HtmlBlock from \"../../components/blocks/HtmlBlock.vue\";\nimport ImageBlock from \"../../components/blocks/ImageBlock.vue\";\nimport MenuBlock from \"../../components/blocks/MenuBlock.vue\";\nimport PreviewSectionBlock from \"../../components/blocks/PreviewSectionBlock.vue\";\nimport SocialIconsBlock from \"../../components/blocks/SocialIconsBlock.vue\";\nimport SpacerBlock from \"../../components/blocks/SpacerBlock.vue\";\nimport TableBlock from \"../../components/blocks/TableBlock.vue\";\nimport TitleBlock from \"../../components/blocks/TitleBlock.vue\";\nimport ParagraphBlock from \"../../components/blocks/ParagraphBlock.vue\";\nimport VideoBlock from \"../../components/blocks/VideoBlock.vue\";\nimport { BLOCK_REGISTRY_KEY } from \"../../keys\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n} from \"../../utils/blockComponentResolver\";\nimport type { Block } from \"@templatical/types\";\nimport { inject, type Component } from \"vue\";\n\ndefineProps<{\n blocks: Block[];\n}>();\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY);\n\nconst modulePreviewComponentMap: Record<string, Component> = {\n section: PreviewSectionBlock,\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n};\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, modulePreviewComponentMap);\n}\n</script>\n\n<template>\n <div\n class=\"tpl:pointer-events-none tpl:mx-auto tpl:w-[600px] tpl:select-none tpl:rounded-lg\"\n style=\"\n background-color: var(--tpl-canvas-bg);\n box-shadow: var(--tpl-shadow-sm);\n \"\n >\n <div\n v-for=\"block in blocks\"\n :key=\"block.id\"\n :style=\"getBlockWrapperStyle(block)\"\n >\n <component\n :is=\"getBlockComponent(block)\"\n :block=\"block\"\n viewport=\"desktop\"\n />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;EAwBA,IAAM,IAAsD;GAC1D,OAAO;GACP,WAAW;GACX,OAAO;GACP,OAAO;GACP,QAAQ;GACR,SAAS;GACT,QAAQ;GACR,MAAM;GACN,OAAO;GACP,QAAQ;GACR,MAAM;GACN,QAAQ;GACT,EAEK,IAAQ,GAOR,IAAgB,EAAO,GAAoB,KAAK,EAEhD,IAAe,QAAe;AAClC,WAAQ,EAAM,MAAM,SAApB;IACE,KAAK,IACH,QAAO,CAAC,OAAO,MAAM;IACvB,KAAK,IACH,QAAO;KAAC;KAAU;KAAU;KAAS;IACvC,KAAK,MACH,QAAO,CAAC,UAAU,SAAS;IAC7B,KAAK,MACH,QAAO,CAAC,UAAU,SAAS;IAC7B,QACE,QAAO,CAAC,OAAO;;IAEnB,EAEI,IAAU,QAAe;GAC7B,IAAM,IAAQ,EAAa,MAAM,QAC3B,IAAW,CAAC,GAAG,EAAM,MAAM,SAAS;AAC1C,UAAO,EAAS,SAAS,GACvB,GAAS,KAAK,EAAE,CAAC;AAEnB,UAAO,EAAS,MAAM,GAAG,EAAM;IAC/B;EAEF,SAAS,EAAgB,GAA2B;AAClD,UAAO,EAAQ,MAAM,MAAa,EAAE;;EAGtC,SAAS,EAAkB,GAAgC;AACzD,UAAO,EAAsB,GAAO,GAAe,EAAyB;;;;eAK5E,EA2BM,OA3BN,GA2BM,CA1BJ,EAyBM,OAzBN,GAyBM,EAAA,EAAA,GAAA,EAxBJ,EAuBM,GAAA,MAAA,EAtBoB,EAAA,QAAhB,GAAG,YADb,EAuBM,OAAA;IArBH,KAAK;IACL,OAAK,EAAA,EAAA,OAAW,EAAA,MAAa,IAAQ,CAAA;eAEtC,EAiBM,GAAA,MAAA,EAhBiB,EAAgB,EAAQ,GAAtC,YADT,EAiBM,OAAA;IAfH,KAAK,EAAW;IAChB,OAAK,EAAE,EAAA,EAAoB,CAAC,EAAU,CAAA;OAI/B,EAAW,SAAI,aAAA,GAAA,EADvB,EAIE,GAAA;;IAFC,OAAO;IACR,UAAS;mCAEX,EAKE,EAJK,EAAkB,EAAU,CAAA,EAAA;;IAEhC,OAAO;IACR,UAAS;;;;;;;;;;;;;;EE9ErB,IAAM,IAAgB,EAAO,EAAmB,EAE1C,IAAuD;GAC3D,SAAS;GACT,OAAO;GACP,WAAW;GACX,OAAO;GACP,OAAO;GACP,QAAQ;GACR,SAAS;GACT,QAAQ;GACR,MAAM;GACN,OAAO;GACP,QAAQ;GACR,MAAM;GACN,QAAQ;GACT;EAED,SAAS,EAAkB,GAAgC;AACzD,UAAO,EAAsB,GAAO,GAAe,EAA0B;;yBAK7E,EAkBM,OAlBN,GAkBM,EAAA,EAAA,GAAA,EAXJ,EAUM,GAAA,MAAA,EATY,EAAA,SAAT,YADT,EAUM,OAAA;GARH,KAAK,EAAM;GACX,OAAK,EAAE,EAAA,EAAoB,CAAC,EAAK,CAAA;YAElC,EAIE,EAHK,EAAkB,EAAK,CAAA,EAAA;GACpB;GACR,UAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SaveModuleDialog-B0TnO_o9.js","names":[],"sources":["../../../src/cloud/components/SaveModuleDialog.vue","../../../src/cloud/components/SaveModuleDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport TplModal from \"./TplModal.vue\";\nimport { useI18n } from \"../../composables\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport {\n EDITOR_KEY,\n SAVED_MODULES_HEADLESS_KEY,\n requireInject,\n} from \"../../keys\";\nimport type { Block } from \"@templatical/types\";\nimport { LoaderCircle } from \"@lucide/vue\";\nimport { computed, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n preSelectedBlockId: string | null;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n (e: \"saved\"): void;\n}>();\n\nconst { t } = useI18n();\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"SaveModuleDialog\");\nconst savedModules = requireInject(\n SAVED_MODULES_HEADLESS_KEY,\n \"SaveModuleDialog\",\n);\n\nconst moduleName = ref(\"\");\nconst selectedBlockIds = ref<Set<string>>(new Set());\nconst isSaving = ref(false);\nconst error = ref<string | null>(null);\n\nconst topLevelBlocks = computed(() => editor.content.value.blocks);\n\nfunction blockLabel(block: Block, index: number): string {\n const typeKey = block.type as keyof typeof t.blocks;\n const label = t.blocks[typeKey] ?? block.type;\n return `${label} ${index + 1}`;\n}\n\nwatch(\n () => props.visible,\n (visible) => {\n if (visible) {\n moduleName.value = \"\";\n error.value = null;\n selectedBlockIds.value = new Set(\n props.preSelectedBlockId ? [props.preSelectedBlockId] : [],\n );\n }\n },\n);\n\nfunction toggleBlock(blockId: string): void {\n const newSet = new Set(selectedBlockIds.value);\n if (newSet.has(blockId)) {\n newSet.delete(blockId);\n } else {\n newSet.add(blockId);\n }\n selectedBlockIds.value = newSet;\n}\n\nconst canSave = computed(\n () =>\n moduleName.value.trim().length > 0 &&\n selectedBlockIds.value.size > 0 &&\n !isSaving.value,\n);\n\nasync function handleSave(): Promise<void> {\n if (!canSave.value) return;\n\n isSaving.value = true;\n error.value = null;\n\n try {\n const selectedBlocks = topLevelBlocks.value.filter((b) =>\n selectedBlockIds.value.has(b.id),\n );\n await savedModules.createModule(moduleName.value.trim(), selectedBlocks);\n emit(\"saved\");\n emit(\"close\");\n } catch (err) {\n error.value = (err as Error).message;\n } finally {\n isSaving.value = false;\n }\n}\n\nfunction handleClose(): void {\n if (!isSaving.value) {\n emit(\"close\");\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSave();\n }\n if (event.key === \"Escape\") {\n handleClose();\n }\n}\n</script>\n\n<template>\n <TplModal :visible=\"visible\" @close=\"handleClose\" @keydown=\"handleKeydown\">\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-busy=\"isSaving\"\n aria-labelledby=\"tpl-save-module-title\"\n class=\"tpl-scale-in tpl:mx-4 tpl:w-full tpl:max-w-sm tpl:rounded-[var(--tpl-radius-lg)] tpl:p-5\"\n style=\"\n background-color: var(--tpl-bg-elevated);\n box-shadow: var(--tpl-shadow-xl);\n \"\n >\n <h3\n id=\"tpl-save-module-title\"\n class=\"tpl:mb-4 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.modules.saveAsModule }}\n </h3>\n\n <!-- Module name -->\n <div class=\"tpl:mb-3\">\n <label\n class=\"tpl:mb-1.5 tpl:block tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.modules.moduleName }}\n </label>\n <input\n v-model=\"moduleName\"\n type=\"text\"\n :placeholder=\"cloudT.modules.moduleNamePlaceholder\"\n class=\"tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1 tpl:text-sm tpl:shadow-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n :disabled=\"isSaving\"\n />\n </div>\n\n <!-- Block selection -->\n <div class=\"tpl:mb-3\">\n <label\n class=\"tpl:mb-1.5 tpl:block tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.modules.selectBlocks }}\n </label>\n <div\n class=\"tpl:max-h-40 tpl:space-y-1 tpl:overflow-y-auto tpl:rounded-md tpl:border tpl:p-2 tpl:border-[var(--tpl-border)]\"\n >\n <label\n v-for=\"(block, index) in topLevelBlocks\"\n :key=\"block.id\"\n class=\"tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:rounded-sm tpl:px-2 tpl:py-1.5 tpl:text-sm tpl:transition-colors tpl:duration-100\"\n :style=\"{\n color: 'var(--tpl-text)',\n backgroundColor: selectedBlockIds.has(block.id)\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n >\n <input\n type=\"checkbox\"\n :checked=\"selectedBlockIds.has(block.id)\"\n class=\"tpl:accent-[var(--tpl-primary)]\"\n :disabled=\"isSaving\"\n @change=\"toggleBlock(block.id)\"\n />\n {{ blockLabel(block, index) }}\n </label>\n </div>\n </div>\n\n <!-- Error message -->\n <p\n v-if=\"error\"\n role=\"alert\"\n class=\"tpl:mb-3 tpl:text-xs tpl:text-[var(--tpl-danger)]\"\n >\n {{ error }}\n </p>\n\n <!-- Actions -->\n <div class=\"tpl:flex tpl:justify-end tpl:gap-2\">\n <button\n type=\"button\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)]\"\n :disabled=\"isSaving\"\n :class=\"{\n 'tpl:cursor-not-allowed tpl:opacity-50': isSaving,\n }\"\n @click=\"handleClose\"\n >\n {{ cloudT.modules.cancel }}\n </button>\n <button\n type=\"button\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:disabled:cursor-not-allowed tpl:disabled:opacity-50 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]\"\n :disabled=\"!canSave\"\n @click=\"handleSave\"\n >\n <span v-if=\"isSaving\" class=\"tpl:flex tpl:items-center tpl:gap-1.5\">\n <LoaderCircle\n class=\"tpl:animate-spin\"\n :size=\"12\"\n :stroke-width=\"2\"\n />\n {{ cloudT.modules.saving }}\n </span>\n <span v-else>\n {{ cloudT.modules.save }}\n </span>\n </button>\n </div>\n </div>\n </TplModal>\n</template>\n","<script setup lang=\"ts\">\nimport TplModal from \"./TplModal.vue\";\nimport { useI18n } from \"../../composables\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport {\n EDITOR_KEY,\n SAVED_MODULES_HEADLESS_KEY,\n requireInject,\n} from \"../../keys\";\nimport type { Block } from \"@templatical/types\";\nimport { LoaderCircle } from \"@lucide/vue\";\nimport { computed, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n preSelectedBlockId: string | null;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n (e: \"saved\"): void;\n}>();\n\nconst { t } = useI18n();\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"SaveModuleDialog\");\nconst savedModules = requireInject(\n SAVED_MODULES_HEADLESS_KEY,\n \"SaveModuleDialog\",\n);\n\nconst moduleName = ref(\"\");\nconst selectedBlockIds = ref<Set<string>>(new Set());\nconst isSaving = ref(false);\nconst error = ref<string | null>(null);\n\nconst topLevelBlocks = computed(() => editor.content.value.blocks);\n\nfunction blockLabel(block: Block, index: number): string {\n const typeKey = block.type as keyof typeof t.blocks;\n const label = t.blocks[typeKey] ?? block.type;\n return `${label} ${index + 1}`;\n}\n\nwatch(\n () => props.visible,\n (visible) => {\n if (visible) {\n moduleName.value = \"\";\n error.value = null;\n selectedBlockIds.value = new Set(\n props.preSelectedBlockId ? [props.preSelectedBlockId] : [],\n );\n }\n },\n);\n\nfunction toggleBlock(blockId: string): void {\n const newSet = new Set(selectedBlockIds.value);\n if (newSet.has(blockId)) {\n newSet.delete(blockId);\n } else {\n newSet.add(blockId);\n }\n selectedBlockIds.value = newSet;\n}\n\nconst canSave = computed(\n () =>\n moduleName.value.trim().length > 0 &&\n selectedBlockIds.value.size > 0 &&\n !isSaving.value,\n);\n\nasync function handleSave(): Promise<void> {\n if (!canSave.value) return;\n\n isSaving.value = true;\n error.value = null;\n\n try {\n const selectedBlocks = topLevelBlocks.value.filter((b) =>\n selectedBlockIds.value.has(b.id),\n );\n await savedModules.createModule(moduleName.value.trim(), selectedBlocks);\n emit(\"saved\");\n emit(\"close\");\n } catch (err) {\n error.value = (err as Error).message;\n } finally {\n isSaving.value = false;\n }\n}\n\nfunction handleClose(): void {\n if (!isSaving.value) {\n emit(\"close\");\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSave();\n }\n if (event.key === \"Escape\") {\n handleClose();\n }\n}\n</script>\n\n<template>\n <TplModal :visible=\"visible\" @close=\"handleClose\" @keydown=\"handleKeydown\">\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-busy=\"isSaving\"\n aria-labelledby=\"tpl-save-module-title\"\n class=\"tpl-scale-in tpl:mx-4 tpl:w-full tpl:max-w-sm tpl:rounded-[var(--tpl-radius-lg)] tpl:p-5\"\n style=\"\n background-color: var(--tpl-bg-elevated);\n box-shadow: var(--tpl-shadow-xl);\n \"\n >\n <h3\n id=\"tpl-save-module-title\"\n class=\"tpl:mb-4 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.modules.saveAsModule }}\n </h3>\n\n <!-- Module name -->\n <div class=\"tpl:mb-3\">\n <label\n class=\"tpl:mb-1.5 tpl:block tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.modules.moduleName }}\n </label>\n <input\n v-model=\"moduleName\"\n type=\"text\"\n :placeholder=\"cloudT.modules.moduleNamePlaceholder\"\n class=\"tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1 tpl:text-sm tpl:shadow-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n :disabled=\"isSaving\"\n />\n </div>\n\n <!-- Block selection -->\n <div class=\"tpl:mb-3\">\n <label\n class=\"tpl:mb-1.5 tpl:block tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.modules.selectBlocks }}\n </label>\n <div\n class=\"tpl:max-h-40 tpl:space-y-1 tpl:overflow-y-auto tpl:rounded-md tpl:border tpl:p-2 tpl:border-[var(--tpl-border)]\"\n >\n <label\n v-for=\"(block, index) in topLevelBlocks\"\n :key=\"block.id\"\n class=\"tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:rounded-sm tpl:px-2 tpl:py-1.5 tpl:text-sm tpl:transition-colors tpl:duration-100\"\n :style=\"{\n color: 'var(--tpl-text)',\n backgroundColor: selectedBlockIds.has(block.id)\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n >\n <input\n type=\"checkbox\"\n :checked=\"selectedBlockIds.has(block.id)\"\n class=\"tpl:accent-[var(--tpl-primary)]\"\n :disabled=\"isSaving\"\n @change=\"toggleBlock(block.id)\"\n />\n {{ blockLabel(block, index) }}\n </label>\n </div>\n </div>\n\n <!-- Error message -->\n <p\n v-if=\"error\"\n role=\"alert\"\n class=\"tpl:mb-3 tpl:text-xs tpl:text-[var(--tpl-danger)]\"\n >\n {{ error }}\n </p>\n\n <!-- Actions -->\n <div class=\"tpl:flex tpl:justify-end tpl:gap-2\">\n <button\n type=\"button\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)]\"\n :disabled=\"isSaving\"\n :class=\"{\n 'tpl:cursor-not-allowed tpl:opacity-50': isSaving,\n }\"\n @click=\"handleClose\"\n >\n {{ cloudT.modules.cancel }}\n </button>\n <button\n type=\"button\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:disabled:cursor-not-allowed tpl:disabled:opacity-50 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]\"\n :disabled=\"!canSave\"\n @click=\"handleSave\"\n >\n <span v-if=\"isSaving\" class=\"tpl:flex tpl:items-center tpl:gap-1.5\">\n <LoaderCircle\n class=\"tpl:animate-spin\"\n :size=\"12\"\n :stroke-width=\"2\"\n />\n {{ cloudT.modules.saving }}\n </span>\n <span v-else>\n {{ cloudT.modules.save }}\n </span>\n </button>\n </div>\n </div>\n </TplModal>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TitleEditor-BHpfxvwy.js","names":[],"sources":["../../../src/components/blocks/TitleEditor.vue","../../../src/components/blocks/TitleEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useI18n } from \"../../composables\";\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport type { TitleBlock as TitleBlockType } from \"@templatical/types\";\nimport { Bold, Italic, Link, LoaderCircle, ScanLine } from \"@lucide/vue\";\nimport { inject } from \"vue\";\nimport { THEME_STYLES_KEY, UI_THEME_KEY } from \"../../keys\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\n\nconst props = defineProps<{\n block: TitleBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\n\nconst { t } = useI18n();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkDialogRef,\n canRequestMergeTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"TitleEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { MergeTagNode, MergeTagSuggestion, LogicMergeTagNode },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n strike: false,\n }),\n LinkExt.configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <Teleport to=\"body\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.titleEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:fixed tpl:z-popover tpl:flex tpl:items-center tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Bold -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('bold'),\n }\"\n :aria-label=\"t.titleEditor.bold\"\n :title=\"t.titleEditor.bold\"\n @click=\"editor?.chain().focus().toggleBold().run()\"\n >\n <Bold :size=\"16\" :stroke-width=\"2.5\" />\n </button>\n <!-- Italic -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('italic'),\n }\"\n :aria-label=\"t.titleEditor.italic\"\n :title=\"t.titleEditor.italic\"\n @click=\"editor?.chain().focus().toggleItalic().run()\"\n >\n <Italic :size=\"16\" :stroke-width=\"2\" />\n </button>\n <span\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n <!-- Link -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('link'),\n }\"\n :aria-label=\"t.titleEditor.addLink\"\n :title=\"t.titleEditor.addLink\"\n @click=\"openLinkDialog\"\n >\n <Link :size=\"16\" :stroke-width=\"2\" />\n </button>\n <!-- Add Merge Tag -->\n <span\n v-if=\"canRequestMergeTag\"\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n ></span>\n <button\n v-if=\"canRequestMergeTag\"\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.add\"\n :title=\"t.mergeTag.add\"\n @click=\"handleAddMergeTag\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.add }}\n </button>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../../composables\";\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport type { TitleBlock as TitleBlockType } from \"@templatical/types\";\nimport { Bold, Italic, Link, LoaderCircle, ScanLine } from \"@lucide/vue\";\nimport { inject } from \"vue\";\nimport { THEME_STYLES_KEY, UI_THEME_KEY } from \"../../keys\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\n\nconst props = defineProps<{\n block: TitleBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\n\nconst { t } = useI18n();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkDialogRef,\n canRequestMergeTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"TitleEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { MergeTagNode, MergeTagSuggestion, LogicMergeTagNode },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n strike: false,\n }),\n LinkExt.configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <Teleport to=\"body\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.titleEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:fixed tpl:z-popover tpl:flex tpl:items-center tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Bold -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('bold'),\n }\"\n :aria-label=\"t.titleEditor.bold\"\n :title=\"t.titleEditor.bold\"\n @click=\"editor?.chain().focus().toggleBold().run()\"\n >\n <Bold :size=\"16\" :stroke-width=\"2.5\" />\n </button>\n <!-- Italic -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('italic'),\n }\"\n :aria-label=\"t.titleEditor.italic\"\n :title=\"t.titleEditor.italic\"\n @click=\"editor?.chain().focus().toggleItalic().run()\"\n >\n <Italic :size=\"16\" :stroke-width=\"2\" />\n </button>\n <span\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n <!-- Link -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('link'),\n }\"\n :aria-label=\"t.titleEditor.addLink\"\n :title=\"t.titleEditor.addLink\"\n @click=\"openLinkDialog\"\n >\n <Link :size=\"16\" :stroke-width=\"2\" />\n </button>\n <!-- Add Merge Tag -->\n <span\n v-if=\"canRequestMergeTag\"\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n ></span>\n <button\n v-if=\"canRequestMergeTag\"\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.add\"\n :title=\"t.mergeTag.add\"\n @click=\"handleAddMergeTag\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.add }}\n </button>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Ct as e, mt as t, st as n, ut as r, vt as i } from "./features-DEMb13KS.js";
|
|
2
|
-
import { D as a, F as o, J as s, M as c, O as l, T as u, U as d, a as f } from "./icons-CsLTcirh.js";
|
|
3
|
-
//#region src/utils/blockTypeIcons.ts
|
|
4
|
-
var p = {
|
|
5
|
-
section: s,
|
|
6
|
-
title: d,
|
|
7
|
-
paragraph: l,
|
|
8
|
-
image: i,
|
|
9
|
-
button: u,
|
|
10
|
-
divider: o,
|
|
11
|
-
video: a,
|
|
12
|
-
social: r,
|
|
13
|
-
menu: t,
|
|
14
|
-
table: n,
|
|
15
|
-
spacer: c,
|
|
16
|
-
countdown: f,
|
|
17
|
-
html: e
|
|
18
|
-
};
|
|
19
|
-
//#endregion
|
|
20
|
-
export { p as t };
|
|
21
|
-
|
|
22
|
-
//# sourceMappingURL=blockTypeIcons-BzzY9_kA.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blockTypeIcons-BzzY9_kA.js","names":[],"sources":["../../../src/utils/blockTypeIcons.ts"],"sourcesContent":["import {\n Code,\n Columns3,\n Heading,\n Image,\n Minus,\n MoveVertical,\n Navigation,\n Pilcrow,\n Play,\n RectangleHorizontal,\n Share2,\n Table,\n Timer,\n} from \"@lucide/vue\";\nimport type { Component } from \"vue\";\n\nexport const blockTypeIcons: Record<string, Component> = {\n section: Columns3,\n title: Heading,\n paragraph: Pilcrow,\n image: Image,\n button: RectangleHorizontal,\n divider: Minus,\n video: Play,\n social: Share2,\n menu: Navigation,\n table: Table,\n spacer: MoveVertical,\n countdown: Timer,\n html: Code,\n};\n"],"mappings":";;;AAiBA,IAAa,IAA4C;CACvD,SAAS;CACT,OAAO;CACP,WAAW;CACX,OAAO;CACP,QAAQ;CACR,SAAS;CACT,OAAO;CACP,QAAQ;CACR,MAAM;CACN,OAAO;CACP,QAAQ;CACR,WAAW;CACX,MAAM;CACP"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"de-D8CnZxV9.js","names":[],"sources":["../../../src/i18n/locales/de.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst de: typeof en = {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Erstellt mit\",\n openSource: \"Open Source\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Rückgängig\",\n redo: \"Wiederholen\",\n collabWarning:\n \"Rückgängig machen kann die Änderungen anderer Mitarbeiter beeinflussen\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Ansichtsgröße\",\n desktop: \"Desktop\",\n tablet: \"Tablet\",\n mobile: \"Mobil\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Dunkelmodus-Vorschau\",\n disable: \"Hellmodus-Vorschau\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Vorschaumodus\",\n disable: \"Vorschau beenden\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Abschnitt\",\n image: \"Bild\",\n title: \"Titel\",\n paragraph: \"Absatz\",\n button: \"Schaltfläche\",\n divider: \"Trennlinie\",\n video: \"Video\",\n social: \"Sozial\",\n spacer: \"Abstand\",\n html: \"HTML\",\n menu: \"Menü\",\n table: \"Tabelle\",\n countdown: \"Countdown\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Inhalt\",\n settings: \"Einstellungen\",\n noSelection: \"Kein Element ausgewählt\",\n noSelectionHint:\n \"Wählen Sie einen Block auf der Leinwand aus, um ihn zu bearbeiten\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplizieren\",\n delete: \"Löschen\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Titelformatierung\",\n bold: \"Fett (Strg+B)\",\n italic: \"Kursiv (Strg+I)\",\n addLink: \"Link hinzufügen\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Textformatierung\",\n bold: \"Fett (Strg+B)\",\n italic: \"Kursiv (Strg+I)\",\n underline: \"Unterstrichen (Strg+U)\",\n strikethrough: \"Durchgestrichen\",\n subscript: \"Tiefgestellt\",\n superscript: \"Hochgestellt\",\n addLink: \"Link hinzufügen\",\n bulletList: \"Aufzählungsliste\",\n numberedList: \"Nummerierte Liste\",\n alignLeft: \"Linksbündig\",\n alignCenter: \"Zentriert\",\n alignRight: \"Rechtsbündig\",\n clearFormatting: \"Formatierung entfernen\",\n insertEmoji: \"Emoji einfügen\",\n fontFamily: \"Schriftart\",\n defaultFont: \"Standard\",\n fontSize: \"Schriftgröße\",\n defaultSize: \"Standard\",\n textColor: \"Textfarbe\",\n highlightColor: \"Hervorhebungsfarbe\",\n lineHeight: \"Zeilenhöhe\",\n letterSpacing: \"Zeichenabstand\",\n emojiItemLabel: \"Emoji {emoji} einfügen\",\n closeEmojiPicker: \"Emoji-Auswahl schließen\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Zum Sortieren ziehen oder Leertaste drücken, um mit der Tastatur zu verschieben\",\n dragLifted:\n \"{block} wird verschoben. Pfeiltasten zum Positionieren, Leer- oder Eingabetaste zum Ablegen, Esc zum Abbrechen.\",\n duplicate: \"Block duplizieren\",\n delete: \"Block löschen\",\n hiddenOnViewport: \"Ausgeblendet auf {viewport}\",\n saveAsModule: \"Als Modul speichern\",\n conditionToggle: \"Anzeigebedingung umschalten\",\n comments: \"Kommentare ({count})\",\n lifted: \"{block} angehoben. Position {position} von {total}.\",\n moved: \"{block} auf Position {position} von {total} verschoben.\",\n dropped: \"{block} auf Position {position} von {total} abgelegt.\",\n cancelled:\n \"Verschieben abgebrochen. {block} auf Position {position} zurückgesetzt.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Blöcke hierher ziehen\",\n columns: \"Spalten\",\n column1: \"1 Spalte\",\n column2: \"2 Spalten\",\n column3: \"3 Spalten\",\n ratio12: \"1:2 Verhältnis\",\n ratio21: \"2:1 Verhältnis\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Link bearbeiten\",\n insertLink: \"Link einfügen\",\n updateLink: \"Link aktualisieren\",\n removeLink: \"Link entfernen\",\n cancel: \"Abbrechen\",\n urlPlaceholder: \"https://beispiel.de\",\n urlLabel: \"URL\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Überschriftenebene\",\n heading1: \"Überschrift 1 (36px)\",\n heading2: \"Überschrift 2 (28px)\",\n heading3: \"Überschrift 3 (22px)\",\n heading4: \"Überschrift 4 (18px)\",\n fontFamily: \"Schriftart\",\n inheritFont: \"Vorlagenschrift verwenden\",\n color: \"Farbe\",\n align: \"Ausrichtung\",\n alignLeft: \"Links\",\n alignCenter: \"Zentriert\",\n alignRight: \"Rechts\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Smileys\",\n gestures: \"Gesten\",\n objects: \"Objekte\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"Bild-URL\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Alternativtext\",\n altTextPlaceholder: \"Bildbeschreibung\",\n width: \"Breite\",\n fullWidth: \"Volle Breite\",\n linkUrl: \"Link-URL\",\n openInNewTab: \"In neuem Tab öffnen\",\n placeholderUrl: \"Platzhalterbild\",\n placeholderUrlPlaceholder: \"https://... (nur zur Gestaltung)\",\n placeholderUrlTooltip:\n \"Da die Bild-URL ein Merge-Tag verwendet, können Sie hier ein echtes Bild angeben, um das Layout während der Gestaltung in der Vorschau anzuzeigen. Dies wird nicht in die endgültige Ausgabe aufgenommen.\",\n clickToAdd: \"Klicken Sie, um eine Bild-URL hinzuzufügen\",\n browseMedia: \"Medien durchsuchen\",\n decorative: \"Dekoratives Bild\",\n decorativeHint:\n \"Wird von Bildschirmlesern ignoriert. Nur für Abstandshalter und visuelle Verzierungen verwenden.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"Video-URL\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Video erkannt — Vorschaubild wird automatisch generiert\",\n openInNewTab: \"In neuem Tab öffnen\",\n customThumbnail: \"Eigenes Vorschaubild\",\n optional: \"(optional)\",\n thumbnailPlaceholder: \"Automatisch aus Video-URL generiert\",\n altText: \"Alternativtext\",\n altTextPlaceholder: \"Videobeschreibung\",\n width: \"Breite\",\n fullWidth: \"Volle Breite\",\n placeholderUrl: \"Platzhalter-Thumbnail\",\n placeholderUrlPlaceholder: \"https://... (nur zur Gestaltung)\",\n placeholderUrlTooltip:\n \"Da die Video-URL ein Merge-Tag verwendet, können Sie hier ein echtes Thumbnail angeben, um das Layout während der Gestaltung in der Vorschau anzuzeigen. Dies wird nicht in die endgültige Ausgabe aufgenommen.\",\n addVideo: \"Video-URL hinzufügen\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Schriftart\",\n inheritFont: \"Vorlagenschrift verwenden\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"In neuem Tab öffnen\",\n background: \"Hintergrund\",\n textColor: \"Textfarbe\",\n borderRadius: \"Eckenradius\",\n fontSize: \"Schriftgröße\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Stil\",\n solid: \"Durchgehend\",\n dashed: \"Gestrichelt\",\n dotted: \"Gepunktet\",\n color: \"Farbe\",\n thickness: \"Stärke\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Symbole\",\n addIcon: \"Symbol hinzufügen\",\n addIcons: \"Soziale Symbole hinzufügen\",\n removeIcon: \"Entfernen\",\n platform: \"Plattform\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Stil\",\n styleSolid: \"Gefüllt\",\n styleOutlined: \"Umrandet\",\n styleRounded: \"Abgerundet\",\n styleSquare: \"Eckig\",\n styleCircle: \"Rund\",\n size: \"Größe\",\n sizeSmall: \"K\",\n sizeMedium: \"M\",\n sizeLarge: \"G\",\n spacing: \"Abstand\",\n align: \"Ausrichtung\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"E-Mail\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Menüpunkte\",\n addItem: \"Punkt hinzufügen\",\n removeItem: \"Entfernen\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://beispiel.de\",\n openInNewTab: \"In neuem Tab öffnen\",\n bold: \"Fett\",\n underline: \"Unterstrichen\",\n color: \"Farbe\",\n linkColor: \"Linkfarbe\",\n fontSize: \"Schriftgröße\",\n fontFamily: \"Schriftfamilie\",\n separator: \"Trennzeichen\",\n separatorColor: \"Trennzeichenfarbe\",\n spacing: \"Abstand\",\n textAlign: \"Ausrichtung\",\n addLinks: \"Menülinks hinzufügen\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Abmessungen\",\n rows: \"Zeilen\",\n columns: \"Spalten\",\n addRow: \"Zeile hinzufügen\",\n removeRow: \"Zeile entfernen\",\n addColumn: \"Spalte hinzufügen\",\n removeColumn: \"Spalte entfernen\",\n hasHeaderRow: \"Kopfzeile\",\n headerBackgroundColor: \"Kopfzeilen-Hintergrund\",\n noHeaderBg: \"Kein Hintergrund\",\n borderColor: \"Rahmenfarbe\",\n borderWidth: \"Rahmenbreite\",\n cellPadding: \"Zellenabstand\",\n fontFamily: \"Schriftart\",\n fontSize: \"Schriftgröße\",\n color: \"Textfarbe\",\n textAlign: \"Ausrichtung\",\n cellPlaceholder: \"Text eingeben...\",\n empty: \"Tabelle hinzufügen\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Höhe\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Zieldatum\",\n timezone: \"Zeitzone\",\n display: \"Anzeige\",\n days: \"Tage\",\n hours: \"Stunden\",\n minutes: \"Minuten\",\n seconds: \"Sekunden\",\n separator: \"Trennzeichen\",\n fontFamily: \"Schriftart\",\n inheritFont: \"Standard\",\n digitFontSize: \"Zifferngröße\",\n digitColor: \"Ziffernfarbe\",\n labelColor: \"Beschriftungsfarbe\",\n labelFontSize: \"Beschriftungsgröße\",\n background: \"Hintergrund\",\n labels: \"Beschriftungen\",\n expiry: \"Ablaufnachricht\",\n expiredMessagePlaceholder: \"Dieses Angebot ist abgelaufen\",\n expiredImageUrl: \"Ablaufbild-URL\",\n hideOnExpiry: \"Bei Ablauf ausblenden\",\n setDate: \"Legen Sie ein Zieldatum im Einstellungsbereich fest\",\n hidden: \"Ausgeblendet (abgelaufen)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound:\n \"Unbekannter Blocktyp — dieser Block ist nicht registriert\",\n renderError:\n \"Dieser Block konnte nicht gerendert werden. Überprüfen Sie die Block-Vorlage auf Fehler.\",\n fields: {\n required: \"Pflichtfeld\",\n addItem: \"Element hinzufügen\",\n removeItem: \"Entfernen\",\n maxItemsReached: \"Maximale Anzahl erreicht\",\n minItemsRequired: \"Mindestens {count} Elemente erforderlich\",\n },\n toolbar: {\n noDefinition:\n \"Registrieren Sie diesen Blocktyp in Ihrer SDK-Konfiguration, um seine Eigenschaften zu bearbeiten\",\n },\n dataSource: {\n fetchButton: \"Inhalt laden\",\n changeButton: \"Ändern\",\n fetching: \"Wird geladen...\",\n readOnlyTooltip: \"Dieser Wert wird aus Ihrer Datenquelle geladen\",\n fetchError: \"Inhalt konnte nicht geladen werden\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"HTML-Inhalt\",\n preview: \"Benutzerdefinierter HTML-Block\",\n empty: \"HTML-Inhalt im Bereich hinzufügen\",\n sanitizationHint:\n \"Skripte und unsichere Elemente werden beim Export entfernt.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Abstände\",\n padding: \"Innenabstand\",\n margin: \"Außenabstand\",\n background: \"Hintergrund\",\n color: \"Farbe\",\n display: \"Anzeige\",\n showOnDesktop: \"Auf Desktop anzeigen\",\n showOnTablet: \"Auf Tablet anzeigen\",\n showOnMobile: \"Auf Mobilgerät anzeigen\",\n hiddenOnDevice: \"Ausgeblendet auf {device}\",\n customCss: \"Benutzerdefiniertes CSS\",\n css: \"CSS\",\n cssPlaceholder: \"/* Benutzerdefinierte Stile */\",\n displayCondition: \"Anzeigebedingung\",\n selectCondition: \"Bedingung auswählen\",\n removeCondition: \"Bedingung entfernen\",\n noCondition: \"Immer sichtbar\",\n conditionApplied: \"Bedingung angewendet\",\n customCondition: \"Eigene Bedingung\",\n customConditionLabel: \"Bedingungsname\",\n customConditionBefore: \"Vorher (öffnende Logik)\",\n customConditionAfter: \"Nachher (schließende Logik)\",\n applyCondition: \"Anwenden\",\n cancelCondition: \"Abbrechen\",\n customBadge: \"Eigene\",\n restoreHiddenBlocks: \"Alle ausgeblendeten Blöcke anzeigen\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Layout\",\n widthPreset: \"Breitenvoreinstellung\",\n customWidth: \"Benutzerdefinierte Breite\",\n appearance: \"Erscheinungsbild\",\n backgroundColor: \"Hintergrundfarbe\",\n fontFamily: \"Schriftfamilie\",\n preheaderText: \"Preheader-Text\",\n preheaderTextPlaceholder:\n \"Vorschautext, der nach der Betreffzeile im Posteingang angezeigt wird...\",\n preheaderTextHint:\n \"Dieser Text erscheint nach der Betreffzeile in der E-Mail-Vorschau. Unterstützt Merge-Tags.\",\n language: \"Sprache\",\n contentLocale: \"Inhaltssprache\",\n contentLocaleHint:\n \"BCP-47-Code (z. B. en, de, pt-BR). Setzt das lang-Attribut der gerenderten E-Mail, damit Screenreader den Inhalt korrekt aussprechen.\",\n tips: \"Tipps\",\n tip1: \"600px ist die Standardbreite für E-Mail-Vorlagen\",\n tip2: \"Verwenden Sie websichere Schriften für beste Kompatibilität\",\n tip3: \"Helle Hintergründe eignen sich am besten für die Lesbarkeit\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Alle Seiten sperren\",\n unlock: \"Seiten entsperren\",\n top: \"Oben\",\n right: \"Rechts\",\n bottom: \"Unten\",\n left: \"Links\",\n decreaseTop: \"Oben verringern\",\n increaseTop: \"Oben erhöhen\",\n decreaseLeft: \"Links verringern\",\n increaseLeft: \"Links erhöhen\",\n decreaseRight: \"Rechts verringern\",\n increaseRight: \"Rechts erhöhen\",\n decreaseBottom: \"Unten verringern\",\n increaseBottom: \"Unten erhöhen\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Farbe auswählen\",\n hexValue: \"Hex-Farbwert\",\n },\n\n // Merge-Tag\n mergeTag: {\n clickToEdit: \"Zum Bearbeiten klicken\",\n remove: \"Merge-Tag entfernen\",\n insert: \"Merge-Tag einfügen\",\n add: \"Merge-Tag hinzufügen\",\n editValue: \"Merge-Tag-Wert bearbeiten\",\n deleteMergeTag: \"Merge-Tag löschen\",\n suggestionEmpty: \"Keine passenden Merge-Tags\",\n },\n\n // Canvas\n canvas: {\n noBlocks: \"Noch keine Blöcke\",\n dragHint:\n \"Beginnen Sie von Grund auf, indem Sie Blöcke aus der Seitenleiste ziehen\",\n dropHere: \"Hier ablegen\",\n aiHintChat: \"oder lassen Sie\",\n aiHintChatSuffix: \"in Sekunden eine komplette Vorlage für Sie erstellen\",\n aiHintDesign:\n \"Haben Sie ein bestehendes Design? Laden Sie einen Screenshot, ein Bild oder PDF hoch und\",\n aiHintDesignSuffix: \"erstellt es sofort nach\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Medienbibliothek\",\n searchPlaceholder: \"Dateien suchen...\",\n allFiles: \"Alle Dateien\",\n filterAll: \"Alle Typen\",\n filterImages: \"Bilder\",\n filterDocuments: \"Dokumente\",\n filterVideos: \"Videos\",\n filterAudio: \"Audio\",\n newFolder: \"Neuer Ordner\",\n folderName: \"Ordnername\",\n noFiles: \"Keine Dateien gefunden\",\n dropOrClick: \"Dateien hierher ziehen oder klicken zum Hochladen\",\n acceptedFormats: \"Bilder, PDF, Video, Audio, Dokumente (max. 10 MB)\",\n uploading: \"Wird hochgeladen...\",\n uploadingProgress: \"{current} von {total} wird hochgeladen...\",\n selectImage: \"Bild auswählen\",\n selectFile: \"Datei auswählen\",\n deleteSelected: \"Löschen\",\n copyUrl: \"URL kopieren\",\n copied: \"Kopiert!\",\n browseMedia: \"Medienbibliothek durchsuchen\",\n renameFolder: \"Ordner umbenennen\",\n addSubfolder: \"Unterordner hinzufügen\",\n subfolderName: \"Unterordnername\",\n sortNewest: \"Neueste zuerst\",\n sortOldest: \"Älteste zuerst\",\n sortNameAsc: \"Name A-Z\",\n sortNameDesc: \"Name Z-A\",\n sortSizeAsc: \"Kleinste zuerst\",\n sortSizeDesc: \"Größte zuerst\",\n moveSelected: \"Verschieben\",\n moveToRoot: \"Alle Dateien\",\n currentFolder: \"(aktuell)\",\n confirmDelete: \"Diese Datei löschen?\",\n renameFile: \"Umbenennen\",\n editFile: \"Datei bearbeiten\",\n fileName: \"Dateiname\",\n altText: \"Alternativtext\",\n altTextPlaceholder: \"Bildbeschreibung für Barrierefreiheit\",\n saveChanges: \"Speichern\",\n cancel: \"Abbrechen\",\n frequentlyUsed: \"Häufig verwendet\",\n deleteWarningTitle: \"Datei löschen\",\n deleteWarningMessage:\n \"Diese Datei wird dauerhaft gelöscht und kann nicht wiederhergestellt werden.\",\n deleteWarningUsageNote:\n \"Die folgenden Dateien werden in Vorlagen verwendet. Das Löschen kann diese Vorlagen beschädigen.\",\n deleteAnyway: \"Datei löschen\",\n usedInTemplates: \"In {count} Vorlage(n) verwendet\",\n viewGrid: \"Rasteransicht\",\n viewList: \"Listenansicht\",\n showFolders: \"Ordner anzeigen\",\n hideFolders: \"Ordner ausblenden\",\n importFromUrl: \"Von URL importieren\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Importieren\",\n importing: \"Wird importiert...\",\n importError: \"Import von URL fehlgeschlagen\",\n conversionLabel: \"Groesse\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Klein (150px)\",\n conversionMedium: \"Mittel (600px)\",\n conversionLarge: \"Gross (1200px)\",\n replaceFile: \"Datei ersetzen\",\n replaceWarningTitle: \"Datei ersetzen\",\n replaceWarningMessage:\n \"Sie sind dabei, diese Datei zu ersetzen. Die Ersatzdatei muss dieselbe Dateierweiterung haben ({extension}).\",\n replaceWarningUsageNote:\n \"Diese Datei wird in {count} Vorlage(n) verwendet. Das Ersetzen aktualisiert alle Verweise.\",\n replaceSelectFile: \"Ersatzdatei auswählen\",\n replace: \"Ersetzen\",\n replacing: \"Wird ersetzt...\",\n replaceError: \"Ersetzen der Datei fehlgeschlagen\",\n saving: \"Wird gespeichert...\",\n cropAspectRatio: \"Seitenverhältnis\",\n cropFree: \"Frei\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Max. Breite\",\n cropMaxHeight: \"Max. Höhe\",\n cropOutputSize: \"Ausgabegröße\",\n cropPixels: \"px\",\n cropOptional: \"(optional)\",\n storageTooltip: \"{used} von {total} verwendet ({remaining} verfügbar)\",\n },\n\n // Seitenleiste\n sidebarNav: {\n browseModules: \"Gespeicherte Module durchsuchen\",\n expandSidebar: \"Block-Seitenleiste erweitern\",\n palette: \"Blockpalette\",\n insertBlock: \"{block}-Block einfügen\",\n },\n\n // Landmark-Bezeichnungen für Hilfstechnologien\n landmarks: {\n canvas: \"E-Mail-Leinwand\",\n blockToolbar: \"Blockeigenschaften\",\n rightSidebar: \"Blockeigenschaften und Vorlageneinstellungen\",\n reorderAnnouncements: \"Block-Neuanordnungsmeldungen\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Editor wird geladen...\",\n editorLoadFailed: \"Editor konnte nicht geladen werden.\",\n retry: \"Erneut versuchen\",\n },\n\n accessibility: {\n panelTitle: \"Barrierefreiheit\",\n panelTabLabel: \"Barrierefreiheit\",\n groupErrors: \"Fehler\",\n groupWarnings: \"Warnungen\",\n groupInfo: \"Hinweise\",\n jump: \"Zum Block springen\",\n fix: \"Beheben\",\n emptyState: \"Keine Probleme mit der Barrierefreiheit.\",\n badgeError: \"Hat Barrierefreiheitsfehler\",\n badgeWarning: \"Hat Barrierefreiheitswarnungen\",\n issueCountTooltip: \"{count} Barrierefreiheitsprobleme\",\n },\n};\n\nexport default de;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"en-8FHaQv4V.js","names":[],"sources":["../../../src/i18n/locales/en.ts"],"sourcesContent":["export default {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Powered by\",\n openSource: \"Open Source\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Undo\",\n redo: \"Redo\",\n collabWarning: \"Undo may affect collaborators' recent changes\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Viewport\",\n desktop: \"Desktop\",\n tablet: \"Tablet\",\n mobile: \"Mobile\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Dark Mode Preview\",\n disable: \"Light Mode Preview\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Preview Mode\",\n disable: \"Exit Preview\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Section\",\n image: \"Image\",\n title: \"Title\",\n paragraph: \"Paragraph\",\n button: \"Button\",\n divider: \"Divider\",\n video: \"Video\",\n social: \"Social\",\n spacer: \"Spacer\",\n html: \"HTML\",\n menu: \"Menu\",\n table: \"Table\",\n countdown: \"Countdown\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Content\",\n settings: \"Settings\",\n noSelection: \"No element selected\",\n noSelectionHint: \"Select a block on the canvas to edit it\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplicate\",\n delete: \"Delete\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Title formatting\",\n bold: \"Bold (Ctrl+B)\",\n italic: \"Italic (Ctrl+I)\",\n addLink: \"Add Link\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Text formatting\",\n bold: \"Bold (Ctrl+B)\",\n italic: \"Italic (Ctrl+I)\",\n underline: \"Underline (Ctrl+U)\",\n strikethrough: \"Strikethrough\",\n subscript: \"Subscript\",\n superscript: \"Superscript\",\n addLink: \"Add Link\",\n bulletList: \"Bullet List\",\n numberedList: \"Numbered List\",\n alignLeft: \"Align Left\",\n alignCenter: \"Align Center\",\n alignRight: \"Align Right\",\n clearFormatting: \"Clear Formatting\",\n insertEmoji: \"Insert Emoji\",\n fontFamily: \"Font Family\",\n defaultFont: \"Default\",\n fontSize: \"Font Size\",\n defaultSize: \"Default\",\n textColor: \"Text Color\",\n highlightColor: \"Highlight Color\",\n lineHeight: \"Line Height\",\n letterSpacing: \"Letter Spacing\",\n emojiItemLabel: \"Insert emoji {emoji}\",\n closeEmojiPicker: \"Close emoji picker\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Drag to reorder, or press Space to move with keyboard\",\n dragLifted:\n \"Moving {block}. Use up and down arrow keys to reposition, Space or Enter to drop, Escape to cancel.\",\n duplicate: \"Duplicate block\",\n delete: \"Delete block\",\n hiddenOnViewport: \"Hidden on {viewport}\",\n saveAsModule: \"Save as Module\",\n conditionToggle: \"Toggle display condition\",\n comments: \"Comments ({count})\",\n lifted: \"{block} lifted. Position {position} of {total}.\",\n moved: \"{block} moved to position {position} of {total}.\",\n dropped: \"{block} dropped at position {position} of {total}.\",\n cancelled: \"Move cancelled. {block} returned to position {position}.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Drop blocks here\",\n columns: \"Columns\",\n column1: \"1 Column\",\n column2: \"2 Columns\",\n column3: \"3 Columns\",\n ratio12: \"1:2 Ratio\",\n ratio21: \"2:1 Ratio\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Edit Link\",\n insertLink: \"Insert Link\",\n updateLink: \"Update Link\",\n removeLink: \"Remove Link\",\n cancel: \"Cancel\",\n urlPlaceholder: \"https://example.com\",\n urlLabel: \"URL\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Heading Level\",\n heading1: \"Heading 1 (36px)\",\n heading2: \"Heading 2 (28px)\",\n heading3: \"Heading 3 (22px)\",\n heading4: \"Heading 4 (18px)\",\n fontFamily: \"Font Family\",\n inheritFont: \"Use template font\",\n color: \"Color\",\n align: \"Align\",\n alignLeft: \"Left\",\n alignCenter: \"Center\",\n alignRight: \"Right\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Smileys\",\n gestures: \"Gestures\",\n objects: \"Objects\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"Image URL\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Alt Text\",\n altTextPlaceholder: \"Image description\",\n width: \"Width\",\n fullWidth: \"Full Width\",\n linkUrl: \"Link URL\",\n openInNewTab: \"Open in new tab\",\n placeholderUrl: \"Placeholder Image\",\n placeholderUrlPlaceholder: \"https://... (design-time only)\",\n placeholderUrlTooltip:\n \"Since the image URL uses a merge tag, you can provide a real image here to preview the layout while designing. This is not included in the final output.\",\n clickToAdd: \"Click to add image URL\",\n browseMedia: \"Browse Media\",\n decorative: \"Decorative image\",\n decorativeHint:\n \"Hidden from screen readers. Use only for spacers and visual flourishes.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"Video URL\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Video detected — thumbnail will be generated automatically\",\n openInNewTab: \"Open in new tab\",\n customThumbnail: \"Custom Thumbnail\",\n optional: \"(optional)\",\n thumbnailPlaceholder: \"Auto-generated from video URL\",\n altText: \"Alt Text\",\n altTextPlaceholder: \"Video description\",\n width: \"Width\",\n fullWidth: \"Full Width\",\n placeholderUrl: \"Placeholder Thumbnail\",\n placeholderUrlPlaceholder: \"https://... (design-time only)\",\n placeholderUrlTooltip:\n \"Since the video URL uses a merge tag, you can provide a real thumbnail here to preview the layout while designing. This is not included in the final output.\",\n addVideo: \"Add a video URL\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Font Family\",\n inheritFont: \"Use template font\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Open in new tab\",\n background: \"Background\",\n textColor: \"Text Color\",\n borderRadius: \"Border Radius\",\n fontSize: \"Font Size\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Style\",\n solid: \"Solid\",\n dashed: \"Dashed\",\n dotted: \"Dotted\",\n color: \"Color\",\n thickness: \"Thickness\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Icons\",\n addIcon: \"Add Icon\",\n addIcons: \"Add social icons\",\n removeIcon: \"Remove\",\n platform: \"Platform\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Style\",\n styleSolid: \"Solid\",\n styleOutlined: \"Outlined\",\n styleRounded: \"Rounded\",\n styleSquare: \"Square\",\n styleCircle: \"Circle\",\n size: \"Size\",\n sizeSmall: \"S\",\n sizeMedium: \"M\",\n sizeLarge: \"L\",\n spacing: \"Spacing\",\n align: \"Alignment\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"Email\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Menu Items\",\n addItem: \"Add Item\",\n removeItem: \"Remove\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://example.com\",\n openInNewTab: \"Open in new tab\",\n bold: \"Bold\",\n underline: \"Underline\",\n color: \"Color\",\n linkColor: \"Link Color\",\n fontSize: \"Font Size\",\n fontFamily: \"Font Family\",\n separator: \"Separator\",\n separatorColor: \"Separator Color\",\n spacing: \"Spacing\",\n textAlign: \"Alignment\",\n addLinks: \"Add menu links\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Dimensions\",\n rows: \"Rows\",\n columns: \"Columns\",\n addRow: \"Add Row\",\n removeRow: \"Remove Row\",\n addColumn: \"Add Column\",\n removeColumn: \"Remove Column\",\n hasHeaderRow: \"Header row\",\n headerBackgroundColor: \"Header Background\",\n noHeaderBg: \"No background\",\n borderColor: \"Border Color\",\n borderWidth: \"Border Width\",\n cellPadding: \"Cell Padding\",\n fontFamily: \"Font Family\",\n fontSize: \"Font Size\",\n color: \"Text Color\",\n textAlign: \"Alignment\",\n cellPlaceholder: \"Enter text...\",\n empty: \"Add a table\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Height\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Target Date\",\n timezone: \"Timezone\",\n display: \"Display\",\n days: \"Days\",\n hours: \"Hours\",\n minutes: \"Minutes\",\n seconds: \"Seconds\",\n separator: \"Separator\",\n fontFamily: \"Font Family\",\n inheritFont: \"Default\",\n digitFontSize: \"Digit Size\",\n digitColor: \"Digit Color\",\n labelColor: \"Label Color\",\n labelFontSize: \"Label Size\",\n background: \"Background\",\n labels: \"Labels\",\n expiry: \"Expired Message\",\n expiredMessagePlaceholder: \"This offer has expired\",\n expiredImageUrl: \"Expired Image URL\",\n hideOnExpiry: \"Hide when expired\",\n setDate: \"Set a target date in the settings panel\",\n hidden: \"Hidden (expired)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound: \"Unknown block type — this block is not registered\",\n renderError:\n \"This block could not be rendered. Check the block template for errors.\",\n fields: {\n required: \"Required\",\n addItem: \"Add item\",\n removeItem: \"Remove\",\n maxItemsReached: \"Maximum items reached\",\n minItemsRequired: \"Minimum {count} items required\",\n },\n toolbar: {\n noDefinition:\n \"Register this block type in your SDK configuration to edit its properties\",\n },\n dataSource: {\n fetchButton: \"Load content\",\n changeButton: \"Change\",\n fetching: \"Loading...\",\n readOnlyTooltip: \"This value is loaded from your data source\",\n fetchError: \"Failed to load content\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"HTML Content\",\n preview: \"Custom HTML block\",\n empty: \"Add HTML content in the panel\",\n sanitizationHint: \"Scripts and unsafe elements are removed on export.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Spacing\",\n padding: \"Padding\",\n margin: \"Margin\",\n background: \"Background\",\n color: \"Color\",\n display: \"Display\",\n showOnDesktop: \"Show on desktop\",\n showOnTablet: \"Show on tablet\",\n showOnMobile: \"Show on mobile\",\n hiddenOnDevice: \"Hidden on {device}\",\n customCss: \"Custom CSS\",\n css: \"CSS\",\n cssPlaceholder: \"/* Custom styles */\",\n displayCondition: \"Display Condition\",\n selectCondition: \"Select condition\",\n removeCondition: \"Remove condition\",\n noCondition: \"Always visible\",\n conditionApplied: \"Condition applied\",\n customCondition: \"Custom condition\",\n customConditionLabel: \"Condition name\",\n customConditionBefore: \"Before (opening logic)\",\n customConditionAfter: \"After (closing logic)\",\n applyCondition: \"Apply\",\n cancelCondition: \"Cancel\",\n customBadge: \"Custom\",\n restoreHiddenBlocks: \"Show all hidden blocks\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Layout\",\n widthPreset: \"Width Preset\",\n customWidth: \"Custom Width\",\n appearance: \"Appearance\",\n backgroundColor: \"Background Color\",\n fontFamily: \"Font Family\",\n preheaderText: \"Preheader Text\",\n preheaderTextPlaceholder:\n \"Preview text shown after subject line in inbox...\",\n preheaderTextHint:\n \"This text appears after the subject line in email client previews. Supports merge tags.\",\n language: \"Language\",\n contentLocale: \"Content language\",\n contentLocaleHint:\n \"BCP 47 code (e.g. en, de, pt-BR). Sets the rendered email's lang attribute so screen readers pronounce content correctly.\",\n tips: \"Tips\",\n tip1: \"600px is the standard width for email templates\",\n tip2: \"Use web-safe fonts for best compatibility\",\n tip3: \"Light backgrounds work best for readability\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Lock all sides\",\n unlock: \"Unlock sides\",\n top: \"Top\",\n right: \"Right\",\n bottom: \"Bottom\",\n left: \"Left\",\n decreaseTop: \"Decrease top\",\n increaseTop: \"Increase top\",\n decreaseLeft: \"Decrease left\",\n increaseLeft: \"Increase left\",\n decreaseRight: \"Decrease right\",\n increaseRight: \"Increase right\",\n decreaseBottom: \"Decrease bottom\",\n increaseBottom: \"Increase bottom\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Pick a color\",\n hexValue: \"Hex color value\",\n },\n\n // Merge Tag\n mergeTag: {\n clickToEdit: \"Click to edit\",\n remove: \"Remove merge tag\",\n insert: \"Insert merge tag\",\n add: \"Add merge tag\",\n editValue: \"Edit merge tag value\",\n deleteMergeTag: \"Delete merge tag\",\n suggestionEmpty: \"No matching merge tags\",\n },\n\n // Canvas\n canvas: {\n noBlocks: \"No blocks yet\",\n dragHint: \"Start from scratch by dragging blocks from the sidebar\",\n dropHere: \"Drop here\",\n aiHintChat: \"or let\",\n aiHintChatSuffix: \"generate a complete template for you in seconds\",\n aiHintDesign:\n \"Have an existing design? Upload a screenshot, image, or PDF and\",\n aiHintDesignSuffix: \"will instantly recreate it\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Media Library\",\n searchPlaceholder: \"Search files...\",\n allFiles: \"All Files\",\n filterAll: \"All Types\",\n filterImages: \"Images\",\n filterDocuments: \"Documents\",\n filterVideos: \"Videos\",\n filterAudio: \"Audio\",\n newFolder: \"New Folder\",\n folderName: \"Folder name\",\n noFiles: \"No files found\",\n dropOrClick: \"Drop files here or click to upload\",\n acceptedFormats: \"Images, PDF, Video, Audio, Documents (max 10MB)\",\n uploading: \"Uploading...\",\n uploadingProgress: \"Uploading {current} of {total}...\",\n selectImage: \"Select Image\",\n selectFile: \"Select File\",\n deleteSelected: \"Delete\",\n copyUrl: \"Copy URL\",\n copied: \"Copied!\",\n browseMedia: \"Browse Media Library\",\n renameFolder: \"Rename folder\",\n addSubfolder: \"Add subfolder\",\n subfolderName: \"Subfolder name\",\n sortNewest: \"Newest First\",\n sortOldest: \"Oldest First\",\n sortNameAsc: \"Name A-Z\",\n sortNameDesc: \"Name Z-A\",\n sortSizeAsc: \"Smallest First\",\n sortSizeDesc: \"Largest First\",\n moveSelected: \"Move\",\n moveToRoot: \"All Files\",\n currentFolder: \"(current)\",\n confirmDelete: \"Delete this file?\",\n renameFile: \"Rename\",\n editFile: \"Edit File\",\n fileName: \"Filename\",\n altText: \"Alt Text\",\n altTextPlaceholder: \"Describe this image for accessibility\",\n saveChanges: \"Save\",\n cancel: \"Cancel\",\n frequentlyUsed: \"Frequently Used\",\n deleteWarningTitle: \"Delete File\",\n deleteWarningMessage:\n \"This file will be permanently deleted and cannot be recovered.\",\n deleteWarningUsageNote:\n \"The following files are used in templates. Deleting them may break those templates.\",\n deleteAnyway: \"Delete file\",\n usedInTemplates: \"Used in {count} template(s)\",\n viewGrid: \"Grid view\",\n viewList: \"List view\",\n showFolders: \"Show folders\",\n hideFolders: \"Hide folders\",\n importFromUrl: \"Import from URL\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Import\",\n importing: \"Importing...\",\n importError: \"Failed to import from URL\",\n conversionLabel: \"Size\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Small (150px)\",\n conversionMedium: \"Medium (600px)\",\n conversionLarge: \"Large (1200px)\",\n replaceFile: \"Replace File\",\n replaceWarningTitle: \"Replace File\",\n replaceWarningMessage:\n \"You are about to replace this file. The replacement must have the same file extension ({extension}).\",\n replaceWarningUsageNote:\n \"This file is used in {count} template(s). Replacing it will update all references.\",\n replaceSelectFile: \"Select replacement file\",\n replace: \"Replace\",\n replacing: \"Replacing...\",\n replaceError: \"Failed to replace file\",\n saving: \"Saving...\",\n cropAspectRatio: \"Aspect Ratio\",\n cropFree: \"Free\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Max Width\",\n cropMaxHeight: \"Max Height\",\n cropOutputSize: \"Output Size\",\n cropPixels: \"px\",\n cropOptional: \"(optional)\",\n storageTooltip: \"{used} of {total} used ({remaining} remaining)\",\n },\n\n // Sidebar\n sidebarNav: {\n browseModules: \"Browse saved modules\",\n expandSidebar: \"Expand block sidebar\",\n palette: \"Block palette\",\n insertBlock: \"Insert {block} block\",\n },\n\n // Landmark region labels for assistive technology\n landmarks: {\n canvas: \"Email canvas\",\n blockToolbar: \"Block properties\",\n rightSidebar: \"Block properties and template settings\",\n reorderAnnouncements: \"Block reorder announcements\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Loading editor...\",\n editorLoadFailed: \"Failed to load editor.\",\n retry: \"Retry\",\n },\n\n accessibility: {\n panelTitle: \"Accessibility\",\n panelTabLabel: \"Accessibility\",\n groupErrors: \"Errors\",\n groupWarnings: \"Warnings\",\n groupInfo: \"Info\",\n jump: \"Jump to block\",\n fix: \"Fix\",\n emptyState: \"No accessibility issues — looking good.\",\n badgeError: \"Has accessibility errors\",\n badgeWarning: \"Has accessibility warnings\",\n issueCountTooltip: \"{count} accessibility issue(s)\",\n },\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extensions-DIxF31tA.js","names":["$emit"],"sources":["../../../src/extensions/FontSize.ts","../../../src/extensions/LetterSpacing.ts","../../../src/extensions/LineHeight.ts","../../../src/extensions/LogicMergeTagNodeView.vue","../../../src/extensions/LogicMergeTagNodeView.vue","../../../src/extensions/isNodeSelected.ts","../../../src/extensions/renderVueNodeView.ts","../../../src/extensions/LogicMergeTagNode.ts","../../../src/extensions/MergeTagNodeView.vue","../../../src/extensions/MergeTagNodeView.vue","../../../src/extensions/MergeTagNode.ts","../../../src/components/MergeTagSuggestionList.vue","../../../src/components/MergeTagSuggestionList.vue","../../../src/extensions/MergeTagSuggestion.ts"],"sourcesContent":["import { Extension } from \"@tiptap/core\";\n\nexport interface FontSizeOptions {\n types: string[];\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n fontSize: {\n setFontSize: (size: string) => ReturnType;\n unsetFontSize: () => ReturnType;\n };\n }\n}\n\nexport const FontSize = Extension.create<FontSizeOptions>({\n name: \"fontSize\",\n\n addOptions() {\n return {\n types: [\"textStyle\"],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n fontSize: {\n default: null,\n parseHTML: (element) =>\n element.style.fontSize?.replace(/['\"]+/g, \"\") || null,\n renderHTML: (attributes) => {\n if (!attributes.fontSize) {\n return {};\n }\n return {\n style: `font-size: ${attributes.fontSize}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setFontSize:\n (size: string) =>\n ({ chain }) => {\n return chain().setMark(\"textStyle\", { fontSize: size }).run();\n },\n unsetFontSize:\n () =>\n ({ chain }) => {\n return chain()\n .setMark(\"textStyle\", { fontSize: null })\n .removeEmptyTextStyle()\n .run();\n },\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport interface LetterSpacingOptions {\n types: string[];\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n letterSpacing: {\n setLetterSpacing: (spacing: string) => ReturnType;\n unsetLetterSpacing: () => ReturnType;\n };\n }\n}\n\nexport const LetterSpacing = Extension.create<LetterSpacingOptions>({\n name: \"letterSpacing\",\n\n addOptions() {\n return {\n types: [\"textStyle\"],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n letterSpacing: {\n default: null,\n parseHTML: (element) =>\n element.style.letterSpacing?.replace(/['\"]+/g, \"\") || null,\n renderHTML: (attributes) => {\n if (!attributes.letterSpacing) {\n return {};\n }\n return {\n style: `letter-spacing: ${attributes.letterSpacing}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setLetterSpacing:\n (spacing: string) =>\n ({ chain }) => {\n return chain().setMark(\"textStyle\", { letterSpacing: spacing }).run();\n },\n unsetLetterSpacing:\n () =>\n ({ chain }) => {\n return chain()\n .setMark(\"textStyle\", { letterSpacing: null })\n .removeEmptyTextStyle()\n .run();\n },\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport interface LineHeightOptions {\n types: string[];\n defaultLineHeight: string;\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n lineHeight: {\n setLineHeight: (lineHeight: string) => ReturnType;\n unsetLineHeight: () => ReturnType;\n };\n }\n}\n\nexport const LineHeight = Extension.create<LineHeightOptions>({\n name: \"lineHeight\",\n\n addOptions() {\n return {\n types: [\"paragraph\"],\n defaultLineHeight: \"1.5\",\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n lineHeight: {\n default: null,\n parseHTML: (element) => element.style.lineHeight || null,\n renderHTML: (attributes) => {\n if (!attributes.lineHeight) {\n return {};\n }\n return {\n style: `line-height: ${attributes.lineHeight}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setLineHeight:\n (lineHeight: string) =>\n ({ commands }) => {\n return this.options.types.every((type) =>\n commands.updateAttributes(type, { lineHeight }),\n );\n },\n unsetLineHeight:\n () =>\n ({ commands }) => {\n return this.options.types.every((type) =>\n commands.resetAttributes(type, \"lineHeight\"),\n );\n },\n };\n },\n});\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n} from \"@templatical/types\";\nimport type { Editor } from \"@tiptap/core\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n value: string;\n keyword: string;\n };\n };\n editor: Editor;\n getPos: () => number;\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { syntax } = useMergeTag();\nconst { t } = useI18n();\n\nconst isValid = computed(() =>\n isLogicMergeTagValue(props.node.attrs.value, syntax),\n);\nconst displayKeyword = computed(() =>\n getLogicMergeTagKeyword(props.node.attrs.value, syntax),\n);\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\nlet handled = false;\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n handled = false;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n if (handled) {\n return;\n }\n handled = true;\n\n const newValue = editValue.value.trim();\n if (!newValue) {\n isEditing.value = false;\n return;\n }\n\n if (newValue !== props.node.attrs.value) {\n props.updateAttributes({\n value: newValue,\n keyword: isLogicMergeTagValue(newValue, syntax)\n ? getLogicMergeTagKeyword(newValue, syntax)\n : \"\",\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n :class=\"\n isValid\n ? 'tpl-logic-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.8em] tpl:font-bold tpl:tracking-wide tpl:uppercase tpl:select-none'\n : ''\n \"\n :style=\"\n isValid\n ? 'background-color: transparent; border: 1.5px solid color-mix(in srgb, var(--tpl-primary) 50%, transparent); color: var(--tpl-primary);'\n : ''\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-40 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:normal-case tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode: valid merge tag -->\n <span\n v-else-if=\"isValid\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayKeyword }}\n </span>\n <!-- Display mode: invalid (plain text) -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ node.attrs.value }}\n </span>\n <button\n v-if=\"isValid\"\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n} from \"@templatical/types\";\nimport type { Editor } from \"@tiptap/core\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n value: string;\n keyword: string;\n };\n };\n editor: Editor;\n getPos: () => number;\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { syntax } = useMergeTag();\nconst { t } = useI18n();\n\nconst isValid = computed(() =>\n isLogicMergeTagValue(props.node.attrs.value, syntax),\n);\nconst displayKeyword = computed(() =>\n getLogicMergeTagKeyword(props.node.attrs.value, syntax),\n);\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\nlet handled = false;\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n handled = false;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n if (handled) {\n return;\n }\n handled = true;\n\n const newValue = editValue.value.trim();\n if (!newValue) {\n isEditing.value = false;\n return;\n }\n\n if (newValue !== props.node.attrs.value) {\n props.updateAttributes({\n value: newValue,\n keyword: isLogicMergeTagValue(newValue, syntax)\n ? getLogicMergeTagKeyword(newValue, syntax)\n : \"\",\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n :class=\"\n isValid\n ? 'tpl-logic-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.8em] tpl:font-bold tpl:tracking-wide tpl:uppercase tpl:select-none'\n : ''\n \"\n :style=\"\n isValid\n ? 'background-color: transparent; border: 1.5px solid color-mix(in srgb, var(--tpl-primary) 50%, transparent); color: var(--tpl-primary);'\n : ''\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-40 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:normal-case tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode: valid merge tag -->\n <span\n v-else-if=\"isValid\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayKeyword }}\n </span>\n <!-- Display mode: invalid (plain text) -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ node.attrs.value }}\n </span>\n <button\n v-if=\"isValid\"\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","import type { Editor } from \"@tiptap/core\";\n\n/**\n * Checks whether a TipTap node of the given type is selected, or if the cursor\n * is immediately adjacent to one (for Backspace/Delete handling).\n *\n * Shared by MergeTagNode and LogicMergeTagNode keyboard shortcuts.\n */\nexport function isNodeSelected(editor: Editor, nodeTypeName: string): boolean {\n const { selection } = editor.state;\n const { $from, $to } = selection;\n\n // Check if selection contains a node of this type\n let found = false;\n editor.state.doc.nodesBetween($from.pos, $to.pos, (node) => {\n if (node.type.name === nodeTypeName) {\n found = true;\n return false;\n }\n });\n\n if (found) {\n return true;\n }\n\n // Check if cursor is right after the node (for Backspace)\n if ($from.pos > 0 && $from.nodeBefore?.type.name === nodeTypeName) {\n return true;\n }\n\n // Check if cursor is right before the node (for Delete)\n if ($from.nodeAfter?.type.name === nodeTypeName) {\n return true;\n }\n\n return false;\n}\n","import type { Component } from \"vue\";\nimport { VueNodeViewRenderer } from \"@tiptap/vue-3\";\n\n/**\n * Typed wrapper for VueNodeViewRenderer that handles the known type mismatch\n * between Vue SFC default exports and TipTap's expected component type.\n */\nexport function renderVueNodeView(component: Component) {\n return VueNodeViewRenderer(\n component as Parameters<typeof VueNodeViewRenderer>[0],\n );\n}\n","import LogicMergeTagNodeView from \"./LogicMergeTagNodeView.vue\";\nimport type { SyntaxPreset } from \"@templatical/types\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n SYNTAX_PRESETS,\n} from \"@templatical/types\";\nimport { InputRule, mergeAttributes, Node, PasteRule } from \"@tiptap/core\";\nimport { isNodeSelected } from \"./isNodeSelected\";\nimport { renderVueNodeView } from \"./renderVueNodeView\";\n\nexport interface LogicMergeTagNodeOptions {\n syntax: SyntaxPreset;\n}\n\nexport const LogicMergeTagNode = Node.create<LogicMergeTagNodeOptions>({\n name: \"logicMergeTagNode\",\n\n group: \"inline\",\n\n inline: true,\n\n atom: true,\n\n addOptions() {\n return {\n syntax: SYNTAX_PRESETS.liquid,\n };\n },\n\n addAttributes() {\n return {\n value: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-logic-merge-tag\") || \"\",\n },\n keyword: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-keyword\") || element.textContent || \"\",\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: \"span[data-logic-merge-tag]\",\n },\n ];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n if (!isLogicMergeTagValue(node.attrs.value, this.options.syntax)) {\n return [\"span\", {}, node.attrs.value];\n }\n\n const keyword = getLogicMergeTagKeyword(\n node.attrs.value,\n this.options.syntax,\n );\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-logic-merge-tag\": node.attrs.value,\n \"data-keyword\": keyword,\n }),\n keyword,\n ];\n },\n\n addNodeView() {\n return renderVueNodeView(LogicMergeTagNodeView);\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => isNodeSelected(this.editor, this.name),\n Delete: () => isNodeSelected(this.editor, this.name),\n };\n },\n\n addInputRules() {\n const inputRegex = new RegExp(this.options.syntax.logic.source + \"$\", \"\");\n\n return [\n new InputRule({\n find: inputRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n if (!isLogicMergeTagValue(fullValue, this.options.syntax)) {\n return;\n }\n\n const keyword = getLogicMergeTagKeyword(\n fullValue,\n this.options.syntax,\n );\n\n const node = this.type.create({\n value: fullValue,\n keyword,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n\n addPasteRules() {\n const pasteRegex = new RegExp(this.options.syntax.logic.source, \"g\");\n\n return [\n new PasteRule({\n find: pasteRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n if (!isLogicMergeTagValue(fullValue, this.options.syntax)) {\n return;\n }\n\n const keyword = getLogicMergeTagKeyword(\n fullValue,\n this.options.syntax,\n );\n\n const node = this.type.create({\n value: fullValue,\n keyword,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n});\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n label: string;\n value: string;\n };\n };\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { getMergeTagLabel } = useMergeTag();\nconst { t } = useI18n();\n\nconst displayLabel = computed(() => getMergeTagLabel(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n if (newValue && newValue !== props.node.attrs.value) {\n // Update with new value and derive label from it\n props.updateAttributes({\n value: newValue,\n label: getMergeTagLabel(newValue),\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n class=\"tpl-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.9em] tpl:font-medium tpl:select-none tpl:text-[var(--tpl-primary)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-primary) 20%, transparent);\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-32 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayLabel }}\n </span>\n <button\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n label: string;\n value: string;\n };\n };\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { getMergeTagLabel } = useMergeTag();\nconst { t } = useI18n();\n\nconst displayLabel = computed(() => getMergeTagLabel(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n if (newValue && newValue !== props.node.attrs.value) {\n // Update with new value and derive label from it\n props.updateAttributes({\n value: newValue,\n label: getMergeTagLabel(newValue),\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n class=\"tpl-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.9em] tpl:font-medium tpl:select-none tpl:text-[var(--tpl-primary)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-primary) 20%, transparent);\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-32 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayLabel }}\n </span>\n <button\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","import MergeTagNodeView from \"./MergeTagNodeView.vue\";\nimport type { MergeTag, SyntaxPreset } from \"@templatical/types\";\nimport { getMergeTagLabel, SYNTAX_PRESETS } from \"@templatical/types\";\nimport { InputRule, mergeAttributes, Node, PasteRule } from \"@tiptap/core\";\nimport { isNodeSelected } from \"./isNodeSelected\";\nimport { renderVueNodeView } from \"./renderVueNodeView\";\n\nexport interface MergeTagNodeOptions {\n mergeTags: MergeTag[];\n syntax: SyntaxPreset;\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n mergeTagNode: {\n insertMergeTag: (attrs: MergeTag) => ReturnType;\n };\n }\n}\n\nexport const MergeTagNode = Node.create<MergeTagNodeOptions>({\n name: \"mergeTagNode\",\n\n group: \"inline\",\n\n inline: true,\n\n atom: true,\n\n addOptions() {\n return {\n mergeTags: [],\n syntax: SYNTAX_PRESETS.liquid,\n };\n },\n\n addAttributes() {\n return {\n label: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-label\") || element.textContent || \"\",\n },\n value: {\n default: \"\",\n parseHTML: (element) => element.getAttribute(\"data-merge-tag\") || \"\",\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: \"span[data-merge-tag]\",\n },\n ];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const label = getMergeTagLabel(node.attrs.value, this.options.mergeTags);\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-merge-tag\": node.attrs.value,\n \"data-label\": label,\n }),\n label,\n ];\n },\n\n addNodeView() {\n return renderVueNodeView(MergeTagNodeView);\n },\n\n addCommands() {\n return {\n insertMergeTag:\n (attrs: MergeTag) =>\n ({ commands }) => {\n return commands.insertContent({\n type: this.name,\n attrs,\n });\n },\n };\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => isNodeSelected(this.editor, this.name),\n Delete: () => isNodeSelected(this.editor, this.name),\n };\n },\n\n addInputRules() {\n const inputRegex = new RegExp(this.options.syntax.value.source + \"$\", \"\");\n\n return [\n new InputRule({\n find: inputRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n const label = getMergeTagLabel(fullValue, this.options.mergeTags);\n\n const node = this.type.create({\n label,\n value: fullValue,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n\n addPasteRules() {\n const pasteRegex = new RegExp(this.options.syntax.value.source, \"g\");\n\n return [\n new PasteRule({\n find: pasteRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n const label = getMergeTagLabel(fullValue, this.options.mergeTags);\n\n const node = this.type.create({\n label,\n value: fullValue,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n});\n","<script setup lang=\"ts\">\nimport type { MergeTag } from \"@templatical/types\";\n\nconst props = defineProps<{\n items: MergeTag[];\n selectedIndex: number;\n emptyText: string;\n /** Stable id used for aria-controls + per-option id derivation. */\n listId?: string;\n}>();\n\ndefineEmits<{\n (e: \"select\", item: MergeTag): void;\n (e: \"hover\", index: number): void;\n}>();\n\nfunction optionId(index: number): string | undefined {\n return props.listId ? `${props.listId}-opt-${index}` : undefined;\n}\n</script>\n\n<template>\n <div\n :id=\"listId\"\n class=\"tpl:min-w-[200px] tpl:max-w-[320px] tpl:max-h-[50vh] tpl:overflow-y-auto tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:py-1 tpl:shadow-lg\"\n role=\"listbox\"\n data-testid=\"merge-tag-suggestion-list\"\n >\n <div\n v-if=\"items.length === 0\"\n class=\"tpl:px-3 tpl:py-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n data-testid=\"merge-tag-suggestion-empty\"\n >\n {{ emptyText }}\n </div>\n <button\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :id=\"optionId(index)\"\n type=\"button\"\n role=\"option\"\n :aria-selected=\"index === selectedIndex\"\n :data-selected=\"index === selectedIndex ? 'true' : 'false'\"\n :data-merge-tag-value=\"item.value\"\n class=\"tpl:flex tpl:w-full tpl:flex-col tpl:items-start tpl:gap-0.5 tpl:px-3 tpl:py-1.5 tpl:text-left tpl:text-xs tpl:transition-colors\"\n :class=\"\n index === selectedIndex\n ? 'tpl:bg-[var(--tpl-primary-light)] tpl:text-[var(--tpl-primary)]'\n : 'tpl:text-[var(--tpl-text)] hover:tpl:bg-[var(--tpl-bg-hover)]'\n \"\n @mousedown.prevent.stop=\"$emit('select', item)\"\n @mousemove=\"index !== selectedIndex && $emit('hover', index)\"\n >\n <span class=\"tpl:font-medium\">{{ item.label }}</span>\n <span class=\"tpl:text-[var(--tpl-text-dim)] tpl:font-mono\">{{\n item.value\n }}</span>\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { MergeTag } from \"@templatical/types\";\n\nconst props = defineProps<{\n items: MergeTag[];\n selectedIndex: number;\n emptyText: string;\n /** Stable id used for aria-controls + per-option id derivation. */\n listId?: string;\n}>();\n\ndefineEmits<{\n (e: \"select\", item: MergeTag): void;\n (e: \"hover\", index: number): void;\n}>();\n\nfunction optionId(index: number): string | undefined {\n return props.listId ? `${props.listId}-opt-${index}` : undefined;\n}\n</script>\n\n<template>\n <div\n :id=\"listId\"\n class=\"tpl:min-w-[200px] tpl:max-w-[320px] tpl:max-h-[50vh] tpl:overflow-y-auto tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:py-1 tpl:shadow-lg\"\n role=\"listbox\"\n data-testid=\"merge-tag-suggestion-list\"\n >\n <div\n v-if=\"items.length === 0\"\n class=\"tpl:px-3 tpl:py-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n data-testid=\"merge-tag-suggestion-empty\"\n >\n {{ emptyText }}\n </div>\n <button\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :id=\"optionId(index)\"\n type=\"button\"\n role=\"option\"\n :aria-selected=\"index === selectedIndex\"\n :data-selected=\"index === selectedIndex ? 'true' : 'false'\"\n :data-merge-tag-value=\"item.value\"\n class=\"tpl:flex tpl:w-full tpl:flex-col tpl:items-start tpl:gap-0.5 tpl:px-3 tpl:py-1.5 tpl:text-left tpl:text-xs tpl:transition-colors\"\n :class=\"\n index === selectedIndex\n ? 'tpl:bg-[var(--tpl-primary-light)] tpl:text-[var(--tpl-primary)]'\n : 'tpl:text-[var(--tpl-text)] hover:tpl:bg-[var(--tpl-bg-hover)]'\n \"\n @mousedown.prevent.stop=\"$emit('select', item)\"\n @mousemove=\"index !== selectedIndex && $emit('hover', index)\"\n >\n <span class=\"tpl:font-medium\">{{ item.label }}</span>\n <span class=\"tpl:text-[var(--tpl-text-dim)] tpl:font-mono\">{{\n item.value\n }}</span>\n </button>\n </div>\n</template>\n","import type { MergeTag } from \"@templatical/types\";\nimport { Extension } from \"@tiptap/core\";\nimport Suggestion, {\n type SuggestionOptions,\n type SuggestionProps,\n type SuggestionKeyDownProps,\n} from \"@tiptap/suggestion\";\nimport { type App, createApp, h, ref, type Ref } from \"vue\";\nimport MergeTagSuggestionList from \"../components/MergeTagSuggestionList.vue\";\n\nconst MAX_RESULTS = 10;\n\n// Monotonic counter for unique listbox IDs across multiple popup instances.\nlet POPUP_ID_SEQ = 0;\n\nexport interface MergeTagSuggestionOptions {\n /** Available merge tags */\n mergeTags: MergeTag[];\n /** Trigger string (e.g. \"{{\", \"*|\", \"%%=\") */\n char: string;\n /** Localized empty-state label */\n emptyText: string;\n}\n\n/**\n * Filter merge tags by query against label and value (case-insensitive).\n * Capped at MAX_RESULTS. Exported for testing.\n */\nexport function filterMergeTags(tags: MergeTag[], query: string): MergeTag[] {\n const trimmed = query.trim().toLowerCase();\n if (trimmed === \"\") {\n return tags.slice(0, MAX_RESULTS);\n }\n return tags\n .filter((tag) => {\n const label = tag.label.toLowerCase();\n const value = tag.value.toLowerCase();\n return label.includes(trimmed) || value.includes(trimmed);\n })\n .slice(0, MAX_RESULTS);\n}\n\n/**\n * Handle a keydown event against a list of items. Returns whether the\n * event was handled (so the suggestion plugin can stop propagation).\n * Exported for testing.\n */\nexport function handleSuggestionKeyDown(\n event: KeyboardEvent,\n items: MergeTag[],\n selectedIndex: Ref<number>,\n onSelect: (item: MergeTag) => void,\n): boolean {\n if (items.length === 0) {\n if (event.key === \"Enter\" || event.key === \"Tab\") return true;\n return false;\n }\n\n if (event.key === \"ArrowDown\") {\n selectedIndex.value = (selectedIndex.value + 1) % items.length;\n return true;\n }\n if (event.key === \"ArrowUp\") {\n selectedIndex.value =\n (selectedIndex.value - 1 + items.length) % items.length;\n return true;\n }\n if (event.key === \"Enter\" || event.key === \"Tab\") {\n onSelect(items[selectedIndex.value]);\n return true;\n }\n return false;\n}\n\nexport const MergeTagSuggestion = Extension.create<MergeTagSuggestionOptions>({\n name: \"mergeTagSuggestion\",\n\n addOptions() {\n return {\n mergeTags: [],\n char: \"{{\",\n emptyText: \"No matching merge tags\",\n };\n },\n\n addProseMirrorPlugins() {\n const tags = this.options.mergeTags;\n const emptyText = this.options.emptyText;\n\n const config: Omit<SuggestionOptions<MergeTag>, \"editor\"> = {\n char: this.options.char,\n allowSpaces: false,\n startOfLine: false,\n // Default is [\" \"] which requires whitespace/line-start before the\n // trigger char — so `.{{` would not fire. Allow any preceding char.\n allowedPrefixes: null,\n items: ({ query }: { query: string }) => filterMergeTags(tags, query),\n command: ({\n editor,\n range,\n props,\n }: {\n editor: SuggestionProps<MergeTag>[\"editor\"];\n range: { from: number; to: number };\n props: MergeTag;\n }) => {\n // Use insertContentAt for atomic replace (matches the canonical\n // @tiptap/suggestion + Mention pattern). Avoids edge cases where\n // chained deleteRange + insertMergeTag fails to insert when the\n // selection state shifts mid-chain.\n editor\n .chain()\n .focus()\n .insertContentAt(range, {\n type: \"mergeTagNode\",\n attrs: { label: props.label, value: props.value },\n })\n .run();\n },\n render: () => {\n let app: App | null = null;\n let container: HTMLElement | null = null;\n let editableEl: HTMLElement | null = null;\n const itemsRef = ref<MergeTag[]>([]);\n const selectedIndex = ref(0);\n let currentCommand: ((item: MergeTag) => void) | null = null;\n const listId = `tpl-merge-tag-suggestion-${++POPUP_ID_SEQ}`;\n let latestClientRect: (() => DOMRect | null) | null = null;\n let scrollTargets: Array<EventTarget> = [];\n\n function reposition(): void {\n position(latestClientRect?.() ?? null);\n }\n\n /**\n * Reposition immediately and on the next animation frame.\n * After a keystroke triggers the suggestion, TipTap may run its\n * own `scrollIntoView` to keep the caret visible. That scroll\n * lands AFTER the current task's `position()` call but BEFORE\n * the browser's next paint, so we re-measure on rAF to catch\n * the post-scroll caret rect. Without this, the popup pins to\n * the pre-scroll caret position and ends up offset on slower\n * runners.\n */\n function repositionAfterPaint(): void {\n reposition();\n requestAnimationFrame(reposition);\n }\n\n function collectScrollAncestors(el: HTMLElement | null): HTMLElement[] {\n // Walk up the DOM finding scrollable ancestors. ProseMirror's\n // scrollIntoView fires on whichever ancestor scrolls — listening\n // to all of them ensures we reposition regardless of which one\n // moves.\n const result: HTMLElement[] = [];\n let node: HTMLElement | null = el?.parentElement ?? null;\n while (\n node &&\n node !== document.body &&\n node !== document.documentElement\n ) {\n const style = window.getComputedStyle(node);\n const overflow = style.overflow + style.overflowX + style.overflowY;\n if (/(auto|scroll|overlay)/.test(overflow)) {\n result.push(node);\n }\n node = node.parentElement;\n }\n return result;\n }\n\n function attachScrollListeners(viewDom: HTMLElement | null): void {\n scrollTargets = [window, ...collectScrollAncestors(viewDom)];\n for (const target of scrollTargets) {\n target.addEventListener(\"scroll\", reposition, {\n passive: true,\n capture: true,\n });\n }\n window.addEventListener(\"resize\", reposition, { passive: true });\n }\n\n function detachScrollListeners(): void {\n for (const target of scrollTargets) {\n target.removeEventListener(\"scroll\", reposition, {\n capture: true,\n } as EventListenerOptions);\n }\n window.removeEventListener(\"resize\", reposition);\n scrollTargets = [];\n }\n\n function position(rect: DOMRect | null): void {\n if (!container || !rect) return;\n // If the caret has scrolled out of the viewport, freeze the\n // popup at its last on-screen position. Following the caret\n // off-screen produces an invisible popup the user can't reach,\n // and lets pathological scroll loops drag the popup further\n // each tick.\n if (rect.bottom < 0 || rect.top > window.innerHeight) return;\n container.style.position = \"fixed\";\n container.style.left = `${rect.left}px`;\n container.style.zIndex = \"9999\";\n // Place below caret first; offsetHeight is sync-readable after\n // the Vue app has mounted (or after onUpdate's reactive flush).\n container.style.top = `${rect.bottom}px`;\n const popupHeight = container.offsetHeight;\n if (popupHeight === 0) return;\n const spaceBelow = window.innerHeight - rect.bottom;\n if (spaceBelow < popupHeight) {\n // Not enough room below — flip above. Clamp to 0 so the\n // popup never positions off the top of the viewport.\n const flippedTop = Math.max(0, rect.top - popupHeight);\n container.style.top = `${flippedTop}px`;\n }\n }\n\n function applyThemeContext(\n target: HTMLElement,\n editorEl: HTMLElement | null | undefined,\n ): void {\n // The popup mounts to document.body so its `position: fixed`\n // resolves against the viewport — any transform/filter on a\n // consumer-page ancestor (route transitions, reveal animations,\n // dark canvas inversion) creates a containing block and moves\n // fixed descendants with it. Body ancestors don't transform.\n //\n // CSS vars (--tpl-bg-elevated, --tpl-border, etc.) are scoped to\n // `.tpl` and `.tpl[data-tpl-theme=\"dark\"]` in the editor's\n // stylesheet, so the popup wouldn't inherit them at body root.\n // Adding `class=\"tpl\"` would also pull base rules (min-height,\n // flex, full-page bg) we don't want on a popup. Instead, snapshot\n // every --tpl-* custom property from the editor's theme root and\n // re-emit them inline on the popup wrapper.\n const themeRoot = editorEl?.closest<HTMLElement>(\"[data-tpl-theme]\");\n if (!themeRoot) return;\n const themeValue = themeRoot.getAttribute(\"data-tpl-theme\");\n if (themeValue) target.setAttribute(\"data-tpl-theme\", themeValue);\n const computed = window.getComputedStyle(themeRoot);\n for (let i = 0; i < computed.length; i++) {\n const prop = computed[i];\n if (prop.startsWith(\"--tpl-\")) {\n target.style.setProperty(prop, computed.getPropertyValue(prop));\n }\n }\n // The popup no longer inherits font from the editor wrapper, so\n // its content would render in the page's default font and end up\n // at a different height — which changes the flip-above decision\n // and shifts the popup off the caret. Copy typography too.\n target.style.fontFamily = computed.fontFamily;\n target.style.fontSize = computed.fontSize;\n target.style.lineHeight = computed.lineHeight;\n }\n\n function setEditableAria(active: boolean): void {\n if (!editableEl) return;\n if (active) {\n editableEl.setAttribute(\"role\", \"combobox\");\n editableEl.setAttribute(\"aria-haspopup\", \"listbox\");\n editableEl.setAttribute(\"aria-expanded\", \"true\");\n editableEl.setAttribute(\"aria-controls\", listId);\n } else {\n editableEl.removeAttribute(\"aria-expanded\");\n editableEl.removeAttribute(\"aria-controls\");\n editableEl.removeAttribute(\"aria-activedescendant\");\n editableEl.removeAttribute(\"aria-haspopup\");\n editableEl.removeAttribute(\"role\");\n }\n }\n\n function setActiveDescendant(): void {\n if (!editableEl) return;\n if (itemsRef.value.length === 0) {\n editableEl.removeAttribute(\"aria-activedescendant\");\n return;\n }\n editableEl.setAttribute(\n \"aria-activedescendant\",\n `${listId}-opt-${selectedIndex.value}`,\n );\n }\n\n function select(item: MergeTag): void {\n currentCommand?.(item);\n }\n\n return {\n onStart: (props: SuggestionProps<MergeTag>) => {\n itemsRef.value = props.items;\n selectedIndex.value = 0;\n currentCommand = (item) => props.command(item);\n\n container = document.createElement(\"div\");\n container.setAttribute(\"data-testid\", \"merge-tag-suggestion-popup\");\n // Use view.dom (ProseMirror contenteditable, actually\n // attached to the DOM) rather than options.element, which may\n // be a detached div when no `element` is passed to the editor\n // constructor (as is the case with @tiptap/vue-3 EditorContent).\n const viewDom = props.editor.view?.dom as HTMLElement | undefined;\n editableEl = viewDom ?? null;\n applyThemeContext(container, viewDom ?? null);\n document.body.appendChild(container);\n\n app = createApp({\n render() {\n return h(MergeTagSuggestionList, {\n items: itemsRef.value,\n selectedIndex: selectedIndex.value,\n emptyText,\n listId,\n onSelect: (item: MergeTag) => select(item),\n onHover: (index: number) => {\n selectedIndex.value = index;\n setActiveDescendant();\n },\n });\n },\n });\n app.mount(container);\n setEditableAria(true);\n setActiveDescendant();\n latestClientRect = props.clientRect ?? null;\n repositionAfterPaint();\n attachScrollListeners(viewDom ?? null);\n },\n onUpdate: (props: SuggestionProps<MergeTag>) => {\n itemsRef.value = props.items;\n // Reset selection when item set changes (query changed).\n if (selectedIndex.value >= props.items.length) {\n selectedIndex.value = 0;\n }\n currentCommand = (item) => props.command(item);\n setActiveDescendant();\n latestClientRect = props.clientRect ?? null;\n repositionAfterPaint();\n },\n onKeyDown: (props: SuggestionKeyDownProps): boolean => {\n if (props.event.key === \"Escape\") {\n return true;\n }\n const handled = handleSuggestionKeyDown(\n props.event,\n itemsRef.value,\n selectedIndex,\n select,\n );\n if (handled) setActiveDescendant();\n return handled;\n },\n onExit: () => {\n detachScrollListeners();\n setEditableAria(false);\n app?.unmount();\n container?.remove();\n app = null;\n container = null;\n editableEl = null;\n currentCommand = null;\n latestClientRect = null;\n },\n };\n },\n };\n\n return [\n Suggestion({\n editor: this.editor,\n ...config,\n }),\n ];\n },\n});\n"],"mappings":"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"}
|