@templatical/editor 0.6.5 → 0.6.6
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/dist/{AiFeatureMenu-uXTxJh06.js → AiFeatureMenu-ChlAWywJ.js} +1 -1
- package/dist/{CloudEditor-_GaYluN7.js → CloudEditor-DYYaScFe.js} +4 -4
- package/dist/{CollaboratorBar-C4eXJkXW.js → CollaboratorBar-Bo8vtPId.js} +1 -1
- package/dist/{ModuleBrowserModal-EDKHLJtb.js → ModuleBrowserModal-CKhsaPnA.js} +4 -4
- package/dist/{ModulePreviewCanvas-MQxat34K.js → ModulePreviewCanvas-Cw9GeGus.js} +1 -1
- package/dist/{ParagraphEditor-C8IP9HOZ.js → ParagraphEditor-DjDiUzmv.js} +1 -1
- package/dist/{SaveModuleDialog-Bgu0FVr6.js → SaveModuleDialog-CSUPmfRP.js} +2 -2
- package/dist/{SnapshotHistory-aSULEKUJ.js → SnapshotHistory-DwX2fj6N.js} +1 -1
- package/dist/{TestEmailModal-wcbmmWCs.js → TestEmailModal-CIlBvWWn.js} +2 -2
- package/dist/{TitleEditor-21D8_OUQ.js → TitleEditor-BCV5k6wj.js} +1 -1
- package/dist/{TplModal-CINtyB6Y.js → TplModal-C3Hq9b58.js} +1 -1
- package/dist/{blockTypeIcons-DKetBdJx.js → blockTypeIcons-iUurP50H.js} +1 -1
- package/dist/bundle-stats.json +5 -5
- package/dist/cdn/chunks/{AccessibilityPanel-BMSGhaNU.js → AccessibilityPanel-AQD2ygU6.js} +3 -3
- package/dist/cdn/chunks/{AccessibilityPanel-BMSGhaNU.js.map → AccessibilityPanel-AQD2ygU6.js.map} +1 -1
- package/dist/cdn/chunks/{AiFeatureMenu-hNba-JqQ.js → AiFeatureMenu-CDh9ifC8.js} +2 -2
- package/dist/cdn/chunks/{AiFeatureMenu-hNba-JqQ.js.map → AiFeatureMenu-CDh9ifC8.js.map} +1 -1
- package/dist/cdn/chunks/{BlockA11yBadge-BIR88CvN.js → BlockA11yBadge-BxZr3s7T.js} +2 -2
- package/dist/cdn/chunks/{BlockA11yBadge-BIR88CvN.js.map → BlockA11yBadge-BxZr3s7T.js.map} +1 -1
- package/dist/cdn/chunks/{CloudEditor-D2G2nNpQ.js → CloudEditor-Fg7pQ9IQ.js} +7 -7
- package/dist/cdn/chunks/{CloudEditor-D2G2nNpQ.js.map → CloudEditor-Fg7pQ9IQ.js.map} +1 -1
- package/dist/cdn/chunks/{CollaboratorBar-Btzom8dY.js → CollaboratorBar-B5a8eBXN.js} +3 -3
- package/dist/cdn/chunks/{CollaboratorBar-Btzom8dY.js.map → CollaboratorBar-B5a8eBXN.js.map} +1 -1
- package/dist/cdn/chunks/{CountdownBlock-BJSAJlJ1.js → CountdownBlock-BeHkO19t.js} +2 -2
- package/dist/cdn/chunks/{CountdownBlock-BJSAJlJ1.js.map → CountdownBlock-BeHkO19t.js.map} +1 -1
- package/dist/cdn/chunks/{CountdownToolbar-DbknNrIi.js → CountdownToolbar-8UfW0jb1.js} +3 -3
- package/dist/cdn/chunks/{CountdownToolbar-DbknNrIi.js.map → CountdownToolbar-8UfW0jb1.js.map} +1 -1
- package/dist/cdn/chunks/{ModuleBrowserModal-BvAuW8O5.js → ModuleBrowserModal-BMUyAmmj.js} +5 -5
- package/dist/cdn/chunks/{ModuleBrowserModal-BvAuW8O5.js.map → ModuleBrowserModal-BMUyAmmj.js.map} +1 -1
- package/dist/cdn/chunks/{ModulePreviewCanvas-CYtt0boo.js → ModulePreviewCanvas-CxSc7Pvd.js} +2 -2
- package/dist/cdn/chunks/{ModulePreviewCanvas-CYtt0boo.js.map → ModulePreviewCanvas-CxSc7Pvd.js.map} +1 -1
- package/dist/cdn/chunks/{NumberWithSuffix-CVfo9ztG.js → NumberWithSuffix-BSOUOUCL.js} +2 -2
- package/dist/cdn/chunks/{NumberWithSuffix-CVfo9ztG.js.map → NumberWithSuffix-BSOUOUCL.js.map} +1 -1
- package/dist/cdn/chunks/{ParagraphEditor-DCo58JP8.js → ParagraphEditor-S1bpgxe5.js} +5 -5
- package/dist/cdn/chunks/{ParagraphEditor-DCo58JP8.js.map → ParagraphEditor-S1bpgxe5.js.map} +1 -1
- package/dist/cdn/chunks/{RichTextEditorContent-BzCThv84.js → RichTextEditorContent-ByehRfEA.js} +2 -2
- package/dist/cdn/chunks/{RichTextEditorContent-BzCThv84.js.map → RichTextEditorContent-ByehRfEA.js.map} +1 -1
- package/dist/cdn/chunks/{SaveModuleDialog-S2Lix1LD.js → SaveModuleDialog-5CNMvgYL.js} +2 -2
- package/dist/cdn/chunks/{SaveModuleDialog-S2Lix1LD.js.map → SaveModuleDialog-5CNMvgYL.js.map} +1 -1
- package/dist/cdn/chunks/{TitleEditor-CYzAMuUW.js → TitleEditor-BASWPsCM.js} +5 -5
- package/dist/cdn/chunks/{TitleEditor-CYzAMuUW.js.map → TitleEditor-BASWPsCM.js.map} +1 -1
- package/dist/cdn/chunks/{blockTypeIcons-DOzUHoor.js → blockTypeIcons-DfOffaYP.js} +3 -3
- package/dist/cdn/chunks/{blockTypeIcons-DOzUHoor.js.map → blockTypeIcons-DfOffaYP.js.map} +1 -1
- package/dist/cdn/chunks/{extensions-wafZZ0-_.js → extensions-BJOV1jre.js} +2 -2
- package/dist/cdn/chunks/{extensions-wafZZ0-_.js.map → extensions-BJOV1jre.js.map} +1 -1
- package/dist/cdn/chunks/{features-B4tNvoi4.js → features-D6FoOm8v.js} +24 -14
- package/dist/cdn/chunks/features-D6FoOm8v.js.map +1 -0
- package/dist/cdn/chunks/{icons-B5nBFtvb.js → icons-CpsjWPU-.js} +2 -2
- package/dist/cdn/chunks/{icons-B5nBFtvb.js.map → icons-CpsjWPU-.js.map} +1 -1
- package/dist/cdn/chunks/{media-library-BLaoBxHe.js → media-library-CEd7Lqxk.js} +3 -3
- package/dist/cdn/chunks/{media-library-BLaoBxHe.js.map → media-library-CEd7Lqxk.js.map} +1 -1
- package/dist/cdn/chunks/{quality-D920ZxXf.js → quality-Bx1oORXQ.js} +2 -2
- package/dist/cdn/chunks/{quality-D920ZxXf.js.map → quality-Bx1oORXQ.js.map} +1 -1
- package/dist/cdn/chunks/{renderer-Yk30CckU.js → renderer-CwxCisa-.js} +2 -2
- package/dist/cdn/chunks/{renderer-Yk30CckU.js.map → renderer-CwxCisa-.js.map} +1 -1
- package/dist/cdn/chunks/{src-kLJg7Y0m.js → src-DDSInEkE.js} +4 -4
- package/dist/cdn/chunks/{src-kLJg7Y0m.js.map → src-DDSInEkE.js.map} +1 -1
- package/dist/cdn/chunks/{styles-DrVLif14.js → styles-B1uu-Cc9.js} +8 -8
- package/dist/cdn/chunks/{styles-DrVLif14.js.map → styles-B1uu-Cc9.js.map} +1 -1
- package/dist/cdn/editor.css +1 -1
- package/dist/cdn/editor.js +5 -5
- package/dist/index.d.ts +11 -11
- package/dist/style.css +1 -1
- package/dist/{styles-CwJQsnSp.js → styles-BgmKdc2x.js} +2 -2
- package/dist/templatical-editor.js +3 -3
- package/dist/{useEditorCore-DLd-5qMg.js → useEditorCore-CnXrv71D.js} +25 -15
- package/package.json +7 -7
- package/dist/cdn/chunks/features-B4tNvoi4.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as e, P as t, f as n, g as r, h as i, m as a, ot as o, p as s, rt as c, st as l, u, x as d } from "./draggable-CNhyCGIO.js";
|
|
2
|
-
import { $ as f } from "./features-
|
|
3
|
-
import { n as p, r as m } from "./icons-
|
|
2
|
+
import { $ as f } from "./features-D6FoOm8v.js";
|
|
3
|
+
import { n as p, r as m } from "./icons-CpsjWPU-.js";
|
|
4
4
|
import { t as h } from "./readableTextColor-DhoK4XiZ.js";
|
|
5
5
|
//#region src/cloud/components/CollaboratorBar.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var g = { class: "tpl-collaborator-bar tpl:flex tpl:items-center tpl:gap-2" }, _ = ["title"], v = {
|
|
@@ -48,4 +48,4 @@ var g = { class: "tpl-collaborator-bar tpl:flex tpl:items-center tpl:gap-2" }, _
|
|
|
48
48
|
//#endregion
|
|
49
49
|
export { S as default };
|
|
50
50
|
|
|
51
|
-
//# sourceMappingURL=CollaboratorBar-
|
|
51
|
+
//# sourceMappingURL=CollaboratorBar-B5a8eBXN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollaboratorBar-
|
|
1
|
+
{"version":3,"file":"CollaboratorBar-B5a8eBXN.js","names":[],"sources":["../../../src/cloud/components/CollaboratorBar.vue","../../../src/cloud/components/CollaboratorBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Collaborator } from \"@templatical/types\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { Wifi, WifiOff } from \"@lucide/vue\";\nimport { computed } from \"vue\";\nimport { readableTextColor } from \"../../utils/readableTextColor\";\n\nconst props = defineProps<{\n collaborators: Collaborator[];\n isConnected: boolean;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\n\nconst maxVisible = 3;\n\nconst visibleCollaborators = computed(() =>\n props.collaborators.slice(0, maxVisible),\n);\n\nconst overflowCollaborators = computed(() =>\n props.collaborators.slice(maxVisible),\n);\n\nconst overflowCount = computed(() => overflowCollaborators.value.length);\n\nconst overflowNames = computed(() =>\n overflowCollaborators.value.map((c) => c.name).join(\"\\n\"),\n);\n\nfunction getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (\n parts[0].charAt(0) + parts[parts.length - 1].charAt(0)\n ).toUpperCase();\n }\n return name.charAt(0).toUpperCase();\n}\n</script>\n\n<template>\n <div class=\"tpl-collaborator-bar tpl:flex tpl:items-center tpl:gap-2\">\n <!-- Connection indicator -->\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1 tpl:text-[11px]\"\n :style=\"{\n color: isConnected ? 'var(--tpl-success)' : 'var(--tpl-text-muted)',\n }\"\n :title=\"\n isConnected\n ? cloudT.collaboration.connected\n : cloudT.collaboration.disconnected\n \"\n >\n <Wifi v-if=\"isConnected\" :size=\"12\" :stroke-width=\"2\" />\n <WifiOff v-else :size=\"12\" :stroke-width=\"2\" />\n </div>\n\n <!-- Avatar stack -->\n <div\n v-if=\"collaborators.length > 0\"\n class=\"tpl:flex tpl:items-center tpl:-space-x-1.5\"\n >\n <div\n v-for=\"collaborator in visibleCollaborators\"\n :key=\"collaborator.id\"\n class=\"tpl-collaborator-avatar tpl:relative tpl:flex tpl:size-6 tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-2 tpl:text-[10px] tpl:font-bold tpl:transition-transform tpl:duration-150 tpl:hover:z-10 tpl:hover:scale-110 tpl:border-[var(--tpl-bg)]\"\n :style=\"{\n backgroundColor: collaborator.color,\n color: readableTextColor(collaborator.color),\n }\"\n :title=\"collaborator.name\"\n >\n {{ getInitials(collaborator.name) }}\n </div>\n <div\n v-if=\"overflowCount > 0\"\n class=\"tpl:relative tpl:flex tpl:size-6 tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-2 tpl:text-[9px] tpl:font-bold tpl:border-[var(--tpl-bg)] tpl:bg-[var(--tpl-bg-hover)] tpl:text-[var(--tpl-text-muted)]\"\n :title=\"overflowNames\"\n >\n +{{ overflowCount }}\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { Collaborator } from \"@templatical/types\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { Wifi, WifiOff } from \"@lucide/vue\";\nimport { computed } from \"vue\";\nimport { readableTextColor } from \"../../utils/readableTextColor\";\n\nconst props = defineProps<{\n collaborators: Collaborator[];\n isConnected: boolean;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\n\nconst maxVisible = 3;\n\nconst visibleCollaborators = computed(() =>\n props.collaborators.slice(0, maxVisible),\n);\n\nconst overflowCollaborators = computed(() =>\n props.collaborators.slice(maxVisible),\n);\n\nconst overflowCount = computed(() => overflowCollaborators.value.length);\n\nconst overflowNames = computed(() =>\n overflowCollaborators.value.map((c) => c.name).join(\"\\n\"),\n);\n\nfunction getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (\n parts[0].charAt(0) + parts[parts.length - 1].charAt(0)\n ).toUpperCase();\n }\n return name.charAt(0).toUpperCase();\n}\n</script>\n\n<template>\n <div class=\"tpl-collaborator-bar tpl:flex tpl:items-center tpl:gap-2\">\n <!-- Connection indicator -->\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1 tpl:text-[11px]\"\n :style=\"{\n color: isConnected ? 'var(--tpl-success)' : 'var(--tpl-text-muted)',\n }\"\n :title=\"\n isConnected\n ? cloudT.collaboration.connected\n : cloudT.collaboration.disconnected\n \"\n >\n <Wifi v-if=\"isConnected\" :size=\"12\" :stroke-width=\"2\" />\n <WifiOff v-else :size=\"12\" :stroke-width=\"2\" />\n </div>\n\n <!-- Avatar stack -->\n <div\n v-if=\"collaborators.length > 0\"\n class=\"tpl:flex tpl:items-center tpl:-space-x-1.5\"\n >\n <div\n v-for=\"collaborator in visibleCollaborators\"\n :key=\"collaborator.id\"\n class=\"tpl-collaborator-avatar tpl:relative tpl:flex tpl:size-6 tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-2 tpl:text-[10px] tpl:font-bold tpl:transition-transform tpl:duration-150 tpl:hover:z-10 tpl:hover:scale-110 tpl:border-[var(--tpl-bg)]\"\n :style=\"{\n backgroundColor: collaborator.color,\n color: readableTextColor(collaborator.color),\n }\"\n :title=\"collaborator.name\"\n >\n {{ getInitials(collaborator.name) }}\n </div>\n <div\n v-if=\"overflowCount > 0\"\n class=\"tpl:relative tpl:flex tpl:size-6 tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-2 tpl:text-[9px] tpl:font-bold tpl:border-[var(--tpl-bg)] tpl:bg-[var(--tpl-bg-hover)] tpl:text-[var(--tpl-text-muted)]\"\n :title=\"overflowNames\"\n >\n +{{ overflowCount }}\n </div>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;iCAcM,IAAa;;;;;;;EAPnB,IAAM,IAAQ,GAKR,EAAE,GAAG,MAAW,GAAoB,EAIpC,IAAuB,QAC3B,EAAM,cAAc,MAAM,GAAG,EAAW,CACzC,EAEK,IAAwB,QAC5B,EAAM,cAAc,MAAM,EAAW,CACtC,EAEK,IAAgB,QAAe,EAAsB,MAAM,OAAO,EAElE,IAAgB,QACpB,EAAsB,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,CAC1D;EAED,SAAS,EAAY,GAAsB;GACzC,IAAM,IAAQ,EAAK,MAAM,CAAC,MAAM,MAAM;AAMtC,UALI,EAAM,UAAU,KAEhB,EAAM,GAAG,OAAO,EAAE,GAAG,EAAM,EAAM,SAAS,GAAG,OAAO,EAAC,EACrD,aAAa,GAEV,EAAK,OAAO,EAAE,CAAC,aAAa;;yBAKnC,EA0CM,OA1CN,GA0CM,CAxCJ,EAaM,OAAA;GAZJ,OAAM;GACL,OAAK,EAAA,EAAA,OAAmB,EAAA,cAAW,uBAAA,yBAAA,CAAA;GAGnC,OAAgB,EAAA,cAAwB,EAAA,EAAM,CAAC,cAAc,YAAsB,EAAA,EAAM,CAAC,cAAc;MAM7F,EAAA,eAAA,GAAA,EAAZ,EAAwD,EAAA,EAAA,EAAA;;GAA9B,MAAM;GAAK,gBAAc;cACnD,EAA+C,EAAA,EAAA,EAAA;;GAA9B,MAAM;GAAK,gBAAc;gBAKpC,EAAA,cAAc,SAAM,KAAA,GAAA,EAD5B,EAuBM,OAvBN,GAuBM,EAAA,EAAA,GAAA,EAnBJ,EAWM,GAAA,MAAA,EAVmB,EAAA,QAAhB,YADT,EAWM,OAAA;GATH,KAAK,EAAa;GACnB,OAAM;GACL,OAAK,EAAA;qBAA+B,EAAa;WAAwB,EAAA,EAAiB,CAAC,EAAa,MAAK;;GAI7G,OAAO,EAAa;OAElB,EAAY,EAAa,KAAI,CAAA,EAAA,IAAA,EAAA,WAG1B,EAAA,QAAa,KAAA,GAAA,EADrB,EAMM,OAAA;;GAJJ,OAAM;GACL,OAAO,EAAA;KACT,OACE,EAAG,EAAA,MAAa,EAAA,GAAA,EAAA,IAAA,EAAA,IAAA,GAAA,CAAA,CAAA,IAAA,EAAA,IAAA,GAAA,CAAA,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-C266TIVP.js";
|
|
2
2
|
import { M as t, P as n, Z as r, f as i, g as a, h as o, ot as s, p as c, rt as l, st as u, u as d, x as f } from "./draggable-CNhyCGIO.js";
|
|
3
|
-
import { Nt as p, cn as m } from "./features-
|
|
3
|
+
import { Nt as p, cn as m } from "./features-D6FoOm8v.js";
|
|
4
4
|
//#region src/components/blocks/CountdownBlock.vue?vue&type=script&setup=true&lang.ts
|
|
5
5
|
var h = {
|
|
6
6
|
key: 0,
|
|
@@ -90,4 +90,4 @@ var h = {
|
|
|
90
90
|
//#endregion
|
|
91
91
|
export { y as n, b as t };
|
|
92
92
|
|
|
93
|
-
//# sourceMappingURL=CountdownBlock-
|
|
93
|
+
//# sourceMappingURL=CountdownBlock-BeHkO19t.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountdownBlock-BJSAJlJ1.js","names":[],"sources":["../../../src/components/blocks/CountdownBlock.vue","../../../src/components/blocks/CountdownBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type {\n CountdownBlock as CountdownBlockType,\n ViewportSize,\n} from \"@templatical/types\";\nimport { useIntervalFn } from \"@vueuse/core\";\nimport { computed, ref } from \"vue\";\nimport { useI18n } from \"../../composables/useI18n\";\n\nconst props = defineProps<{\n block: CountdownBlockType;\n viewport: ViewportSize;\n}>();\n\nconst { t } = useI18n();\n\nconst now = ref(Date.now());\nuseIntervalFn(() => {\n now.value = Date.now();\n}, 1000);\n\nconst targetTime = computed(() => {\n if (!props.block.targetDate) return null;\n const date = new Date(props.block.targetDate);\n return isNaN(date.getTime()) ? null : date.getTime();\n});\n\nconst isExpired = computed(() => {\n if (!targetTime.value) return false;\n return now.value >= targetTime.value;\n});\n\nconst remaining = computed(() => {\n if (!targetTime.value || isExpired.value) {\n return { days: 0, hours: 0, minutes: 0, seconds: 0 };\n }\n const diff = targetTime.value - now.value;\n const totalSeconds = Math.floor(diff / 1000);\n return {\n days: Math.floor(totalSeconds / 86400),\n hours: Math.floor((totalSeconds % 86400) / 3600),\n minutes: Math.floor((totalSeconds % 3600) / 60),\n seconds: totalSeconds % 60,\n };\n});\n\nconst segments = computed(() => {\n const result: Array<{ value: string; label: string }> = [];\n if (props.block.showDays) {\n result.push({\n value: String(remaining.value.days).padStart(2, \"0\"),\n label: props.block.labelDays,\n });\n }\n if (props.block.showHours) {\n result.push({\n value: String(remaining.value.hours).padStart(2, \"0\"),\n label: props.block.labelHours,\n });\n }\n if (props.block.showMinutes) {\n result.push({\n value: String(remaining.value.minutes).padStart(2, \"0\"),\n label: props.block.labelMinutes,\n });\n }\n if (props.block.showSeconds) {\n result.push({\n value: String(remaining.value.seconds).padStart(2, \"0\"),\n label: props.block.labelSeconds,\n });\n }\n return result;\n});\n\nconst containerStyle = computed(() => ({\n backgroundColor: props.block.backgroundColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n\nconst digitStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n fontWeight: \"bold\" as const,\n color: props.block.digitColor,\n lineHeight: \"1.2\",\n}));\n\nconst labelStyle = computed(() => ({\n fontSize: `${props.block.labelFontSize}px`,\n color: props.block.labelColor,\n marginTop: \"4px\",\n}));\n\nconst separatorStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n color: props.block.digitColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n</script>\n\n<template>\n <!-- Empty state: no target date -->\n <div\n v-if=\"!block.targetDate\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-8 tpl:text-sm tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.countdown.setDate }}\n </div>\n\n <!-- Expired + hidden -->\n <div\n v-else-if=\"isExpired && block.hideOnExpiry\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-4 tpl:text-xs tpl:text-[var(--tpl-text-dim)] tpl:opacity-50\"\n >\n {{ t.countdown.hidden }}\n </div>\n\n <!-- Expired with message -->\n <div\n v-else-if=\"isExpired\"\n :style=\"containerStyle\"\n class=\"tpl:py-4 tpl:text-center\"\n >\n <span\n :style=\"{\n fontSize: `${block.digitFontSize}px`,\n color: block.digitColor,\n }\"\n >\n {{ block.expiredMessage }}\n </span>\n </div>\n\n <!-- Active countdown -->\n <div\n v-else\n :style=\"containerStyle\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-2 tpl:py-4\"\n >\n <template v-for=\"(segment, index) in segments\" :key=\"segment.label\">\n <span v-if=\"index > 0\" :style=\"separatorStyle\" class=\"tpl:self-start\">\n {{ block.separator }}\n </span>\n <div class=\"tpl:text-center\">\n <div :style=\"digitStyle\">{{ segment.value }}</div>\n <div :style=\"labelStyle\">{{ segment.label }}</div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type {\n CountdownBlock as CountdownBlockType,\n ViewportSize,\n} from \"@templatical/types\";\nimport { useIntervalFn } from \"@vueuse/core\";\nimport { computed, ref } from \"vue\";\nimport { useI18n } from \"../../composables/useI18n\";\n\nconst props = defineProps<{\n block: CountdownBlockType;\n viewport: ViewportSize;\n}>();\n\nconst { t } = useI18n();\n\nconst now = ref(Date.now());\nuseIntervalFn(() => {\n now.value = Date.now();\n}, 1000);\n\nconst targetTime = computed(() => {\n if (!props.block.targetDate) return null;\n const date = new Date(props.block.targetDate);\n return isNaN(date.getTime()) ? null : date.getTime();\n});\n\nconst isExpired = computed(() => {\n if (!targetTime.value) return false;\n return now.value >= targetTime.value;\n});\n\nconst remaining = computed(() => {\n if (!targetTime.value || isExpired.value) {\n return { days: 0, hours: 0, minutes: 0, seconds: 0 };\n }\n const diff = targetTime.value - now.value;\n const totalSeconds = Math.floor(diff / 1000);\n return {\n days: Math.floor(totalSeconds / 86400),\n hours: Math.floor((totalSeconds % 86400) / 3600),\n minutes: Math.floor((totalSeconds % 3600) / 60),\n seconds: totalSeconds % 60,\n };\n});\n\nconst segments = computed(() => {\n const result: Array<{ value: string; label: string }> = [];\n if (props.block.showDays) {\n result.push({\n value: String(remaining.value.days).padStart(2, \"0\"),\n label: props.block.labelDays,\n });\n }\n if (props.block.showHours) {\n result.push({\n value: String(remaining.value.hours).padStart(2, \"0\"),\n label: props.block.labelHours,\n });\n }\n if (props.block.showMinutes) {\n result.push({\n value: String(remaining.value.minutes).padStart(2, \"0\"),\n label: props.block.labelMinutes,\n });\n }\n if (props.block.showSeconds) {\n result.push({\n value: String(remaining.value.seconds).padStart(2, \"0\"),\n label: props.block.labelSeconds,\n });\n }\n return result;\n});\n\nconst containerStyle = computed(() => ({\n backgroundColor: props.block.backgroundColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n\nconst digitStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n fontWeight: \"bold\" as const,\n color: props.block.digitColor,\n lineHeight: \"1.2\",\n}));\n\nconst labelStyle = computed(() => ({\n fontSize: `${props.block.labelFontSize}px`,\n color: props.block.labelColor,\n marginTop: \"4px\",\n}));\n\nconst separatorStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n color: props.block.digitColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n</script>\n\n<template>\n <!-- Empty state: no target date -->\n <div\n v-if=\"!block.targetDate\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-8 tpl:text-sm tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.countdown.setDate }}\n </div>\n\n <!-- Expired + hidden -->\n <div\n v-else-if=\"isExpired && block.hideOnExpiry\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-4 tpl:text-xs tpl:text-[var(--tpl-text-dim)] tpl:opacity-50\"\n >\n {{ t.countdown.hidden }}\n </div>\n\n <!-- Expired with message -->\n <div\n v-else-if=\"isExpired\"\n :style=\"containerStyle\"\n class=\"tpl:py-4 tpl:text-center\"\n >\n <span\n :style=\"{\n fontSize: `${block.digitFontSize}px`,\n color: block.digitColor,\n }\"\n >\n {{ block.expiredMessage }}\n </span>\n </div>\n\n <!-- Active countdown -->\n <div\n v-else\n :style=\"containerStyle\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-2 tpl:py-4\"\n >\n <template v-for=\"(segment, index) in segments\" :key=\"segment.label\">\n <span v-if=\"index > 0\" :style=\"separatorStyle\" class=\"tpl:self-start\">\n {{ block.separator }}\n </span>\n <div class=\"tpl:text-center\">\n <div :style=\"digitStyle\">{{ segment.value }}</div>\n <div :style=\"labelStyle\">{{ segment.label }}</div>\n </div>\n </template>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CountdownBlock-BeHkO19t.js","names":[],"sources":["../../../src/components/blocks/CountdownBlock.vue","../../../src/components/blocks/CountdownBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type {\n CountdownBlock as CountdownBlockType,\n ViewportSize,\n} from \"@templatical/types\";\nimport { useIntervalFn } from \"@vueuse/core\";\nimport { computed, ref } from \"vue\";\nimport { useI18n } from \"../../composables/useI18n\";\n\nconst props = defineProps<{\n block: CountdownBlockType;\n viewport: ViewportSize;\n}>();\n\nconst { t } = useI18n();\n\nconst now = ref(Date.now());\nuseIntervalFn(() => {\n now.value = Date.now();\n}, 1000);\n\nconst targetTime = computed(() => {\n if (!props.block.targetDate) return null;\n const date = new Date(props.block.targetDate);\n return isNaN(date.getTime()) ? null : date.getTime();\n});\n\nconst isExpired = computed(() => {\n if (!targetTime.value) return false;\n return now.value >= targetTime.value;\n});\n\nconst remaining = computed(() => {\n if (!targetTime.value || isExpired.value) {\n return { days: 0, hours: 0, minutes: 0, seconds: 0 };\n }\n const diff = targetTime.value - now.value;\n const totalSeconds = Math.floor(diff / 1000);\n return {\n days: Math.floor(totalSeconds / 86400),\n hours: Math.floor((totalSeconds % 86400) / 3600),\n minutes: Math.floor((totalSeconds % 3600) / 60),\n seconds: totalSeconds % 60,\n };\n});\n\nconst segments = computed(() => {\n const result: Array<{ value: string; label: string }> = [];\n if (props.block.showDays) {\n result.push({\n value: String(remaining.value.days).padStart(2, \"0\"),\n label: props.block.labelDays,\n });\n }\n if (props.block.showHours) {\n result.push({\n value: String(remaining.value.hours).padStart(2, \"0\"),\n label: props.block.labelHours,\n });\n }\n if (props.block.showMinutes) {\n result.push({\n value: String(remaining.value.minutes).padStart(2, \"0\"),\n label: props.block.labelMinutes,\n });\n }\n if (props.block.showSeconds) {\n result.push({\n value: String(remaining.value.seconds).padStart(2, \"0\"),\n label: props.block.labelSeconds,\n });\n }\n return result;\n});\n\nconst containerStyle = computed(() => ({\n backgroundColor: props.block.backgroundColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n\nconst digitStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n fontWeight: \"bold\" as const,\n color: props.block.digitColor,\n lineHeight: \"1.2\",\n}));\n\nconst labelStyle = computed(() => ({\n fontSize: `${props.block.labelFontSize}px`,\n color: props.block.labelColor,\n marginTop: \"4px\",\n}));\n\nconst separatorStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n color: props.block.digitColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n</script>\n\n<template>\n <!-- Empty state: no target date -->\n <div\n v-if=\"!block.targetDate\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-8 tpl:text-sm tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.countdown.setDate }}\n </div>\n\n <!-- Expired + hidden -->\n <div\n v-else-if=\"isExpired && block.hideOnExpiry\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-4 tpl:text-xs tpl:text-[var(--tpl-text-dim)] tpl:opacity-50\"\n >\n {{ t.countdown.hidden }}\n </div>\n\n <!-- Expired with message -->\n <div\n v-else-if=\"isExpired\"\n :style=\"containerStyle\"\n class=\"tpl:py-4 tpl:text-center\"\n >\n <span\n :style=\"{\n fontSize: `${block.digitFontSize}px`,\n color: block.digitColor,\n }\"\n >\n {{ block.expiredMessage }}\n </span>\n </div>\n\n <!-- Active countdown -->\n <div\n v-else\n :style=\"containerStyle\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-2 tpl:py-4\"\n >\n <template v-for=\"(segment, index) in segments\" :key=\"segment.label\">\n <span v-if=\"index > 0\" :style=\"separatorStyle\" class=\"tpl:self-start\">\n {{ block.separator }}\n </span>\n <div class=\"tpl:text-center\">\n <div :style=\"digitStyle\">{{ segment.value }}</div>\n <div :style=\"labelStyle\">{{ segment.label }}</div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type {\n CountdownBlock as CountdownBlockType,\n ViewportSize,\n} from \"@templatical/types\";\nimport { useIntervalFn } from \"@vueuse/core\";\nimport { computed, ref } from \"vue\";\nimport { useI18n } from \"../../composables/useI18n\";\n\nconst props = defineProps<{\n block: CountdownBlockType;\n viewport: ViewportSize;\n}>();\n\nconst { t } = useI18n();\n\nconst now = ref(Date.now());\nuseIntervalFn(() => {\n now.value = Date.now();\n}, 1000);\n\nconst targetTime = computed(() => {\n if (!props.block.targetDate) return null;\n const date = new Date(props.block.targetDate);\n return isNaN(date.getTime()) ? null : date.getTime();\n});\n\nconst isExpired = computed(() => {\n if (!targetTime.value) return false;\n return now.value >= targetTime.value;\n});\n\nconst remaining = computed(() => {\n if (!targetTime.value || isExpired.value) {\n return { days: 0, hours: 0, minutes: 0, seconds: 0 };\n }\n const diff = targetTime.value - now.value;\n const totalSeconds = Math.floor(diff / 1000);\n return {\n days: Math.floor(totalSeconds / 86400),\n hours: Math.floor((totalSeconds % 86400) / 3600),\n minutes: Math.floor((totalSeconds % 3600) / 60),\n seconds: totalSeconds % 60,\n };\n});\n\nconst segments = computed(() => {\n const result: Array<{ value: string; label: string }> = [];\n if (props.block.showDays) {\n result.push({\n value: String(remaining.value.days).padStart(2, \"0\"),\n label: props.block.labelDays,\n });\n }\n if (props.block.showHours) {\n result.push({\n value: String(remaining.value.hours).padStart(2, \"0\"),\n label: props.block.labelHours,\n });\n }\n if (props.block.showMinutes) {\n result.push({\n value: String(remaining.value.minutes).padStart(2, \"0\"),\n label: props.block.labelMinutes,\n });\n }\n if (props.block.showSeconds) {\n result.push({\n value: String(remaining.value.seconds).padStart(2, \"0\"),\n label: props.block.labelSeconds,\n });\n }\n return result;\n});\n\nconst containerStyle = computed(() => ({\n backgroundColor: props.block.backgroundColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n\nconst digitStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n fontWeight: \"bold\" as const,\n color: props.block.digitColor,\n lineHeight: \"1.2\",\n}));\n\nconst labelStyle = computed(() => ({\n fontSize: `${props.block.labelFontSize}px`,\n color: props.block.labelColor,\n marginTop: \"4px\",\n}));\n\nconst separatorStyle = computed(() => ({\n fontSize: `${props.block.digitFontSize}px`,\n color: props.block.digitColor,\n fontFamily: props.block.fontFamily || \"inherit\",\n}));\n</script>\n\n<template>\n <!-- Empty state: no target date -->\n <div\n v-if=\"!block.targetDate\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-8 tpl:text-sm tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.countdown.setDate }}\n </div>\n\n <!-- Expired + hidden -->\n <div\n v-else-if=\"isExpired && block.hideOnExpiry\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:py-4 tpl:text-xs tpl:text-[var(--tpl-text-dim)] tpl:opacity-50\"\n >\n {{ t.countdown.hidden }}\n </div>\n\n <!-- Expired with message -->\n <div\n v-else-if=\"isExpired\"\n :style=\"containerStyle\"\n class=\"tpl:py-4 tpl:text-center\"\n >\n <span\n :style=\"{\n fontSize: `${block.digitFontSize}px`,\n color: block.digitColor,\n }\"\n >\n {{ block.expiredMessage }}\n </span>\n </div>\n\n <!-- Active countdown -->\n <div\n v-else\n :style=\"containerStyle\"\n class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-2 tpl:py-4\"\n >\n <template v-for=\"(segment, index) in segments\" :key=\"segment.label\">\n <span v-if=\"index > 0\" :style=\"separatorStyle\" class=\"tpl:self-start\">\n {{ block.separator }}\n </span>\n <div class=\"tpl:text-center\">\n <div :style=\"digitStyle\">{{ segment.value }}</div>\n <div :style=\"labelStyle\">{{ segment.label }}</div>\n </div>\n </template>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { M as e, P as t, V as n, at as r, f as i, g as a, m as o, p as s, rt as c, st as l, u, v as d, x as f, y as p } from "./draggable-CNhyCGIO.js";
|
|
2
|
-
import { Nt as m } from "./features-
|
|
2
|
+
import { Nt as m } from "./features-D6FoOm8v.js";
|
|
3
3
|
import { f as h } from "./styleConstants-DP1VOca8.js";
|
|
4
|
-
import { i as g, n as _, r as v, t as y } from "./NumberWithSuffix-
|
|
4
|
+
import { i as g, n as _, r as v, t as y } from "./NumberWithSuffix-BSOUOUCL.js";
|
|
5
5
|
//#region src/components/toolbar/CheckboxItem.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var b = { class: "tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:text-[12px] tpl:text-[var(--tpl-text)]" }, x = ["checked"], S = /* @__PURE__ */ f({
|
|
7
7
|
__name: "CheckboxItem",
|
|
@@ -209,4 +209,4 @@ var b = { class: "tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:tex
|
|
|
209
209
|
//#endregion
|
|
210
210
|
export { I as default };
|
|
211
211
|
|
|
212
|
-
//# sourceMappingURL=CountdownToolbar-
|
|
212
|
+
//# sourceMappingURL=CountdownToolbar-8UfW0jb1.js.map
|
package/dist/cdn/chunks/{CountdownToolbar-DbknNrIi.js.map → CountdownToolbar-8UfW0jb1.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountdownToolbar-DbknNrIi.js","names":[],"sources":["../../../src/components/toolbar/CheckboxItem.vue","../../../src/components/toolbar/CheckboxItem.vue","../../../src/components/toolbar/CountdownToolbar.vue","../../../src/components/toolbar/CountdownToolbar.vue"],"sourcesContent":["<script setup lang=\"ts\">\ndefineProps<{\n modelValue: boolean;\n label: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: boolean): void;\n}>();\n</script>\n\n<template>\n <label\n class=\"tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:text-[12px] tpl:text-[var(--tpl-text)]\"\n >\n <input\n type=\"checkbox\"\n class=\"tpl:size-3.5 tpl:cursor-pointer tpl:accent-[var(--tpl-primary)]\"\n :checked=\"modelValue\"\n @change=\"\n emit('update:modelValue', ($event.target as HTMLInputElement).checked)\n \"\n />\n {{ label }}\n </label>\n</template>\n","<script setup lang=\"ts\">\ndefineProps<{\n modelValue: boolean;\n label: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: boolean): void;\n}>();\n</script>\n\n<template>\n <label\n class=\"tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:text-[12px] tpl:text-[var(--tpl-text)]\"\n >\n <input\n type=\"checkbox\"\n class=\"tpl:size-3.5 tpl:cursor-pointer tpl:accent-[var(--tpl-primary)]\"\n :checked=\"modelValue\"\n @change=\"\n emit('update:modelValue', ($event.target as HTMLInputElement).checked)\n \"\n />\n {{ label }}\n </label>\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport SlidingPillSelect from \"../SlidingPillSelect.vue\";\nimport FieldRow from \"./FieldRow.vue\";\nimport CheckboxItem from \"./CheckboxItem.vue\";\nimport NumberWithSuffix from \"./NumberWithSuffix.vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { inputClass } from \"../../constants/styleConstants\";\nimport type { CountdownBlock } from \"@templatical/types\";\nimport { computed } from \"vue\";\n\ndefineProps<{\n block: CountdownBlock;\n fontFamilies: Array<{ value: string; label: string }>;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update\", updates: Partial<CountdownBlock>): void;\n}>();\n\nconst { t } = useI18n();\n\nconst TIMEZONES = [\n \"UTC\",\n \"America/New_York\",\n \"America/Chicago\",\n \"America/Denver\",\n \"America/Los_Angeles\",\n \"Europe/London\",\n \"Europe/Berlin\",\n \"Europe/Paris\",\n \"Europe/Moscow\",\n \"Asia/Dubai\",\n \"Asia/Kolkata\",\n \"Asia/Shanghai\",\n \"Asia/Tokyo\",\n \"Australia/Sydney\",\n \"Pacific/Auckland\",\n];\n\nconst SEPARATORS = [\n { value: \":\", label: \":\" },\n { value: \"-\", label: \"-\" },\n { value: \" \", label: \"␣\" },\n];\n\ntype UnitKey = \"Days\" | \"Hours\" | \"Minutes\" | \"Seconds\";\nconst UNITS: UnitKey[] = [\"Days\", \"Hours\", \"Minutes\", \"Seconds\"];\n\nconst unitItems = computed(() =>\n UNITS.map((unit) => ({\n unit,\n showKey: `show${unit}` as const,\n labelKey: `label${unit}` as const,\n translationKey: unit.toLowerCase() as\n | \"days\"\n | \"hours\"\n | \"minutes\"\n | \"seconds\",\n })),\n);\n\nfunction updateField(field: keyof CountdownBlock, value: unknown): void {\n emit(\"update\", { [field]: value } as Partial<CountdownBlock>);\n}\n</script>\n\n<template>\n <FieldRow :label=\"t.countdown.targetDate\">\n <input\n type=\"datetime-local\"\n :class=\"inputClass\"\n :value=\"block.targetDate\"\n @input=\"\n updateField('targetDate', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.timezone\">\n <select\n :class=\"inputClass\"\n :value=\"block.timezone\"\n @change=\"\n updateField('timezone', ($event.target as HTMLSelectElement).value)\n \"\n >\n <option v-for=\"tz in TIMEZONES\" :key=\"tz\" :value=\"tz\">{{ tz }}</option>\n </select>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.display\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <CheckboxItem\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n :model-value=\"block[item.showKey]\"\n :label=\"t.countdown[item.translationKey]\"\n @update:model-value=\"updateField(item.showKey, $event)\"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.separator\">\n <SlidingPillSelect\n :options=\"SEPARATORS\"\n :model-value=\"block.separator\"\n @update:model-value=\"updateField('separator', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.fontFamily\">\n <select\n :class=\"inputClass\"\n :value=\"block.fontFamily || ''\"\n @change=\"\n updateField(\n 'fontFamily',\n ($event.target as HTMLSelectElement).value || undefined,\n )\n \"\n >\n <option value=\"\">{{ t.countdown.inheritFont }}</option>\n <option\n v-for=\"font in fontFamilies\"\n :key=\"font.value\"\n :value=\"font.value\"\n >\n {{ font.label }}\n </option>\n </select>\n </FieldRow>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitFontSize\">\n <NumberWithSuffix\n :model-value=\"block.digitFontSize\"\n :min=\"12\"\n :max=\"72\"\n suffix=\"px\"\n @update:model-value=\"updateField('digitFontSize', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelFontSize\">\n <NumberWithSuffix\n :model-value=\"block.labelFontSize\"\n :min=\"8\"\n :max=\"24\"\n suffix=\"px\"\n @update:model-value=\"updateField('labelFontSize', $event)\"\n />\n </FieldRow>\n </div>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitColor\">\n <ColorPicker\n :model-value=\"block.digitColor\"\n @update:model-value=\"updateField('digitColor', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelColor\">\n <ColorPicker\n :model-value=\"block.labelColor\"\n @update:model-value=\"updateField('labelColor', $event)\"\n />\n </FieldRow>\n </div>\n\n <FieldRow :label=\"t.countdown.background\">\n <ColorPicker\n :model-value=\"block.backgroundColor\"\n @update:model-value=\"updateField('backgroundColor', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.labels\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <input\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block[item.labelKey]\"\n :placeholder=\"t.countdown[item.translationKey]\"\n @input=\"\n updateField(item.labelKey, ($event.target as HTMLInputElement).value)\n \"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiry\">\n <input\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block.expiredMessage\"\n :placeholder=\"t.countdown.expiredMessagePlaceholder\"\n @input=\"\n updateField('expiredMessage', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiredImageUrl\">\n <input\n type=\"url\"\n :class=\"inputClass\"\n :value=\"block.expiredImageUrl\"\n placeholder=\"https://...\"\n @input=\"\n updateField(\n 'expiredImageUrl',\n ($event.target as HTMLInputElement).value,\n )\n \"\n />\n </FieldRow>\n\n <CheckboxItem\n :model-value=\"block.hideOnExpiry\"\n :label=\"t.countdown.hideOnExpiry\"\n class=\"tpl:mb-3.5\"\n @update:model-value=\"updateField('hideOnExpiry', $event)\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport SlidingPillSelect from \"../SlidingPillSelect.vue\";\nimport FieldRow from \"./FieldRow.vue\";\nimport CheckboxItem from \"./CheckboxItem.vue\";\nimport NumberWithSuffix from \"./NumberWithSuffix.vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { inputClass } from \"../../constants/styleConstants\";\nimport type { CountdownBlock } from \"@templatical/types\";\nimport { computed } from \"vue\";\n\ndefineProps<{\n block: CountdownBlock;\n fontFamilies: Array<{ value: string; label: string }>;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update\", updates: Partial<CountdownBlock>): void;\n}>();\n\nconst { t } = useI18n();\n\nconst TIMEZONES = [\n \"UTC\",\n \"America/New_York\",\n \"America/Chicago\",\n \"America/Denver\",\n \"America/Los_Angeles\",\n \"Europe/London\",\n \"Europe/Berlin\",\n \"Europe/Paris\",\n \"Europe/Moscow\",\n \"Asia/Dubai\",\n \"Asia/Kolkata\",\n \"Asia/Shanghai\",\n \"Asia/Tokyo\",\n \"Australia/Sydney\",\n \"Pacific/Auckland\",\n];\n\nconst SEPARATORS = [\n { value: \":\", label: \":\" },\n { value: \"-\", label: \"-\" },\n { value: \" \", label: \"␣\" },\n];\n\ntype UnitKey = \"Days\" | \"Hours\" | \"Minutes\" | \"Seconds\";\nconst UNITS: UnitKey[] = [\"Days\", \"Hours\", \"Minutes\", \"Seconds\"];\n\nconst unitItems = computed(() =>\n UNITS.map((unit) => ({\n unit,\n showKey: `show${unit}` as const,\n labelKey: `label${unit}` as const,\n translationKey: unit.toLowerCase() as\n | \"days\"\n | \"hours\"\n | \"minutes\"\n | \"seconds\",\n })),\n);\n\nfunction updateField(field: keyof CountdownBlock, value: unknown): void {\n emit(\"update\", { [field]: value } as Partial<CountdownBlock>);\n}\n</script>\n\n<template>\n <FieldRow :label=\"t.countdown.targetDate\">\n <input\n type=\"datetime-local\"\n :class=\"inputClass\"\n :value=\"block.targetDate\"\n @input=\"\n updateField('targetDate', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.timezone\">\n <select\n :class=\"inputClass\"\n :value=\"block.timezone\"\n @change=\"\n updateField('timezone', ($event.target as HTMLSelectElement).value)\n \"\n >\n <option v-for=\"tz in TIMEZONES\" :key=\"tz\" :value=\"tz\">{{ tz }}</option>\n </select>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.display\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <CheckboxItem\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n :model-value=\"block[item.showKey]\"\n :label=\"t.countdown[item.translationKey]\"\n @update:model-value=\"updateField(item.showKey, $event)\"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.separator\">\n <SlidingPillSelect\n :options=\"SEPARATORS\"\n :model-value=\"block.separator\"\n @update:model-value=\"updateField('separator', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.fontFamily\">\n <select\n :class=\"inputClass\"\n :value=\"block.fontFamily || ''\"\n @change=\"\n updateField(\n 'fontFamily',\n ($event.target as HTMLSelectElement).value || undefined,\n )\n \"\n >\n <option value=\"\">{{ t.countdown.inheritFont }}</option>\n <option\n v-for=\"font in fontFamilies\"\n :key=\"font.value\"\n :value=\"font.value\"\n >\n {{ font.label }}\n </option>\n </select>\n </FieldRow>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitFontSize\">\n <NumberWithSuffix\n :model-value=\"block.digitFontSize\"\n :min=\"12\"\n :max=\"72\"\n suffix=\"px\"\n @update:model-value=\"updateField('digitFontSize', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelFontSize\">\n <NumberWithSuffix\n :model-value=\"block.labelFontSize\"\n :min=\"8\"\n :max=\"24\"\n suffix=\"px\"\n @update:model-value=\"updateField('labelFontSize', $event)\"\n />\n </FieldRow>\n </div>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitColor\">\n <ColorPicker\n :model-value=\"block.digitColor\"\n @update:model-value=\"updateField('digitColor', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelColor\">\n <ColorPicker\n :model-value=\"block.labelColor\"\n @update:model-value=\"updateField('labelColor', $event)\"\n />\n </FieldRow>\n </div>\n\n <FieldRow :label=\"t.countdown.background\">\n <ColorPicker\n :model-value=\"block.backgroundColor\"\n @update:model-value=\"updateField('backgroundColor', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.labels\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <input\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block[item.labelKey]\"\n :placeholder=\"t.countdown[item.translationKey]\"\n @input=\"\n updateField(item.labelKey, ($event.target as HTMLInputElement).value)\n \"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiry\">\n <input\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block.expiredMessage\"\n :placeholder=\"t.countdown.expiredMessagePlaceholder\"\n @input=\"\n updateField('expiredMessage', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiredImageUrl\">\n <input\n type=\"url\"\n :class=\"inputClass\"\n :value=\"block.expiredImageUrl\"\n placeholder=\"https://...\"\n @input=\"\n updateField(\n 'expiredImageUrl',\n ($event.target as HTMLInputElement).value,\n )\n \"\n />\n </FieldRow>\n\n <CheckboxItem\n :model-value=\"block.hideOnExpiry\"\n :label=\"t.countdown.hideOnExpiry\"\n class=\"tpl:mb-3.5\"\n @update:model-value=\"updateField('hideOnExpiry', $event)\"\n />\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CountdownToolbar-8UfW0jb1.js","names":[],"sources":["../../../src/components/toolbar/CheckboxItem.vue","../../../src/components/toolbar/CheckboxItem.vue","../../../src/components/toolbar/CountdownToolbar.vue","../../../src/components/toolbar/CountdownToolbar.vue"],"sourcesContent":["<script setup lang=\"ts\">\ndefineProps<{\n modelValue: boolean;\n label: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: boolean): void;\n}>();\n</script>\n\n<template>\n <label\n class=\"tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:text-[12px] tpl:text-[var(--tpl-text)]\"\n >\n <input\n type=\"checkbox\"\n class=\"tpl:size-3.5 tpl:cursor-pointer tpl:accent-[var(--tpl-primary)]\"\n :checked=\"modelValue\"\n @change=\"\n emit('update:modelValue', ($event.target as HTMLInputElement).checked)\n \"\n />\n {{ label }}\n </label>\n</template>\n","<script setup lang=\"ts\">\ndefineProps<{\n modelValue: boolean;\n label: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: boolean): void;\n}>();\n</script>\n\n<template>\n <label\n class=\"tpl:flex tpl:cursor-pointer tpl:items-center tpl:gap-2 tpl:text-[12px] tpl:text-[var(--tpl-text)]\"\n >\n <input\n type=\"checkbox\"\n class=\"tpl:size-3.5 tpl:cursor-pointer tpl:accent-[var(--tpl-primary)]\"\n :checked=\"modelValue\"\n @change=\"\n emit('update:modelValue', ($event.target as HTMLInputElement).checked)\n \"\n />\n {{ label }}\n </label>\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport SlidingPillSelect from \"../SlidingPillSelect.vue\";\nimport FieldRow from \"./FieldRow.vue\";\nimport CheckboxItem from \"./CheckboxItem.vue\";\nimport NumberWithSuffix from \"./NumberWithSuffix.vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { inputClass } from \"../../constants/styleConstants\";\nimport type { CountdownBlock } from \"@templatical/types\";\nimport { computed } from \"vue\";\n\ndefineProps<{\n block: CountdownBlock;\n fontFamilies: Array<{ value: string; label: string }>;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update\", updates: Partial<CountdownBlock>): void;\n}>();\n\nconst { t } = useI18n();\n\nconst TIMEZONES = [\n \"UTC\",\n \"America/New_York\",\n \"America/Chicago\",\n \"America/Denver\",\n \"America/Los_Angeles\",\n \"Europe/London\",\n \"Europe/Berlin\",\n \"Europe/Paris\",\n \"Europe/Moscow\",\n \"Asia/Dubai\",\n \"Asia/Kolkata\",\n \"Asia/Shanghai\",\n \"Asia/Tokyo\",\n \"Australia/Sydney\",\n \"Pacific/Auckland\",\n];\n\nconst SEPARATORS = [\n { value: \":\", label: \":\" },\n { value: \"-\", label: \"-\" },\n { value: \" \", label: \"␣\" },\n];\n\ntype UnitKey = \"Days\" | \"Hours\" | \"Minutes\" | \"Seconds\";\nconst UNITS: UnitKey[] = [\"Days\", \"Hours\", \"Minutes\", \"Seconds\"];\n\nconst unitItems = computed(() =>\n UNITS.map((unit) => ({\n unit,\n showKey: `show${unit}` as const,\n labelKey: `label${unit}` as const,\n translationKey: unit.toLowerCase() as\n | \"days\"\n | \"hours\"\n | \"minutes\"\n | \"seconds\",\n })),\n);\n\nfunction updateField(field: keyof CountdownBlock, value: unknown): void {\n emit(\"update\", { [field]: value } as Partial<CountdownBlock>);\n}\n</script>\n\n<template>\n <FieldRow :label=\"t.countdown.targetDate\">\n <input\n type=\"datetime-local\"\n :class=\"inputClass\"\n :value=\"block.targetDate\"\n @input=\"\n updateField('targetDate', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.timezone\">\n <select\n :class=\"inputClass\"\n :value=\"block.timezone\"\n @change=\"\n updateField('timezone', ($event.target as HTMLSelectElement).value)\n \"\n >\n <option v-for=\"tz in TIMEZONES\" :key=\"tz\" :value=\"tz\">{{ tz }}</option>\n </select>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.display\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <CheckboxItem\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n :model-value=\"block[item.showKey]\"\n :label=\"t.countdown[item.translationKey]\"\n @update:model-value=\"updateField(item.showKey, $event)\"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.separator\">\n <SlidingPillSelect\n :options=\"SEPARATORS\"\n :model-value=\"block.separator\"\n @update:model-value=\"updateField('separator', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.fontFamily\">\n <select\n :class=\"inputClass\"\n :value=\"block.fontFamily || ''\"\n @change=\"\n updateField(\n 'fontFamily',\n ($event.target as HTMLSelectElement).value || undefined,\n )\n \"\n >\n <option value=\"\">{{ t.countdown.inheritFont }}</option>\n <option\n v-for=\"font in fontFamilies\"\n :key=\"font.value\"\n :value=\"font.value\"\n >\n {{ font.label }}\n </option>\n </select>\n </FieldRow>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitFontSize\">\n <NumberWithSuffix\n :model-value=\"block.digitFontSize\"\n :min=\"12\"\n :max=\"72\"\n suffix=\"px\"\n @update:model-value=\"updateField('digitFontSize', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelFontSize\">\n <NumberWithSuffix\n :model-value=\"block.labelFontSize\"\n :min=\"8\"\n :max=\"24\"\n suffix=\"px\"\n @update:model-value=\"updateField('labelFontSize', $event)\"\n />\n </FieldRow>\n </div>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitColor\">\n <ColorPicker\n :model-value=\"block.digitColor\"\n @update:model-value=\"updateField('digitColor', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelColor\">\n <ColorPicker\n :model-value=\"block.labelColor\"\n @update:model-value=\"updateField('labelColor', $event)\"\n />\n </FieldRow>\n </div>\n\n <FieldRow :label=\"t.countdown.background\">\n <ColorPicker\n :model-value=\"block.backgroundColor\"\n @update:model-value=\"updateField('backgroundColor', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.labels\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <input\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block[item.labelKey]\"\n :placeholder=\"t.countdown[item.translationKey]\"\n @input=\"\n updateField(item.labelKey, ($event.target as HTMLInputElement).value)\n \"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiry\">\n <input\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block.expiredMessage\"\n :placeholder=\"t.countdown.expiredMessagePlaceholder\"\n @input=\"\n updateField('expiredMessage', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiredImageUrl\">\n <input\n type=\"url\"\n :class=\"inputClass\"\n :value=\"block.expiredImageUrl\"\n placeholder=\"https://...\"\n @input=\"\n updateField(\n 'expiredImageUrl',\n ($event.target as HTMLInputElement).value,\n )\n \"\n />\n </FieldRow>\n\n <CheckboxItem\n :model-value=\"block.hideOnExpiry\"\n :label=\"t.countdown.hideOnExpiry\"\n class=\"tpl:mb-3.5\"\n @update:model-value=\"updateField('hideOnExpiry', $event)\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport SlidingPillSelect from \"../SlidingPillSelect.vue\";\nimport FieldRow from \"./FieldRow.vue\";\nimport CheckboxItem from \"./CheckboxItem.vue\";\nimport NumberWithSuffix from \"./NumberWithSuffix.vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { inputClass } from \"../../constants/styleConstants\";\nimport type { CountdownBlock } from \"@templatical/types\";\nimport { computed } from \"vue\";\n\ndefineProps<{\n block: CountdownBlock;\n fontFamilies: Array<{ value: string; label: string }>;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update\", updates: Partial<CountdownBlock>): void;\n}>();\n\nconst { t } = useI18n();\n\nconst TIMEZONES = [\n \"UTC\",\n \"America/New_York\",\n \"America/Chicago\",\n \"America/Denver\",\n \"America/Los_Angeles\",\n \"Europe/London\",\n \"Europe/Berlin\",\n \"Europe/Paris\",\n \"Europe/Moscow\",\n \"Asia/Dubai\",\n \"Asia/Kolkata\",\n \"Asia/Shanghai\",\n \"Asia/Tokyo\",\n \"Australia/Sydney\",\n \"Pacific/Auckland\",\n];\n\nconst SEPARATORS = [\n { value: \":\", label: \":\" },\n { value: \"-\", label: \"-\" },\n { value: \" \", label: \"␣\" },\n];\n\ntype UnitKey = \"Days\" | \"Hours\" | \"Minutes\" | \"Seconds\";\nconst UNITS: UnitKey[] = [\"Days\", \"Hours\", \"Minutes\", \"Seconds\"];\n\nconst unitItems = computed(() =>\n UNITS.map((unit) => ({\n unit,\n showKey: `show${unit}` as const,\n labelKey: `label${unit}` as const,\n translationKey: unit.toLowerCase() as\n | \"days\"\n | \"hours\"\n | \"minutes\"\n | \"seconds\",\n })),\n);\n\nfunction updateField(field: keyof CountdownBlock, value: unknown): void {\n emit(\"update\", { [field]: value } as Partial<CountdownBlock>);\n}\n</script>\n\n<template>\n <FieldRow :label=\"t.countdown.targetDate\">\n <input\n type=\"datetime-local\"\n :class=\"inputClass\"\n :value=\"block.targetDate\"\n @input=\"\n updateField('targetDate', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.timezone\">\n <select\n :class=\"inputClass\"\n :value=\"block.timezone\"\n @change=\"\n updateField('timezone', ($event.target as HTMLSelectElement).value)\n \"\n >\n <option v-for=\"tz in TIMEZONES\" :key=\"tz\" :value=\"tz\">{{ tz }}</option>\n </select>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.display\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <CheckboxItem\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n :model-value=\"block[item.showKey]\"\n :label=\"t.countdown[item.translationKey]\"\n @update:model-value=\"updateField(item.showKey, $event)\"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.separator\">\n <SlidingPillSelect\n :options=\"SEPARATORS\"\n :model-value=\"block.separator\"\n @update:model-value=\"updateField('separator', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.fontFamily\">\n <select\n :class=\"inputClass\"\n :value=\"block.fontFamily || ''\"\n @change=\"\n updateField(\n 'fontFamily',\n ($event.target as HTMLSelectElement).value || undefined,\n )\n \"\n >\n <option value=\"\">{{ t.countdown.inheritFont }}</option>\n <option\n v-for=\"font in fontFamilies\"\n :key=\"font.value\"\n :value=\"font.value\"\n >\n {{ font.label }}\n </option>\n </select>\n </FieldRow>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitFontSize\">\n <NumberWithSuffix\n :model-value=\"block.digitFontSize\"\n :min=\"12\"\n :max=\"72\"\n suffix=\"px\"\n @update:model-value=\"updateField('digitFontSize', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelFontSize\">\n <NumberWithSuffix\n :model-value=\"block.labelFontSize\"\n :min=\"8\"\n :max=\"24\"\n suffix=\"px\"\n @update:model-value=\"updateField('labelFontSize', $event)\"\n />\n </FieldRow>\n </div>\n\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-3\">\n <FieldRow :label=\"t.countdown.digitColor\">\n <ColorPicker\n :model-value=\"block.digitColor\"\n @update:model-value=\"updateField('digitColor', $event)\"\n />\n </FieldRow>\n <FieldRow :label=\"t.countdown.labelColor\">\n <ColorPicker\n :model-value=\"block.labelColor\"\n @update:model-value=\"updateField('labelColor', $event)\"\n />\n </FieldRow>\n </div>\n\n <FieldRow :label=\"t.countdown.background\">\n <ColorPicker\n :model-value=\"block.backgroundColor\"\n @update:model-value=\"updateField('backgroundColor', $event)\"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.labels\">\n <div class=\"tpl:grid tpl:grid-cols-2 tpl:gap-2\">\n <input\n v-for=\"item in unitItems\"\n :key=\"item.unit\"\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block[item.labelKey]\"\n :placeholder=\"t.countdown[item.translationKey]\"\n @input=\"\n updateField(item.labelKey, ($event.target as HTMLInputElement).value)\n \"\n />\n </div>\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiry\">\n <input\n type=\"text\"\n :class=\"inputClass\"\n :value=\"block.expiredMessage\"\n :placeholder=\"t.countdown.expiredMessagePlaceholder\"\n @input=\"\n updateField('expiredMessage', ($event.target as HTMLInputElement).value)\n \"\n />\n </FieldRow>\n\n <FieldRow :label=\"t.countdown.expiredImageUrl\">\n <input\n type=\"url\"\n :class=\"inputClass\"\n :value=\"block.expiredImageUrl\"\n placeholder=\"https://...\"\n @input=\"\n updateField(\n 'expiredImageUrl',\n ($event.target as HTMLInputElement).value,\n )\n \"\n />\n </FieldRow>\n\n <CheckboxItem\n :model-value=\"block.hideOnExpiry\"\n :label=\"t.countdown.hideOnExpiry\"\n class=\"tpl:mb-3.5\"\n @update:model-value=\"updateField('hideOnExpiry', $event)\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;EAMA,IAAM,IAAO;yBAMX,EAYQ,SAZR,GAYQ,CATN,EAOE,SAAA;GANA,MAAK;GACL,OAAM;GACL,SAAS,EAAA;GACT,UAAM,AAAA,EAAA,QAAA,MAAW,EAAI,qBAAuB,EAAO,OAA4B,QAAO;qBAGvF,MACF,EAAG,EAAA,MAAK,EAAA,EAAA,CAAA,CAAA;;;;;;;;;;;;;;EEPZ,IAAM,IAAO,GAIP,EAAE,SAAM,GAAS,EAEjB,IAAY;GAChB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD,EAEK,IAAa;GACjB;IAAE,OAAO;IAAK,OAAO;IAAK;GAC1B;IAAE,OAAO;IAAK,OAAO;IAAK;GAC1B;IAAE,OAAO;IAAK,OAAO;IAAK;GAC3B,EAGK,IAAmB;GAAC;GAAQ;GAAS;GAAW;GAAU,EAE1D,IAAY,QAChB,EAAM,KAAK,OAAU;GACnB;GACA,SAAS,OAAO;GAChB,UAAU,QAAQ;GAClB,gBAAgB,EAAK,aAAa;GAKnC,EAAE,CACJ;EAED,SAAS,EAAY,GAA6B,GAAsB;AACtE,KAAK,UAAU,GAAG,IAAQ,GAAO,CAA4B;;;GAK7D,EASW,GAAA,EATA,OAAO,EAAA,EAAC,CAAC,UAAU,YAAA,EAAA;qBAQ1B,CAPF,EAOE,SAAA;KANA,MAAK;KACJ,OAAK,EAAE,EAAA,EAAU,CAAA;KACjB,OAAO,EAAA,MAAM;KACb,SAAK,AAAA,EAAA,QAAA,MAAW,EAAW,cAAgB,EAAO,OAA4B,MAAK;;;;GAMxF,EAUW,GAAA,EAVA,OAAO,EAAA,EAAC,CAAC,UAAU,UAAA,EAAA;qBASnB,CART,EAQS,UAAA;KAPN,OAAK,EAAE,EAAA,EAAU,CAAA;KACjB,OAAO,EAAA,MAAM;KACb,UAAM,AAAA,EAAA,QAAA,MAAW,EAAW,YAAc,EAAO,OAA6B,MAAK;cAIpF,EAAuE,GAAA,MAAA,EAAlD,IAAN,MAAf,EAAuE,UAAA;KAAtC,KAAK;KAAK,OAAO;SAAO,EAAE,EAAA,GAAA,EAAA;;;GAI/D,EAUW,GAAA,EAVA,OAAO,EAAA,EAAC,CAAC,UAAU,SAAA,EAAA;qBAStB,CARN,EAQM,OARN,GAQM,EAAA,EAAA,GAAA,EAPJ,EAME,GAAA,MAAA,EALe,EAAA,QAAR,YADT,EAME,GAAA;KAJC,KAAK,EAAK;KACV,eAAa,EAAA,MAAM,EAAK;KACxB,OAAO,EAAA,EAAC,CAAC,UAAU,EAAK;KACxB,wBAAkB,MAAE,EAAY,EAAK,SAAS,EAAM;;;;;;;;GAK3D,EAMW,GAAA,EANA,OAAO,EAAA,EAAC,CAAC,UAAU,WAAA,EAAA;qBAK1B,CAJF,EAIE,GAAA;KAHC,SAAS;KACT,eAAa,EAAA,MAAM;KACnB,uBAAkB,AAAA,EAAA,QAAA,MAAE,EAAW,aAAc,EAAM;;;;GAIxD,EAoBW,GAAA,EApBA,OAAO,EAAA,EAAC,CAAC,UAAU,YAAA,EAAA;qBAmBnB,CAlBT,EAkBS,UAAA;KAjBN,OAAK,EAAE,EAAA,EAAU,CAAA;KACjB,OAAO,EAAA,MAAM,cAAU;KACvB,UAAM,AAAA,EAAA,QAAA,MAAW,EAAA,cAAgD,EAAO,OAA6B,SAAS,KAAA,EAAA;QAO/G,EAAuD,UAAvD,GAAuD,EAAnC,EAAA,EAAC,CAAC,UAAU,YAAW,EAAA,EAAA,GAAA,EAAA,GAAA,EAC3C,EAMS,GAAA,MAAA,EALQ,EAAA,eAAR,YADT,EAMS,UAAA;KAJN,KAAK,EAAK;KACV,OAAO,EAAK;SAEV,EAAK,MAAK,EAAA,GAAA,EAAA;;;GAKnB,EAmBM,OAnBN,GAmBM,CAlBJ,EAQW,GAAA,EARA,OAAO,EAAA,EAAC,CAAC,UAAU,eAAA,EAAA;qBAO1B,CANF,EAME,GAAA;KALC,eAAa,EAAA,MAAM;KACnB,KAAK;KACL,KAAK;KACN,QAAO;KACN,uBAAkB,AAAA,EAAA,QAAA,MAAE,EAAW,iBAAkB,EAAM;;;qBAG5D,EAQW,GAAA,EARA,OAAO,EAAA,EAAC,CAAC,UAAU,eAAA,EAAA;qBAO1B,CANF,EAME,GAAA;KALC,eAAa,EAAA,MAAM;KACnB,KAAK;KACL,KAAK;KACN,QAAO;KACN,uBAAkB,AAAA,EAAA,QAAA,MAAE,EAAW,iBAAkB,EAAM;;;;GAK9D,EAaM,OAbN,GAaM,CAZJ,EAKW,GAAA,EALA,OAAO,EAAA,EAAC,CAAC,UAAU,YAAA,EAAA;qBAI1B,CAHF,EAGE,GAAA;KAFC,eAAa,EAAA,MAAM;KACnB,uBAAkB,AAAA,EAAA,QAAA,MAAE,EAAW,cAAe,EAAM;;;qBAGzD,EAKW,GAAA,EALA,OAAO,EAAA,EAAC,CAAC,UAAU,YAAA,EAAA;qBAI1B,CAHF,EAGE,GAAA;KAFC,eAAa,EAAA,MAAM;KACnB,uBAAkB,AAAA,EAAA,QAAA,MAAE,EAAW,cAAe,EAAM;;;;GAK3D,EAKW,GAAA,EALA,OAAO,EAAA,EAAC,CAAC,UAAU,YAAA,EAAA;qBAI1B,CAHF,EAGE,GAAA;KAFC,eAAa,EAAA,MAAM;KACnB,uBAAkB,AAAA,EAAA,QAAA,MAAE,EAAW,mBAAoB,EAAM;;;;GAI9D,EAcW,GAAA,EAdA,OAAO,EAAA,EAAC,CAAC,UAAU,QAAA,EAAA;qBAatB,CAZN,EAYM,OAZN,GAYM,EAAA,EAAA,GAAA,EAXJ,EAUE,GAAA,MAAA,EATe,EAAA,QAAR,YADT,EAUE,SAAA;KARC,KAAK,EAAK;KACX,MAAK;KACJ,OAAK,EAAE,EAAA,EAAU,CAAA;KACjB,OAAO,EAAA,MAAM,EAAK;KAClB,aAAa,EAAA,EAAC,CAAC,UAAU,EAAK;KAC9B,UAAK,MAAa,EAAY,EAAK,UAAW,EAAO,OAA4B,MAAK;;;;GAO7F,EAUW,GAAA,EAVA,OAAO,EAAA,EAAC,CAAC,UAAU,QAAA,EAAA;qBAS1B,CARF,EAQE,SAAA;KAPA,MAAK;KACJ,OAAK,EAAE,EAAA,EAAU,CAAA;KACjB,OAAO,EAAA,MAAM;KACb,aAAa,EAAA,EAAC,CAAC,UAAU;KACzB,SAAK,AAAA,EAAA,QAAA,MAAW,EAAW,kBAAoB,EAAO,OAA4B,MAAK;;;;GAM5F,EAaW,GAAA,EAbA,OAAO,EAAA,EAAC,CAAC,UAAU,iBAAA,EAAA;qBAY1B,CAXF,EAWE,SAAA;KAVA,MAAK;KACJ,OAAK,EAAE,EAAA,EAAU,CAAA;KACjB,OAAO,EAAA,MAAM;KACd,aAAY;KACX,SAAK,AAAA,EAAA,SAAA,MAAW,EAAA,mBAAqD,EAAO,OAA4B,MAAA;;;;GAS7G,EAKE,GAAA;IAJC,eAAa,EAAA,MAAM;IACnB,OAAO,EAAA,EAAC,CAAC,UAAU;IACpB,OAAM;IACL,uBAAkB,AAAA,EAAA,SAAA,MAAE,EAAW,gBAAiB,EAAM"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { H as e, L as t, M as n, P as r, V as ee, Z as i, a as te, b as a, f as o, g as s, h as ne, l as c, m as l, o as re, ot as ie, p as u, rt as d, st as f, u as p, x as m, y as h, z as ae } from "./draggable-CNhyCGIO.js";
|
|
2
|
-
import { $ as oe, Kt as se, Nt as ce, Xt as le, en as g, i as ue, ot as de, rt as fe } from "./features-
|
|
3
|
-
import { b as pe, j as _ } from "./icons-
|
|
4
|
-
import { t as v } from "./blockTypeIcons-
|
|
2
|
+
import { $ as oe, Kt as se, Nt as ce, Xt as le, en as g, i as ue, ot as de, rt as fe } from "./features-D6FoOm8v.js";
|
|
3
|
+
import { b as pe, j as _ } from "./icons-CpsjWPU-.js";
|
|
4
|
+
import { t as v } from "./blockTypeIcons-DfOffaYP.js";
|
|
5
5
|
//#region src/cloud/components/ModuleBrowserModal.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var me = {
|
|
7
7
|
role: "dialog",
|
|
@@ -40,7 +40,7 @@ var me = {
|
|
|
40
40
|
props: { visible: { type: Boolean } },
|
|
41
41
|
emits: ["close", "insert"],
|
|
42
42
|
setup(m, { emit: B }) {
|
|
43
|
-
let Te = m, V = B, Ee = a(() => import("./ModulePreviewCanvas-
|
|
43
|
+
let Te = m, V = B, Ee = a(() => import("./ModulePreviewCanvas-CxSc7Pvd.js")), { t: De } = ce(), { t: H } = oe(), U = g(le, "ModuleBrowserModal"), W = g(se, "ModuleBrowserModal"), G = i(""), K = i(null), q = i(null), J = i("end"), Y = o(() => {
|
|
44
44
|
let e = U.modules.value;
|
|
45
45
|
if (!G.value) return e;
|
|
46
46
|
let t = G.value.toLowerCase();
|
|
@@ -192,4 +192,4 @@ var me = {
|
|
|
192
192
|
//#endregion
|
|
193
193
|
export { B as default };
|
|
194
194
|
|
|
195
|
-
//# sourceMappingURL=ModuleBrowserModal-
|
|
195
|
+
//# sourceMappingURL=ModuleBrowserModal-BMUyAmmj.js.map
|
package/dist/cdn/chunks/{ModuleBrowserModal-BvAuW8O5.js.map → ModuleBrowserModal-BMUyAmmj.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModuleBrowserModal-BvAuW8O5.js","names":[],"sources":["../../../src/cloud/components/ModuleBrowserModal.vue","../../../src/cloud/components/ModuleBrowserModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport TplModal from \"./TplModal.vue\";\nimport { useI18n } from \"../../composables\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { blockTypeIcons } from \"../../utils/blockTypeIcons\";\nimport {\n SAVED_MODULES_HEADLESS_KEY,\n EDITOR_KEY,\n requireInject,\n} from \"../../keys\";\nimport type { SavedModule } from \"@templatical/types\";\nimport { Package, Search, Trash2, X } from \"@lucide/vue\";\nimport { computed, defineAsyncComponent, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n (e: \"insert\", module: SavedModule, insertIndex: number | undefined): void;\n}>();\n\nconst ModulePreviewCanvas = defineAsyncComponent(\n () => import(\"./ModulePreviewCanvas.vue\"),\n);\n\nconst { t } = useI18n();\nconst { t: cloudT } = useCloudI18nStrict();\nconst savedModules = requireInject(\n SAVED_MODULES_HEADLESS_KEY,\n \"ModuleBrowserModal\",\n);\nconst editor = requireInject(EDITOR_KEY, \"ModuleBrowserModal\");\n\nconst searchQuery = ref(\"\");\nconst selectedModuleId = ref<string | null>(null);\nconst confirmDeleteId = ref<string | null>(null);\n// 'end' = append, 'beginning' = index 0, or block id = after that block\nconst insertPosition = ref<string>(\"end\");\n\nconst filteredModules = computed(() => {\n const modules = savedModules.modules.value;\n if (!searchQuery.value) return modules;\n const query = searchQuery.value.toLowerCase();\n return modules.filter((m) => m.name.toLowerCase().includes(query));\n});\n\nconst selectedModule = computed(() => {\n if (!selectedModuleId.value) return null;\n return (\n savedModules.modules.value.find((m) => m.id === selectedModuleId.value) ??\n null\n );\n});\n\ninterface PositionOption {\n value: string;\n label: string;\n}\n\nconst positionOptions = computed<PositionOption[]>(() => {\n const options: PositionOption[] = [\n { value: \"beginning\", label: cloudT.modules.insertAtBeginning },\n ];\n const blocks = editor.content.value.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const typeKey = block.type as keyof typeof t.blocks;\n const label = t.blocks[typeKey] ?? block.type;\n options.push({\n value: block.id,\n label: cloudT.modules.insertAfterBlock.replace(\n \"{block}\",\n `${label} ${i + 1}`,\n ),\n });\n }\n options.push({ value: \"end\", label: cloudT.modules.insertAtEnd });\n return options;\n});\n\nconst resolvedInsertIndex = computed<number | undefined>(() => {\n if (insertPosition.value === \"end\") return undefined;\n if (insertPosition.value === \"beginning\") return 0;\n const blocks = editor.content.value.blocks;\n const idx = blocks.findIndex((b) => b.id === insertPosition.value);\n if (idx !== -1) return idx + 1;\n return undefined;\n});\n\nwatch(\n () => props.visible,\n (visible) => {\n if (visible) {\n searchQuery.value = \"\";\n selectedModuleId.value = null;\n confirmDeleteId.value = null;\n // Default to after selected block, or end\n const selectedId = editor.state.selectedBlockId;\n if (selectedId) {\n const idx = editor.content.value.blocks.findIndex(\n (b) => b.id === selectedId,\n );\n insertPosition.value = idx !== -1 ? selectedId : \"end\";\n } else {\n insertPosition.value = \"end\";\n }\n }\n },\n);\n\nfunction getModuleBlockTypeIcons(\n module: SavedModule,\n): { type: string; icon: unknown }[] {\n const icons: { type: string; icon: unknown }[] = [];\n const seen = new Set<string>();\n for (const block of module.content) {\n if (!seen.has(block.type) && blockTypeIcons[block.type]) {\n seen.add(block.type);\n icons.push({ type: block.type, icon: blockTypeIcons[block.type] });\n }\n if (icons.length >= 5) break;\n }\n return icons;\n}\n\nfunction getRemainingTypeCount(module: SavedModule): number {\n const types = new Set(module.content.map((b) => b.type));\n return Math.max(0, types.size - 5);\n}\n\nasync function handleDelete(moduleId: string): Promise<void> {\n try {\n await savedModules.deleteModule(moduleId);\n if (selectedModuleId.value === moduleId) {\n selectedModuleId.value = null;\n }\n } finally {\n confirmDeleteId.value = null;\n }\n}\n\nfunction handleInsert(): void {\n if (selectedModule.value) {\n emit(\"insert\", selectedModule.value, resolvedInsertIndex.value);\n }\n}\n\nfunction handleClose(): void {\n emit(\"close\");\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n handleClose();\n }\n if (event.key === \"Enter\" && selectedModule.value) {\n event.preventDefault();\n handleInsert();\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-labelledby=\"tpl-module-browser-title\"\n class=\"tpl-scale-in tpl:mx-4 tpl:flex tpl:w-full tpl:max-w-[1000px] tpl:flex-col tpl:rounded-[var(--tpl-radius-lg)]\"\n style=\"\n background-color: var(--tpl-bg-elevated);\n box-shadow: var(--tpl-shadow-xl);\n max-height: 90vh;\n \"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:px-5 tpl:py-4 tpl:border-[var(--tpl-border)]\"\n >\n <h3\n id=\"tpl-module-browser-title\"\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.modules.browse }}\n </h3>\n <button\n :aria-label=\"cloudT.modules.close\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-1 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n @click=\"handleClose\"\n >\n <X :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"tpl:flex tpl:min-h-0 tpl:flex-1 tpl:overflow-hidden\">\n <!-- Left panel: module grid -->\n <div\n class=\"tpl:flex tpl:w-[300px] tpl:shrink-0 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Search -->\n <div class=\"tpl:px-4 tpl:pt-4 tpl:pb-3\">\n <div class=\"tpl:relative\">\n <Search\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:pointer-events-none tpl:absolute tpl:left-3 tpl:top-1/2 tpl:-translate-y-1/2 tpl:text-[var(--tpl-text-dim)]\"\n />\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n :placeholder=\"cloudT.modules.search\"\n class=\"tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:pl-9 tpl:pr-3 tpl:text-sm tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n />\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:px-4 tpl:pb-4\">\n <div\n v-if=\"filteredModules.length > 0\"\n class=\"tpl:flex tpl:flex-col tpl:gap-1\"\n >\n <button\n v-for=\"mod in filteredModules\"\n :key=\"mod.id\"\n type=\"button\"\n :aria-pressed=\"selectedModuleId === mod.id\"\n class=\"tpl:group/card tpl:w-full tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-md)] tpl:border tpl:bg-transparent tpl:px-3 tpl:py-2 tpl:text-left tpl:transition-all tpl:duration-[120ms]\"\n :style=\"{\n borderColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary)'\n : 'var(--tpl-border)',\n backgroundColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"selectedModuleId = mod.id\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <span\n class=\"tpl:flex-1 tpl:truncate tpl:text-xs tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ mod.name }}\n </span>\n <span\n class=\"tpl:shrink-0 tpl:rounded-full tpl:px-1.5 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:bg-[var(--tpl-bg-hover)] tpl:text-[var(--tpl-text-muted)]\"\n >\n {{\n cloudT.modules.blockCount.replace(\n \"{count}\",\n String(mod.content.length),\n )\n }}\n </span>\n </div>\n <div class=\"tpl:mt-1 tpl:flex tpl:items-center tpl:gap-1\">\n <component\n :is=\"icon.icon\"\n v-for=\"icon in getModuleBlockTypeIcons(mod)\"\n :key=\"icon.type\"\n :size=\"14\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <span\n v-if=\"getRemainingTypeCount(mod) > 0\"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n +{{ getRemainingTypeCount(mod) }}\n </span>\n <button\n v-if=\"confirmDeleteId === mod.id\"\n :aria-label=\"cloudT.modules.deleteConfirm\"\n class=\"tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-2 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:transition-colors tpl:duration-100 tpl:border-[var(--tpl-danger)] tpl:text-[var(--tpl-danger)]\"\n style=\"background-color: transparent\"\n @click.stop=\"handleDelete(mod.id)\"\n >\n {{ cloudT.modules.deleteConfirm }}\n </button>\n <button\n v-else\n class=\"tpl-module-delete-btn tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-0.5 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n :aria-label=\"cloudT.modules.delete\"\n :title=\"cloudT.modules.delete\"\n @click.stop=\"confirmDeleteId = mod.id\"\n >\n <Trash2 :size=\"12\" :stroke-width=\"1.5\" />\n </button>\n </div>\n </button>\n </div>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:py-12\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p class=\"tpl:mt-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\">\n {{\n searchQuery\n ? cloudT.modules.noModules\n : cloudT.modules.noModulesHint\n }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Right panel: preview -->\n <div\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden tpl:border-l tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"selectedModule\"\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Visual preview -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <ModulePreviewCanvas :blocks=\"selectedModule.content\" />\n </div>\n </div>\n\n <!-- Empty preview state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:items-center tpl:justify-center tpl:px-4\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:mt-2 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.selectToPreview }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Footer -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-t tpl:px-5 tpl:py-3 tpl:border-[var(--tpl-border)]\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <label\n class=\"tpl:shrink-0 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.insertPosition }}\n </label>\n <select\n v-model=\"insertPosition\"\n class=\"tpl:h-7 tpl:max-w-[220px] tpl:rounded-md tpl:border tpl:px-2 tpl:text-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n >\n <option\n v-for=\"opt in positionOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </option>\n </select>\n </div>\n <div class=\"tpl:flex 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 @click=\"handleClose\"\n >\n {{ cloudT.modules.close }}\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=\"!selectedModule\"\n @click=\"handleInsert\"\n >\n {{ cloudT.modules.insert }}\n </button>\n </div>\n </div>\n </div>\n </TplModal>\n</template>\n\n<style>\n.tpl-module-delete-btn:hover {\n color: var(--tpl-danger) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport TplModal from \"./TplModal.vue\";\nimport { useI18n } from \"../../composables\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { blockTypeIcons } from \"../../utils/blockTypeIcons\";\nimport {\n SAVED_MODULES_HEADLESS_KEY,\n EDITOR_KEY,\n requireInject,\n} from \"../../keys\";\nimport type { SavedModule } from \"@templatical/types\";\nimport { Package, Search, Trash2, X } from \"@lucide/vue\";\nimport { computed, defineAsyncComponent, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n (e: \"insert\", module: SavedModule, insertIndex: number | undefined): void;\n}>();\n\nconst ModulePreviewCanvas = defineAsyncComponent(\n () => import(\"./ModulePreviewCanvas.vue\"),\n);\n\nconst { t } = useI18n();\nconst { t: cloudT } = useCloudI18nStrict();\nconst savedModules = requireInject(\n SAVED_MODULES_HEADLESS_KEY,\n \"ModuleBrowserModal\",\n);\nconst editor = requireInject(EDITOR_KEY, \"ModuleBrowserModal\");\n\nconst searchQuery = ref(\"\");\nconst selectedModuleId = ref<string | null>(null);\nconst confirmDeleteId = ref<string | null>(null);\n// 'end' = append, 'beginning' = index 0, or block id = after that block\nconst insertPosition = ref<string>(\"end\");\n\nconst filteredModules = computed(() => {\n const modules = savedModules.modules.value;\n if (!searchQuery.value) return modules;\n const query = searchQuery.value.toLowerCase();\n return modules.filter((m) => m.name.toLowerCase().includes(query));\n});\n\nconst selectedModule = computed(() => {\n if (!selectedModuleId.value) return null;\n return (\n savedModules.modules.value.find((m) => m.id === selectedModuleId.value) ??\n null\n );\n});\n\ninterface PositionOption {\n value: string;\n label: string;\n}\n\nconst positionOptions = computed<PositionOption[]>(() => {\n const options: PositionOption[] = [\n { value: \"beginning\", label: cloudT.modules.insertAtBeginning },\n ];\n const blocks = editor.content.value.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const typeKey = block.type as keyof typeof t.blocks;\n const label = t.blocks[typeKey] ?? block.type;\n options.push({\n value: block.id,\n label: cloudT.modules.insertAfterBlock.replace(\n \"{block}\",\n `${label} ${i + 1}`,\n ),\n });\n }\n options.push({ value: \"end\", label: cloudT.modules.insertAtEnd });\n return options;\n});\n\nconst resolvedInsertIndex = computed<number | undefined>(() => {\n if (insertPosition.value === \"end\") return undefined;\n if (insertPosition.value === \"beginning\") return 0;\n const blocks = editor.content.value.blocks;\n const idx = blocks.findIndex((b) => b.id === insertPosition.value);\n if (idx !== -1) return idx + 1;\n return undefined;\n});\n\nwatch(\n () => props.visible,\n (visible) => {\n if (visible) {\n searchQuery.value = \"\";\n selectedModuleId.value = null;\n confirmDeleteId.value = null;\n // Default to after selected block, or end\n const selectedId = editor.state.selectedBlockId;\n if (selectedId) {\n const idx = editor.content.value.blocks.findIndex(\n (b) => b.id === selectedId,\n );\n insertPosition.value = idx !== -1 ? selectedId : \"end\";\n } else {\n insertPosition.value = \"end\";\n }\n }\n },\n);\n\nfunction getModuleBlockTypeIcons(\n module: SavedModule,\n): { type: string; icon: unknown }[] {\n const icons: { type: string; icon: unknown }[] = [];\n const seen = new Set<string>();\n for (const block of module.content) {\n if (!seen.has(block.type) && blockTypeIcons[block.type]) {\n seen.add(block.type);\n icons.push({ type: block.type, icon: blockTypeIcons[block.type] });\n }\n if (icons.length >= 5) break;\n }\n return icons;\n}\n\nfunction getRemainingTypeCount(module: SavedModule): number {\n const types = new Set(module.content.map((b) => b.type));\n return Math.max(0, types.size - 5);\n}\n\nasync function handleDelete(moduleId: string): Promise<void> {\n try {\n await savedModules.deleteModule(moduleId);\n if (selectedModuleId.value === moduleId) {\n selectedModuleId.value = null;\n }\n } finally {\n confirmDeleteId.value = null;\n }\n}\n\nfunction handleInsert(): void {\n if (selectedModule.value) {\n emit(\"insert\", selectedModule.value, resolvedInsertIndex.value);\n }\n}\n\nfunction handleClose(): void {\n emit(\"close\");\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n handleClose();\n }\n if (event.key === \"Enter\" && selectedModule.value) {\n event.preventDefault();\n handleInsert();\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-labelledby=\"tpl-module-browser-title\"\n class=\"tpl-scale-in tpl:mx-4 tpl:flex tpl:w-full tpl:max-w-[1000px] tpl:flex-col tpl:rounded-[var(--tpl-radius-lg)]\"\n style=\"\n background-color: var(--tpl-bg-elevated);\n box-shadow: var(--tpl-shadow-xl);\n max-height: 90vh;\n \"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:px-5 tpl:py-4 tpl:border-[var(--tpl-border)]\"\n >\n <h3\n id=\"tpl-module-browser-title\"\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.modules.browse }}\n </h3>\n <button\n :aria-label=\"cloudT.modules.close\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-1 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n @click=\"handleClose\"\n >\n <X :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"tpl:flex tpl:min-h-0 tpl:flex-1 tpl:overflow-hidden\">\n <!-- Left panel: module grid -->\n <div\n class=\"tpl:flex tpl:w-[300px] tpl:shrink-0 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Search -->\n <div class=\"tpl:px-4 tpl:pt-4 tpl:pb-3\">\n <div class=\"tpl:relative\">\n <Search\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:pointer-events-none tpl:absolute tpl:left-3 tpl:top-1/2 tpl:-translate-y-1/2 tpl:text-[var(--tpl-text-dim)]\"\n />\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n :placeholder=\"cloudT.modules.search\"\n class=\"tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:pl-9 tpl:pr-3 tpl:text-sm tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n />\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:px-4 tpl:pb-4\">\n <div\n v-if=\"filteredModules.length > 0\"\n class=\"tpl:flex tpl:flex-col tpl:gap-1\"\n >\n <button\n v-for=\"mod in filteredModules\"\n :key=\"mod.id\"\n type=\"button\"\n :aria-pressed=\"selectedModuleId === mod.id\"\n class=\"tpl:group/card tpl:w-full tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-md)] tpl:border tpl:bg-transparent tpl:px-3 tpl:py-2 tpl:text-left tpl:transition-all tpl:duration-[120ms]\"\n :style=\"{\n borderColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary)'\n : 'var(--tpl-border)',\n backgroundColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"selectedModuleId = mod.id\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <span\n class=\"tpl:flex-1 tpl:truncate tpl:text-xs tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ mod.name }}\n </span>\n <span\n class=\"tpl:shrink-0 tpl:rounded-full tpl:px-1.5 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:bg-[var(--tpl-bg-hover)] tpl:text-[var(--tpl-text-muted)]\"\n >\n {{\n cloudT.modules.blockCount.replace(\n \"{count}\",\n String(mod.content.length),\n )\n }}\n </span>\n </div>\n <div class=\"tpl:mt-1 tpl:flex tpl:items-center tpl:gap-1\">\n <component\n :is=\"icon.icon\"\n v-for=\"icon in getModuleBlockTypeIcons(mod)\"\n :key=\"icon.type\"\n :size=\"14\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <span\n v-if=\"getRemainingTypeCount(mod) > 0\"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n +{{ getRemainingTypeCount(mod) }}\n </span>\n <button\n v-if=\"confirmDeleteId === mod.id\"\n :aria-label=\"cloudT.modules.deleteConfirm\"\n class=\"tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-2 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:transition-colors tpl:duration-100 tpl:border-[var(--tpl-danger)] tpl:text-[var(--tpl-danger)]\"\n style=\"background-color: transparent\"\n @click.stop=\"handleDelete(mod.id)\"\n >\n {{ cloudT.modules.deleteConfirm }}\n </button>\n <button\n v-else\n class=\"tpl-module-delete-btn tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-0.5 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n :aria-label=\"cloudT.modules.delete\"\n :title=\"cloudT.modules.delete\"\n @click.stop=\"confirmDeleteId = mod.id\"\n >\n <Trash2 :size=\"12\" :stroke-width=\"1.5\" />\n </button>\n </div>\n </button>\n </div>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:py-12\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p class=\"tpl:mt-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\">\n {{\n searchQuery\n ? cloudT.modules.noModules\n : cloudT.modules.noModulesHint\n }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Right panel: preview -->\n <div\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden tpl:border-l tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"selectedModule\"\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Visual preview -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <ModulePreviewCanvas :blocks=\"selectedModule.content\" />\n </div>\n </div>\n\n <!-- Empty preview state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:items-center tpl:justify-center tpl:px-4\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:mt-2 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.selectToPreview }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Footer -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-t tpl:px-5 tpl:py-3 tpl:border-[var(--tpl-border)]\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <label\n class=\"tpl:shrink-0 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.insertPosition }}\n </label>\n <select\n v-model=\"insertPosition\"\n class=\"tpl:h-7 tpl:max-w-[220px] tpl:rounded-md tpl:border tpl:px-2 tpl:text-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n >\n <option\n v-for=\"opt in positionOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </option>\n </select>\n </div>\n <div class=\"tpl:flex 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 @click=\"handleClose\"\n >\n {{ cloudT.modules.close }}\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=\"!selectedModule\"\n @click=\"handleInsert\"\n >\n {{ cloudT.modules.insert }}\n </button>\n </div>\n </div>\n </div>\n </TplModal>\n</template>\n\n<style>\n.tpl-module-delete-btn:hover {\n color: var(--tpl-danger) !important;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ModuleBrowserModal-BMUyAmmj.js","names":[],"sources":["../../../src/cloud/components/ModuleBrowserModal.vue","../../../src/cloud/components/ModuleBrowserModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport TplModal from \"./TplModal.vue\";\nimport { useI18n } from \"../../composables\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { blockTypeIcons } from \"../../utils/blockTypeIcons\";\nimport {\n SAVED_MODULES_HEADLESS_KEY,\n EDITOR_KEY,\n requireInject,\n} from \"../../keys\";\nimport type { SavedModule } from \"@templatical/types\";\nimport { Package, Search, Trash2, X } from \"@lucide/vue\";\nimport { computed, defineAsyncComponent, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n (e: \"insert\", module: SavedModule, insertIndex: number | undefined): void;\n}>();\n\nconst ModulePreviewCanvas = defineAsyncComponent(\n () => import(\"./ModulePreviewCanvas.vue\"),\n);\n\nconst { t } = useI18n();\nconst { t: cloudT } = useCloudI18nStrict();\nconst savedModules = requireInject(\n SAVED_MODULES_HEADLESS_KEY,\n \"ModuleBrowserModal\",\n);\nconst editor = requireInject(EDITOR_KEY, \"ModuleBrowserModal\");\n\nconst searchQuery = ref(\"\");\nconst selectedModuleId = ref<string | null>(null);\nconst confirmDeleteId = ref<string | null>(null);\n// 'end' = append, 'beginning' = index 0, or block id = after that block\nconst insertPosition = ref<string>(\"end\");\n\nconst filteredModules = computed(() => {\n const modules = savedModules.modules.value;\n if (!searchQuery.value) return modules;\n const query = searchQuery.value.toLowerCase();\n return modules.filter((m) => m.name.toLowerCase().includes(query));\n});\n\nconst selectedModule = computed(() => {\n if (!selectedModuleId.value) return null;\n return (\n savedModules.modules.value.find((m) => m.id === selectedModuleId.value) ??\n null\n );\n});\n\ninterface PositionOption {\n value: string;\n label: string;\n}\n\nconst positionOptions = computed<PositionOption[]>(() => {\n const options: PositionOption[] = [\n { value: \"beginning\", label: cloudT.modules.insertAtBeginning },\n ];\n const blocks = editor.content.value.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const typeKey = block.type as keyof typeof t.blocks;\n const label = t.blocks[typeKey] ?? block.type;\n options.push({\n value: block.id,\n label: cloudT.modules.insertAfterBlock.replace(\n \"{block}\",\n `${label} ${i + 1}`,\n ),\n });\n }\n options.push({ value: \"end\", label: cloudT.modules.insertAtEnd });\n return options;\n});\n\nconst resolvedInsertIndex = computed<number | undefined>(() => {\n if (insertPosition.value === \"end\") return undefined;\n if (insertPosition.value === \"beginning\") return 0;\n const blocks = editor.content.value.blocks;\n const idx = blocks.findIndex((b) => b.id === insertPosition.value);\n if (idx !== -1) return idx + 1;\n return undefined;\n});\n\nwatch(\n () => props.visible,\n (visible) => {\n if (visible) {\n searchQuery.value = \"\";\n selectedModuleId.value = null;\n confirmDeleteId.value = null;\n // Default to after selected block, or end\n const selectedId = editor.state.selectedBlockId;\n if (selectedId) {\n const idx = editor.content.value.blocks.findIndex(\n (b) => b.id === selectedId,\n );\n insertPosition.value = idx !== -1 ? selectedId : \"end\";\n } else {\n insertPosition.value = \"end\";\n }\n }\n },\n);\n\nfunction getModuleBlockTypeIcons(\n module: SavedModule,\n): { type: string; icon: unknown }[] {\n const icons: { type: string; icon: unknown }[] = [];\n const seen = new Set<string>();\n for (const block of module.content) {\n if (!seen.has(block.type) && blockTypeIcons[block.type]) {\n seen.add(block.type);\n icons.push({ type: block.type, icon: blockTypeIcons[block.type] });\n }\n if (icons.length >= 5) break;\n }\n return icons;\n}\n\nfunction getRemainingTypeCount(module: SavedModule): number {\n const types = new Set(module.content.map((b) => b.type));\n return Math.max(0, types.size - 5);\n}\n\nasync function handleDelete(moduleId: string): Promise<void> {\n try {\n await savedModules.deleteModule(moduleId);\n if (selectedModuleId.value === moduleId) {\n selectedModuleId.value = null;\n }\n } finally {\n confirmDeleteId.value = null;\n }\n}\n\nfunction handleInsert(): void {\n if (selectedModule.value) {\n emit(\"insert\", selectedModule.value, resolvedInsertIndex.value);\n }\n}\n\nfunction handleClose(): void {\n emit(\"close\");\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n handleClose();\n }\n if (event.key === \"Enter\" && selectedModule.value) {\n event.preventDefault();\n handleInsert();\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-labelledby=\"tpl-module-browser-title\"\n class=\"tpl-scale-in tpl:mx-4 tpl:flex tpl:w-full tpl:max-w-[1000px] tpl:flex-col tpl:rounded-[var(--tpl-radius-lg)]\"\n style=\"\n background-color: var(--tpl-bg-elevated);\n box-shadow: var(--tpl-shadow-xl);\n max-height: 90vh;\n \"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:px-5 tpl:py-4 tpl:border-[var(--tpl-border)]\"\n >\n <h3\n id=\"tpl-module-browser-title\"\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.modules.browse }}\n </h3>\n <button\n :aria-label=\"cloudT.modules.close\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-1 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n @click=\"handleClose\"\n >\n <X :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"tpl:flex tpl:min-h-0 tpl:flex-1 tpl:overflow-hidden\">\n <!-- Left panel: module grid -->\n <div\n class=\"tpl:flex tpl:w-[300px] tpl:shrink-0 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Search -->\n <div class=\"tpl:px-4 tpl:pt-4 tpl:pb-3\">\n <div class=\"tpl:relative\">\n <Search\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:pointer-events-none tpl:absolute tpl:left-3 tpl:top-1/2 tpl:-translate-y-1/2 tpl:text-[var(--tpl-text-dim)]\"\n />\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n :placeholder=\"cloudT.modules.search\"\n class=\"tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:pl-9 tpl:pr-3 tpl:text-sm tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n />\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:px-4 tpl:pb-4\">\n <div\n v-if=\"filteredModules.length > 0\"\n class=\"tpl:flex tpl:flex-col tpl:gap-1\"\n >\n <button\n v-for=\"mod in filteredModules\"\n :key=\"mod.id\"\n type=\"button\"\n :aria-pressed=\"selectedModuleId === mod.id\"\n class=\"tpl:group/card tpl:w-full tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-md)] tpl:border tpl:bg-transparent tpl:px-3 tpl:py-2 tpl:text-left tpl:transition-all tpl:duration-[120ms]\"\n :style=\"{\n borderColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary)'\n : 'var(--tpl-border)',\n backgroundColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"selectedModuleId = mod.id\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <span\n class=\"tpl:flex-1 tpl:truncate tpl:text-xs tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ mod.name }}\n </span>\n <span\n class=\"tpl:shrink-0 tpl:rounded-full tpl:px-1.5 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:bg-[var(--tpl-bg-hover)] tpl:text-[var(--tpl-text-muted)]\"\n >\n {{\n cloudT.modules.blockCount.replace(\n \"{count}\",\n String(mod.content.length),\n )\n }}\n </span>\n </div>\n <div class=\"tpl:mt-1 tpl:flex tpl:items-center tpl:gap-1\">\n <component\n :is=\"icon.icon\"\n v-for=\"icon in getModuleBlockTypeIcons(mod)\"\n :key=\"icon.type\"\n :size=\"14\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <span\n v-if=\"getRemainingTypeCount(mod) > 0\"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n +{{ getRemainingTypeCount(mod) }}\n </span>\n <button\n v-if=\"confirmDeleteId === mod.id\"\n :aria-label=\"cloudT.modules.deleteConfirm\"\n class=\"tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-2 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:transition-colors tpl:duration-100 tpl:border-[var(--tpl-danger)] tpl:text-[var(--tpl-danger)]\"\n style=\"background-color: transparent\"\n @click.stop=\"handleDelete(mod.id)\"\n >\n {{ cloudT.modules.deleteConfirm }}\n </button>\n <button\n v-else\n class=\"tpl-module-delete-btn tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-0.5 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n :aria-label=\"cloudT.modules.delete\"\n :title=\"cloudT.modules.delete\"\n @click.stop=\"confirmDeleteId = mod.id\"\n >\n <Trash2 :size=\"12\" :stroke-width=\"1.5\" />\n </button>\n </div>\n </button>\n </div>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:py-12\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p class=\"tpl:mt-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\">\n {{\n searchQuery\n ? cloudT.modules.noModules\n : cloudT.modules.noModulesHint\n }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Right panel: preview -->\n <div\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden tpl:border-l tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"selectedModule\"\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Visual preview -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <ModulePreviewCanvas :blocks=\"selectedModule.content\" />\n </div>\n </div>\n\n <!-- Empty preview state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:items-center tpl:justify-center tpl:px-4\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:mt-2 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.selectToPreview }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Footer -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-t tpl:px-5 tpl:py-3 tpl:border-[var(--tpl-border)]\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <label\n class=\"tpl:shrink-0 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.insertPosition }}\n </label>\n <select\n v-model=\"insertPosition\"\n class=\"tpl:h-7 tpl:max-w-[220px] tpl:rounded-md tpl:border tpl:px-2 tpl:text-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n >\n <option\n v-for=\"opt in positionOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </option>\n </select>\n </div>\n <div class=\"tpl:flex 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 @click=\"handleClose\"\n >\n {{ cloudT.modules.close }}\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=\"!selectedModule\"\n @click=\"handleInsert\"\n >\n {{ cloudT.modules.insert }}\n </button>\n </div>\n </div>\n </div>\n </TplModal>\n</template>\n\n<style>\n.tpl-module-delete-btn:hover {\n color: var(--tpl-danger) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport TplModal from \"./TplModal.vue\";\nimport { useI18n } from \"../../composables\";\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { blockTypeIcons } from \"../../utils/blockTypeIcons\";\nimport {\n SAVED_MODULES_HEADLESS_KEY,\n EDITOR_KEY,\n requireInject,\n} from \"../../keys\";\nimport type { SavedModule } from \"@templatical/types\";\nimport { Package, Search, Trash2, X } from \"@lucide/vue\";\nimport { computed, defineAsyncComponent, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n (e: \"insert\", module: SavedModule, insertIndex: number | undefined): void;\n}>();\n\nconst ModulePreviewCanvas = defineAsyncComponent(\n () => import(\"./ModulePreviewCanvas.vue\"),\n);\n\nconst { t } = useI18n();\nconst { t: cloudT } = useCloudI18nStrict();\nconst savedModules = requireInject(\n SAVED_MODULES_HEADLESS_KEY,\n \"ModuleBrowserModal\",\n);\nconst editor = requireInject(EDITOR_KEY, \"ModuleBrowserModal\");\n\nconst searchQuery = ref(\"\");\nconst selectedModuleId = ref<string | null>(null);\nconst confirmDeleteId = ref<string | null>(null);\n// 'end' = append, 'beginning' = index 0, or block id = after that block\nconst insertPosition = ref<string>(\"end\");\n\nconst filteredModules = computed(() => {\n const modules = savedModules.modules.value;\n if (!searchQuery.value) return modules;\n const query = searchQuery.value.toLowerCase();\n return modules.filter((m) => m.name.toLowerCase().includes(query));\n});\n\nconst selectedModule = computed(() => {\n if (!selectedModuleId.value) return null;\n return (\n savedModules.modules.value.find((m) => m.id === selectedModuleId.value) ??\n null\n );\n});\n\ninterface PositionOption {\n value: string;\n label: string;\n}\n\nconst positionOptions = computed<PositionOption[]>(() => {\n const options: PositionOption[] = [\n { value: \"beginning\", label: cloudT.modules.insertAtBeginning },\n ];\n const blocks = editor.content.value.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const typeKey = block.type as keyof typeof t.blocks;\n const label = t.blocks[typeKey] ?? block.type;\n options.push({\n value: block.id,\n label: cloudT.modules.insertAfterBlock.replace(\n \"{block}\",\n `${label} ${i + 1}`,\n ),\n });\n }\n options.push({ value: \"end\", label: cloudT.modules.insertAtEnd });\n return options;\n});\n\nconst resolvedInsertIndex = computed<number | undefined>(() => {\n if (insertPosition.value === \"end\") return undefined;\n if (insertPosition.value === \"beginning\") return 0;\n const blocks = editor.content.value.blocks;\n const idx = blocks.findIndex((b) => b.id === insertPosition.value);\n if (idx !== -1) return idx + 1;\n return undefined;\n});\n\nwatch(\n () => props.visible,\n (visible) => {\n if (visible) {\n searchQuery.value = \"\";\n selectedModuleId.value = null;\n confirmDeleteId.value = null;\n // Default to after selected block, or end\n const selectedId = editor.state.selectedBlockId;\n if (selectedId) {\n const idx = editor.content.value.blocks.findIndex(\n (b) => b.id === selectedId,\n );\n insertPosition.value = idx !== -1 ? selectedId : \"end\";\n } else {\n insertPosition.value = \"end\";\n }\n }\n },\n);\n\nfunction getModuleBlockTypeIcons(\n module: SavedModule,\n): { type: string; icon: unknown }[] {\n const icons: { type: string; icon: unknown }[] = [];\n const seen = new Set<string>();\n for (const block of module.content) {\n if (!seen.has(block.type) && blockTypeIcons[block.type]) {\n seen.add(block.type);\n icons.push({ type: block.type, icon: blockTypeIcons[block.type] });\n }\n if (icons.length >= 5) break;\n }\n return icons;\n}\n\nfunction getRemainingTypeCount(module: SavedModule): number {\n const types = new Set(module.content.map((b) => b.type));\n return Math.max(0, types.size - 5);\n}\n\nasync function handleDelete(moduleId: string): Promise<void> {\n try {\n await savedModules.deleteModule(moduleId);\n if (selectedModuleId.value === moduleId) {\n selectedModuleId.value = null;\n }\n } finally {\n confirmDeleteId.value = null;\n }\n}\n\nfunction handleInsert(): void {\n if (selectedModule.value) {\n emit(\"insert\", selectedModule.value, resolvedInsertIndex.value);\n }\n}\n\nfunction handleClose(): void {\n emit(\"close\");\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n handleClose();\n }\n if (event.key === \"Enter\" && selectedModule.value) {\n event.preventDefault();\n handleInsert();\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-labelledby=\"tpl-module-browser-title\"\n class=\"tpl-scale-in tpl:mx-4 tpl:flex tpl:w-full tpl:max-w-[1000px] tpl:flex-col tpl:rounded-[var(--tpl-radius-lg)]\"\n style=\"\n background-color: var(--tpl-bg-elevated);\n box-shadow: var(--tpl-shadow-xl);\n max-height: 90vh;\n \"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:px-5 tpl:py-4 tpl:border-[var(--tpl-border)]\"\n >\n <h3\n id=\"tpl-module-browser-title\"\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.modules.browse }}\n </h3>\n <button\n :aria-label=\"cloudT.modules.close\"\n class=\"tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-1 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n @click=\"handleClose\"\n >\n <X :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"tpl:flex tpl:min-h-0 tpl:flex-1 tpl:overflow-hidden\">\n <!-- Left panel: module grid -->\n <div\n class=\"tpl:flex tpl:w-[300px] tpl:shrink-0 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Search -->\n <div class=\"tpl:px-4 tpl:pt-4 tpl:pb-3\">\n <div class=\"tpl:relative\">\n <Search\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:pointer-events-none tpl:absolute tpl:left-3 tpl:top-1/2 tpl:-translate-y-1/2 tpl:text-[var(--tpl-text-dim)]\"\n />\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n :placeholder=\"cloudT.modules.search\"\n class=\"tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:pl-9 tpl:pr-3 tpl:text-sm tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n />\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:px-4 tpl:pb-4\">\n <div\n v-if=\"filteredModules.length > 0\"\n class=\"tpl:flex tpl:flex-col tpl:gap-1\"\n >\n <button\n v-for=\"mod in filteredModules\"\n :key=\"mod.id\"\n type=\"button\"\n :aria-pressed=\"selectedModuleId === mod.id\"\n class=\"tpl:group/card tpl:w-full tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-md)] tpl:border tpl:bg-transparent tpl:px-3 tpl:py-2 tpl:text-left tpl:transition-all tpl:duration-[120ms]\"\n :style=\"{\n borderColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary)'\n : 'var(--tpl-border)',\n backgroundColor:\n selectedModuleId === mod.id\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"selectedModuleId = mod.id\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <span\n class=\"tpl:flex-1 tpl:truncate tpl:text-xs tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n {{ mod.name }}\n </span>\n <span\n class=\"tpl:shrink-0 tpl:rounded-full tpl:px-1.5 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:bg-[var(--tpl-bg-hover)] tpl:text-[var(--tpl-text-muted)]\"\n >\n {{\n cloudT.modules.blockCount.replace(\n \"{count}\",\n String(mod.content.length),\n )\n }}\n </span>\n </div>\n <div class=\"tpl:mt-1 tpl:flex tpl:items-center tpl:gap-1\">\n <component\n :is=\"icon.icon\"\n v-for=\"icon in getModuleBlockTypeIcons(mod)\"\n :key=\"icon.type\"\n :size=\"14\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <span\n v-if=\"getRemainingTypeCount(mod) > 0\"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n +{{ getRemainingTypeCount(mod) }}\n </span>\n <button\n v-if=\"confirmDeleteId === mod.id\"\n :aria-label=\"cloudT.modules.deleteConfirm\"\n class=\"tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-2 tpl:py-0.5 tpl:text-[10px] tpl:font-medium tpl:transition-colors tpl:duration-100 tpl:border-[var(--tpl-danger)] tpl:text-[var(--tpl-danger)]\"\n style=\"background-color: transparent\"\n @click.stop=\"handleDelete(mod.id)\"\n >\n {{ cloudT.modules.deleteConfirm }}\n </button>\n <button\n v-else\n class=\"tpl-module-delete-btn tpl:ml-auto tpl:cursor-pointer tpl:rounded-md tpl:border-none tpl:bg-transparent tpl:p-0.5 tpl:transition-colors tpl:duration-100 tpl:text-[var(--tpl-text-dim)]\"\n :aria-label=\"cloudT.modules.delete\"\n :title=\"cloudT.modules.delete\"\n @click.stop=\"confirmDeleteId = mod.id\"\n >\n <Trash2 :size=\"12\" :stroke-width=\"1.5\" />\n </button>\n </div>\n </button>\n </div>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:py-12\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p class=\"tpl:mt-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\">\n {{\n searchQuery\n ? cloudT.modules.noModules\n : cloudT.modules.noModulesHint\n }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Right panel: preview -->\n <div\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden tpl:border-l tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"selectedModule\"\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:overflow-hidden\"\n >\n <!-- Visual preview -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <ModulePreviewCanvas :blocks=\"selectedModule.content\" />\n </div>\n </div>\n\n <!-- Empty preview state -->\n <div\n v-else\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:items-center tpl:justify-center tpl:px-4\"\n >\n <Package\n :size=\"32\"\n :stroke-width=\"1\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:mt-2 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.selectToPreview }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Footer -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-t tpl:px-5 tpl:py-3 tpl:border-[var(--tpl-border)]\"\n >\n <div class=\"tpl:flex tpl:items-center tpl:gap-2\">\n <label\n class=\"tpl:shrink-0 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.modules.insertPosition }}\n </label>\n <select\n v-model=\"insertPosition\"\n class=\"tpl:h-7 tpl:max-w-[220px] tpl:rounded-md tpl:border tpl:px-2 tpl:text-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]\"\n >\n <option\n v-for=\"opt in positionOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </option>\n </select>\n </div>\n <div class=\"tpl:flex 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 @click=\"handleClose\"\n >\n {{ cloudT.modules.close }}\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=\"!selectedModule\"\n @click=\"handleInsert\"\n >\n {{ cloudT.modules.insert }}\n </button>\n </div>\n </div>\n </div>\n </TplModal>\n</template>\n\n<style>\n.tpl-module-delete-btn:hover {\n color: var(--tpl-danger) !important;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { I as e, L as t, M as n, P as r, T as i, f as a, g as o, m as s, ot as c, p as l, rt as u, u as d, x as f } from "./draggable-CNhyCGIO.js";
|
|
2
|
-
import { A as p, At as m, B as h, G as g, H as _, K as v, L as y, M as b, N as x, U as S, V as C, W as w, j as T, z as E, zt as D } from "./features-
|
|
2
|
+
import { A as p, At as m, B as h, G as g, H as _, K as v, L as y, M as b, N as x, U as S, V as C, W as w, j as T, z as E, zt as D } from "./features-D6FoOm8v.js";
|
|
3
3
|
//#region src/components/blocks/PreviewSectionBlock.vue?vue&type=script&setup=true&lang.ts
|
|
4
4
|
var O = { class: "tpl:w-full" }, k = { class: "tpl:flex tpl:gap-0" }, A = /* @__PURE__ */ f({
|
|
5
5
|
name: "PreviewSectionBlock",
|
|
@@ -104,4 +104,4 @@ var O = { class: "tpl:w-full" }, k = { class: "tpl:flex tpl:gap-0" }, A = /* @__
|
|
|
104
104
|
//#endregion
|
|
105
105
|
export { M as default };
|
|
106
106
|
|
|
107
|
-
//# sourceMappingURL=ModulePreviewCanvas-
|
|
107
|
+
//# sourceMappingURL=ModulePreviewCanvas-CxSc7Pvd.js.map
|
package/dist/cdn/chunks/{ModulePreviewCanvas-CYtt0boo.js.map → ModulePreviewCanvas-CxSc7Pvd.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModulePreviewCanvas-CYtt0boo.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
|
+
{"version":3,"file":"ModulePreviewCanvas-CxSc7Pvd.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,5 +1,5 @@
|
|
|
1
1
|
import { F as e, L as t, M as n, P as r, V as i, Z as a, at as o, c as s, f as c, g as l, h as u, m as d, n as f, ot as p, p as m, rt as h, st as g, u as _, x as v, y as ee } from "./draggable-CNhyCGIO.js";
|
|
2
|
-
import { Nt as te, tn as ne } from "./features-
|
|
2
|
+
import { Nt as te, tn as ne } from "./features-D6FoOm8v.js";
|
|
3
3
|
import { h as y, i as b, m as x, p as S, u as re } from "./styleConstants-DP1VOca8.js";
|
|
4
4
|
//#region ../../node_modules/.pnpm/vanilla-colorful@0.7.2/node_modules/vanilla-colorful/lib/utils/math.js
|
|
5
5
|
var C = (e, t = 0, n = 1) => e > n ? n : e < t ? t : e, w = (e, t = 0, n = 10 ** t) => Math.round(n * e) / n;
|
|
@@ -420,4 +420,4 @@ var ue = [
|
|
|
420
420
|
//#endregion
|
|
421
421
|
export { pe as i, ve as n, ge as r, xe as t };
|
|
422
422
|
|
|
423
|
-
//# sourceMappingURL=NumberWithSuffix-
|
|
423
|
+
//# sourceMappingURL=NumberWithSuffix-BSOUOUCL.js.map
|