@oneclick.dev/cms-core-modules 0.0.123 → 0.0.125

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.
Files changed (223) hide show
  1. package/dist/AppointmentListTable-CWzbwqR-.js +1 -0
  2. package/dist/AppointmentListTable-DoZuBstk.mjs +270 -0
  3. package/dist/ContentEditor-BlNbqkAz.js +324 -0
  4. package/dist/{ContentEditor-MDGolnIP.mjs → ContentEditor-D754iLJS.mjs} +7985 -26820
  5. package/dist/{Detail-Dk8E6_uF.mjs → Detail-BOxWQ1QQ.mjs} +15 -14
  6. package/dist/{Detail-Cn9Bk0u0.mjs → Detail-BfKW0uZE.mjs} +26 -25
  7. package/dist/Detail-DFVu2F38.mjs +11 -0
  8. package/dist/Detail-DJea_fCd.js +1 -0
  9. package/dist/Detail-DPJacXfm.js +1 -0
  10. package/dist/Detail-DSLZ7_bM.js +1 -0
  11. package/dist/Detail-DUGThL9Y.js +1 -0
  12. package/dist/{Detail-B_scnidb.mjs → Detail-D_LlEeHu.mjs} +35 -34
  13. package/dist/Editor-D4evcdhv.mjs +768 -0
  14. package/dist/Editor-gLLtuJbY.js +1 -0
  15. package/dist/FormStatusBadge.vue_vue_type_script_setup_true_lang-BjKpsqT9.js +1 -0
  16. package/dist/FormStatusBadge.vue_vue_type_script_setup_true_lang-D5v5AhLe.mjs +76 -0
  17. package/dist/Knowledge-B66vxz--.js +1 -0
  18. package/dist/Knowledge-BnMTTuJ7.mjs +742 -0
  19. package/dist/Overview-0hFXiuYo.js +1 -0
  20. package/dist/Overview-BE4uYPx0.mjs +745 -0
  21. package/dist/Overview-BTx5LF4J.js +1 -0
  22. package/dist/Overview-CCu2PHai.mjs +289 -0
  23. package/dist/Overview-CQRpFhbJ.mjs +286 -0
  24. package/dist/Overview-CTs7sX4d.js +1 -0
  25. package/dist/Overview-Cj89XXKN.js +1 -0
  26. package/dist/Overview-D2u-leeO.js +1 -0
  27. package/dist/Overview-D_2wozCG.mjs +1733 -0
  28. package/dist/Overview-D_c18mbR.mjs +248 -0
  29. package/dist/Overview-Dffo-zH4.mjs +11 -0
  30. package/dist/Overview-g4Rcj245.js +1 -0
  31. package/dist/{TableCalculationWidget-CrqcLGfU.mjs → TableCalculationWidget-B_LFoOYm.mjs} +3 -3
  32. package/dist/{TableCalculationWidget-CkQPrVUd.js → TableCalculationWidget-CahOIcbk.js} +1 -1
  33. package/dist/TableDataWidget-BwqWFH4A.js +1 -0
  34. package/dist/TableDataWidget-RsVxcDsL.mjs +112 -0
  35. package/dist/TableOverviewCard-BPWCqo56.js +1 -0
  36. package/dist/{TableOverviewCard-Ci0d4o4w.mjs → TableOverviewCard-D667DDag.mjs} +113 -127
  37. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-C3XiOXgb.js +1 -0
  38. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-sp0TLio0.mjs +547 -0
  39. package/dist/{TableRowActionCard-BhdnnPaq.mjs → TableRowActionCard-BPYJ-Kjy.mjs} +95 -101
  40. package/dist/TableRowActionCard-Bnqj1YIe.js +1 -0
  41. package/dist/TableView-CwhZ9YN2.js +4 -0
  42. package/dist/TableView-DX9PKS8N.mjs +9673 -0
  43. package/dist/TemplateBuilder.vue_vue_type_script_setup_true_lang-BgDdzbLe.js +1 -0
  44. package/dist/TemplateBuilder.vue_vue_type_script_setup_true_lang-D85V4nrQ.mjs +2886 -0
  45. package/dist/Test-CzmOmi53.mjs +447 -0
  46. package/dist/Test-USDtNFY1.js +1 -0
  47. package/dist/UserDetail-DpUL3mhk.mjs +1483 -0
  48. package/dist/UserDetail-KRIfxaYd.js +1 -0
  49. package/dist/cms-core-modules.css +1 -1
  50. package/dist/dateRangePresets-CaPVagHY.mjs +453 -0
  51. package/dist/dateRangePresets-gxQCiZ6c.js +1 -0
  52. package/dist/index-6hZ6MYY6.js +1 -0
  53. package/dist/index-BVmmicu3.mjs +14 -0
  54. package/dist/index-CQuN5rKx.js +1 -0
  55. package/dist/index-ChHD_1Cf.js +144 -0
  56. package/dist/index-CnDGeInm.js +1 -0
  57. package/dist/index-CqDTc5Ig.mjs +20 -0
  58. package/dist/index-CvV4nVWI.js +1 -0
  59. package/dist/index-CyvvAdt4.js +1 -0
  60. package/dist/index-DH2z0W_w.mjs +19012 -0
  61. package/dist/index-DIRD7t5_.mjs +20 -0
  62. package/dist/index-DZKzj48V.mjs +17 -0
  63. package/dist/index-OJuBYR60.mjs +57 -0
  64. package/dist/index.cjs.js +1 -1
  65. package/dist/index.mjs +480 -103
  66. package/dist/orders-C_sz8J9b.js +1 -0
  67. package/dist/{orders-BfTLIm7U.mjs → orders-Cgdggzvx.mjs} +84 -84
  68. package/dist/server-handlers.cjs.js +1 -1
  69. package/dist/server-handlers.mjs +2696 -605
  70. package/dist/src/appointments/chat-components/AppointmentListTable.vue.d.ts +3 -0
  71. package/dist/src/appointments/index.d.ts +93 -3
  72. package/dist/src/appointments/reservation-summary.d.ts +48 -0
  73. package/dist/src/appointments/server.d.ts +1 -0
  74. package/dist/src/appointments/tools.d.ts +93 -3
  75. package/dist/src/contentManager/components/content-editor/tiptap-extensions/Container.d.ts +1 -1
  76. package/dist/src/contentManager/components/content-editor/tiptap-extensions/Row.d.ts +7 -0
  77. package/dist/src/contentManager/components/content-editor/tiptap-extensions/Stack.d.ts +7 -0
  78. package/dist/src/contentManager/components/content-editor/tiptap-extensions/helpers/resizeHistory.d.ts +9 -0
  79. package/dist/src/contentManager/components/content-editor/tiptap-menus/ElementEditorMenu.vue.d.ts +3 -1
  80. package/dist/src/filezone/config.d.ts +31 -0
  81. package/dist/src/filezone/index.d.ts +43 -0
  82. package/dist/src/filezone/index.vue.d.ts +2 -0
  83. package/dist/src/filezone/metadata.d.ts +2 -0
  84. package/dist/src/filezone/pages/Overview.vue.d.ts +4 -0
  85. package/dist/src/filezone/permissions.d.ts +5 -0
  86. package/dist/src/filezone/routes.d.ts +5 -0
  87. package/dist/src/filezone/server.d.ts +36 -0
  88. package/dist/src/firebaseAuthManager/components/DeleteUserDialog.vue.d.ts +25 -0
  89. package/dist/src/firebaseAuthManager/components/ReasonActionDialog.vue.d.ts +23 -0
  90. package/dist/src/firebaseAuthManager/components/UserStatusBadge.vue.d.ts +5 -0
  91. package/dist/src/firebaseAuthManager/config.d.ts +151 -0
  92. package/dist/src/firebaseAuthManager/index.d.ts +163 -0
  93. package/dist/src/firebaseAuthManager/index.vue.d.ts +14 -0
  94. package/dist/src/firebaseAuthManager/metadata.d.ts +2 -0
  95. package/dist/src/firebaseAuthManager/pages/Overview.vue.d.ts +2 -0
  96. package/dist/src/firebaseAuthManager/pages/UserDetail.vue.d.ts +2 -0
  97. package/dist/src/firebaseAuthManager/permissions.d.ts +5 -0
  98. package/dist/src/firebaseAuthManager/routes.d.ts +5 -0
  99. package/dist/src/firebaseAuthManager/server.d.ts +162 -0
  100. package/dist/src/firebaseAuthManager/types.d.ts +84 -0
  101. package/dist/src/formBuilder/components/FormPreviewDialog.vue.d.ts +12 -0
  102. package/dist/src/formBuilder/components/FormStatusBadge.vue.d.ts +9 -0
  103. package/dist/src/formBuilder/config.d.ts +31 -0
  104. package/dist/src/formBuilder/index.d.ts +44 -0
  105. package/dist/src/formBuilder/index.vue.d.ts +14 -0
  106. package/dist/src/formBuilder/lib/forms.d.ts +11 -0
  107. package/dist/src/formBuilder/metadata.d.ts +2 -0
  108. package/dist/src/formBuilder/pages/Editor.vue.d.ts +2 -0
  109. package/dist/src/formBuilder/pages/Overview.vue.d.ts +2 -0
  110. package/dist/src/formBuilder/permissions.d.ts +5 -0
  111. package/dist/src/formBuilder/routes.d.ts +5 -0
  112. package/dist/src/formBuilder/server.d.ts +87 -0
  113. package/dist/src/formBuilder/tools.d.ts +1 -0
  114. package/dist/src/formBuilder/types.d.ts +46 -0
  115. package/dist/src/helpbot/composables/useHelpbotApi.d.ts +18 -0
  116. package/dist/src/helpbot/config.d.ts +17 -0
  117. package/dist/src/helpbot/index.d.ts +29 -0
  118. package/dist/src/helpbot/index.vue.d.ts +2 -0
  119. package/dist/src/helpbot/metadata.d.ts +2 -0
  120. package/dist/src/helpbot/pages/Knowledge.vue.d.ts +4 -0
  121. package/dist/src/helpbot/pages/Overview.vue.d.ts +2 -0
  122. package/dist/src/helpbot/pages/Test.vue.d.ts +4 -0
  123. package/dist/src/helpbot/permissions.d.ts +5 -0
  124. package/dist/src/helpbot/routes.d.ts +5 -0
  125. package/dist/src/helpbot/types.d.ts +42 -0
  126. package/dist/src/index.d.ts +5 -0
  127. package/dist/src/mailTemplates/builder-types.d.ts +40 -0
  128. package/dist/src/mailTemplates/components/BlockRenderer.vue.d.ts +24 -0
  129. package/dist/src/mailTemplates/components/DesignPanel.vue.d.ts +13 -0
  130. package/dist/src/mailTemplates/components/EmailCanvas.vue.d.ts +44 -0
  131. package/dist/src/mailTemplates/components/RichTextEditor.vue.d.ts +10 -0
  132. package/dist/src/mailTemplates/components/RightSidebar.vue.d.ts +18 -0
  133. package/dist/src/mailTemplates/components/SettingsPanel.vue.d.ts +15 -0
  134. package/dist/src/mailTemplates/components/TemplateBuilder.vue.d.ts +2 -0
  135. package/dist/src/mailTemplates/components/TemplateList.vue.d.ts +19 -1
  136. package/dist/src/mailTemplates/components/rich-text.d.ts +6 -0
  137. package/dist/src/mailTemplates/config.d.ts +10 -4
  138. package/dist/src/mailTemplates/defaults.d.ts +10 -0
  139. package/dist/src/mailTemplates/editor-state.d.ts +21 -0
  140. package/dist/src/mailTemplates/index.d.ts +11 -5
  141. package/dist/src/mailTemplates/index.vue.d.ts +2 -4
  142. package/dist/src/mailTemplates/metadata.d.ts +1 -1
  143. package/dist/src/mailTemplates/pages/Detail.vue.d.ts +1 -13
  144. package/dist/src/mailTemplates/pages/Overview.vue.d.ts +1 -13
  145. package/dist/src/mailTemplates/server.d.ts +23 -0
  146. package/dist/src/server-handlers.d.ts +6 -0
  147. package/dist/src/table/badge-filter-utils.d.ts +8 -0
  148. package/dist/src/table/chat-components/TableOverviewCard.vue.d.ts +2 -7
  149. package/dist/src/table/chat-components/TableResultView.vue.d.ts +3 -7
  150. package/dist/src/table/components/TableDisplayCell.vue.d.ts +8 -0
  151. package/dist/src/table/components/columns/BadgeColumnSettings.vue.d.ts +9 -0
  152. package/dist/src/table/components/columns/ColumnColorSelect.vue.d.ts +11 -0
  153. package/dist/src/table/components/columns/ColumnDisplaySettings.vue.d.ts +9 -0
  154. package/dist/src/table/components/columns/ColumnTypeSelect.vue.d.ts +11 -0
  155. package/dist/src/table/components/columns/ColumnValueSourceInput.vue.d.ts +15 -0
  156. package/dist/src/table/components/columns/DialogTableColumnItem.vue.d.ts +8 -11
  157. package/dist/src/table/components/columns/ProgressColumnSettings.vue.d.ts +8 -0
  158. package/dist/src/table/components/stats/StatDialog.vue.d.ts +6 -10
  159. package/dist/src/table/components/stats/Stats.vue.d.ts +9 -15
  160. package/dist/src/table/composables/useTableClock.d.ts +4 -0
  161. package/dist/src/table/display-utils.d.ts +35 -0
  162. package/dist/src/table/row-value.d.ts +1 -0
  163. package/dist/src/table/stat-utils.d.ts +9 -0
  164. package/dist/src/table/tool-utils.d.ts +1 -1
  165. package/dist/src/table/types.d.ts +54 -1
  166. package/dist/src/whatsappBusiness/analytics.d.ts +4 -0
  167. package/dist/src/whatsappBusiness/components/AccountPanel.vue.d.ts +2 -0
  168. package/dist/src/whatsappBusiness/components/InsightsPanel.vue.d.ts +5 -0
  169. package/dist/src/whatsappBusiness/components/TemplateDialog.vue.d.ts +14 -0
  170. package/dist/src/whatsappBusiness/components/TemplatesPanel.vue.d.ts +5 -0
  171. package/dist/src/whatsappBusiness/components/presentation.d.ts +4 -0
  172. package/dist/src/whatsappBusiness/config.d.ts +51 -0
  173. package/dist/src/whatsappBusiness/connection.d.ts +77 -0
  174. package/dist/src/whatsappBusiness/index.d.ts +63 -0
  175. package/dist/src/whatsappBusiness/index.vue.d.ts +5 -0
  176. package/dist/src/whatsappBusiness/metadata.d.ts +2 -0
  177. package/dist/src/whatsappBusiness/pages/Overview.vue.d.ts +2 -0
  178. package/dist/src/whatsappBusiness/permissions.d.ts +5 -0
  179. package/dist/src/whatsappBusiness/provider.d.ts +21 -0
  180. package/dist/src/whatsappBusiness/routes.d.ts +5 -0
  181. package/dist/src/whatsappBusiness/server.d.ts +14 -0
  182. package/dist/src/whatsappBusiness/templates.d.ts +94 -0
  183. package/dist/src/whatsappBusiness/types.d.ts +162 -0
  184. package/dist/{tool-sandbox-DoF1PsyS.js → tool-sandbox-BSkKdH7V.js} +1 -1
  185. package/dist/{tool-sandbox-DdkMLkDK.mjs → tool-sandbox-DU9b1B7v.mjs} +1 -1
  186. package/dist/types-9N-DKxNj.mjs +250 -0
  187. package/dist/types-B5MifmeF.mjs +2696 -0
  188. package/dist/types-Cem0vPo_.js +1 -0
  189. package/dist/types-D5dgTskW.js +1 -0
  190. package/dist/useHelpbotApi-BIIungOh.js +1 -0
  191. package/dist/useHelpbotApi-HC9JSiSn.mjs +229 -0
  192. package/dist/{useTableAgentTools-D5mzGf3A.js → useTableAgentTools-BrUot49I.js} +1 -1
  193. package/dist/{useTableAgentTools-DcN3kYRL.mjs → useTableAgentTools-r5InEI4p.mjs} +8 -8
  194. package/dist/vee-validate-zod-CWZwNTWE.js +1 -0
  195. package/dist/vee-validate-zod-D0WaDgDZ.mjs +1780 -0
  196. package/package.json +2 -2
  197. package/src/appointments/tools.ts +52 -2
  198. package/src/formBuilder/tools.ts +1 -0
  199. package/dist/AppointmentListTable-DZJNmTMb.mjs +0 -177
  200. package/dist/AppointmentListTable-Dieu9US_.js +0 -1
  201. package/dist/ContentEditor-C-Wm48ai.js +0 -467
  202. package/dist/Detail-BCUUNWvp.js +0 -1
  203. package/dist/Detail-Byk781b4.mjs +0 -26
  204. package/dist/Detail-DGg_xXZc.js +0 -1
  205. package/dist/Detail-Sc2qZdxj.js +0 -1
  206. package/dist/Detail-mvSGbnFU.js +0 -1
  207. package/dist/Overview-BDlBCUI_.js +0 -1
  208. package/dist/Overview-Su8ZUbMs.mjs +0 -26
  209. package/dist/TableDataWidget-7qvC3Egd.js +0 -1
  210. package/dist/TableDataWidget-DMTSoGRO.mjs +0 -121
  211. package/dist/TableOverviewCard-AFq-puJs.js +0 -1
  212. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-CBn-Oxl9.mjs +0 -534
  213. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-C_Lv-SmJ.js +0 -1
  214. package/dist/TableRowActionCard-IzB6tNN-.js +0 -1
  215. package/dist/TableView-BkwoKREo.js +0 -4
  216. package/dist/TableView-C4Zyp8d7.mjs +0 -8228
  217. package/dist/TemplateList.vue_vue_type_script_setup_true_lang-B_AtWnHa.js +0 -1
  218. package/dist/TemplateList.vue_vue_type_script_setup_true_lang-Cmovy7kk.mjs +0 -40
  219. package/dist/dateRangePresets-B-l5b_wR.mjs +0 -48
  220. package/dist/dateRangePresets-CPWqst_x.js +0 -1
  221. package/dist/orders-DUa2PVoa.js +0 -1
  222. package/dist/vee-validate-zod-SjDT8X35.mjs +0 -4404
  223. package/dist/vee-validate-zod-VCmLnrtQ.js +0 -1
@@ -0,0 +1,2886 @@
1
+ import { defineComponent as me, useModel as kt, computed as j, resolveComponent as U, openBlock as s, createElementBlock as u, createElementVNode as l, createTextVNode as c, toDisplayString as $, createBlock as N, withCtx as p, createVNode as o, unref as w, createCommentVNode as T, Fragment as P, renderList as te, normalizeClass as ie, resolveDynamicComponent as fe, mergeModels as Xe, h as lt, withModifiers as ye, normalizeStyle as K, ref as D, reactive as ht, watch as he, onBeforeUnmount as ot, withDirectives as G, vShow as wt, vModelSelect as Me, vModelCheckbox as St, withKeys as _e, vModelText as ne, createStaticVNode as Ct, Transition as $t, onMounted as Bt } from "vue";
2
+ import { useModuleApi as nt, useModulePermissions as Tt, useModuleRoute as Vt, useRouter as Ut, useModuleBreadcrumbs as Dt } from "@oneclick.dev/cms-kit";
3
+ import { Plus as Le, Search as zt, ChevronRight as It, Mail as Ee, ShieldCheck as Mt, Bell as Lt, CreditCard as At, KeyRound as Rt, UserPlus as jt, GripVertical as Et, Pencil as at, MoveUp as Nt, MoveDown as Ht, Copy as Oe, Trash2 as st, Image as We, Undo2 as Pt, Redo2 as Ft, Download as Ot, Loader2 as Ne, Check as He, Eye as Wt, Code2 as it, Monitor as Jt, Tablet as qt, Smartphone as Yt, Type as rt, AlignLeft as Pe, MousePointer as dt, Columns as ut, Minus as mt, Square as Fe, AlertCircle as Kt, Bold as Gt, Italic as Qt, Underline as Zt, Strikethrough as Xt, List as _t, ListOrdered as el, Link as tl, Unlink as ll, RemoveFormatting as ol, X as nl, AlignCenter as al, AlignRight as sl, Code as il, RotateCcw as rl, Palette as dl, Settings2 as ul, PanelLeft as ml, SlidersHorizontal as cl } from "lucide-vue-next";
4
+ import { t as ae } from "./index-RLz1QPrf.mjs";
5
+ import { _ as ct } from "./_plugin-vue_export-helper-CHgC5LLL.mjs";
6
+ import { E as pl, M as vl, C as fl, I as bl, O as xl } from "./index-DH2z0W_w.mjs";
7
+ const Ue = {
8
+ bodyBg: "#f4f4f5",
9
+ contentBg: "#ffffff",
10
+ footerBg: "#f4f4f5",
11
+ footerTextColor: "#71717a",
12
+ primaryColor: "#18181b",
13
+ primaryForeground: "#ffffff",
14
+ textColor: "#18181b",
15
+ secondaryTextColor: "#71717a",
16
+ linkColor: "#2563eb",
17
+ fontFamily: "Arial, Helvetica, sans-serif",
18
+ borderRadius: 8,
19
+ contentWidth: 600,
20
+ contentPadding: 40,
21
+ logoUrl: "",
22
+ footerText: "© {{year}} {{agency_name}}. All rights reserved.",
23
+ showUnsubscribe: !0,
24
+ showSocialLinks: !1
25
+ };
26
+ function je(t) {
27
+ switch (t) {
28
+ case "header":
29
+ return { text: "Heading", level: "h2", align: "left" };
30
+ case "text":
31
+ return { html: "<p>Enter your text here...</p>" };
32
+ case "button":
33
+ return { text: "Click Here", url: "#", align: "center", variant: "primary" };
34
+ case "image":
35
+ return { src: "", alt: "Image", width: 600, align: "center" };
36
+ case "divider":
37
+ return { color: "#e5e7eb" };
38
+ case "spacer":
39
+ return { height: 24 };
40
+ case "columns":
41
+ return { columns: [{ label: "Label", value: "Value" }, { label: "Label", value: "Value" }] };
42
+ default:
43
+ return {};
44
+ }
45
+ }
46
+ const pt = [
47
+ {
48
+ name: "Welcome Email",
49
+ subject: "Welcome to {{agency_name}}, {{user_name}}!",
50
+ description: "Sent when a new user is invited to the dashboard.",
51
+ category: "onboarding",
52
+ status: "active",
53
+ blocks: [
54
+ { id: "welcome-header", type: "header", content: { text: "Welcome aboard, {{user_name}}!", level: "h1", align: "center" } },
55
+ { id: "welcome-text", type: "text", content: { html: "<p>You've been invited to join <strong>{{project_name}}</strong> on {{agency_name}}. Click the button below to get started.</p>" } },
56
+ { id: "welcome-btn", type: "button", content: { text: "Accept Invitation", url: "{{invite_url}}", align: "center", variant: "primary" } },
57
+ { id: "welcome-divider", type: "divider", content: { color: "#e5e7eb" } },
58
+ { id: "welcome-footer", type: "text", content: { html: `<p style="text-align:center">If you didn't expect this invitation, you can safely ignore this email.</p>` } }
59
+ ]
60
+ },
61
+ {
62
+ name: "Password Reset",
63
+ subject: "Reset your password — {{agency_name}}",
64
+ description: "Sent when a user requests a password reset.",
65
+ category: "authentication",
66
+ status: "active",
67
+ blocks: [
68
+ { id: "reset-header", type: "header", content: { text: "Password Reset", level: "h2", align: "left" } },
69
+ { id: "reset-text", type: "text", content: { html: "<p>Hi {{user_name}},</p><p>We received a request to reset the password for your account ({{user_email}}). Click the button below to choose a new password.</p>" } },
70
+ { id: "reset-btn", type: "button", content: { text: "Reset Password", url: "{{reset_url}}", align: "center", variant: "primary" } },
71
+ { id: "reset-spacer", type: "spacer", content: { height: 16 } },
72
+ { id: "reset-note", type: "text", content: { html: `<p style="font-size:13px;color:#71717a">If you didn't request this, no action is needed — your password will remain unchanged.</p>` } }
73
+ ]
74
+ },
75
+ {
76
+ name: "Payment Confirmation",
77
+ subject: "Payment received — {{agency_name}}",
78
+ description: "Sent after a successful payment is processed.",
79
+ category: "billing",
80
+ status: "active",
81
+ blocks: [
82
+ { id: "payment-header", type: "header", content: { text: "Payment Confirmed", level: "h2", align: "left" } },
83
+ { id: "payment-text", type: "text", content: { html: "<p>Hi {{user_name}},</p><p>We've successfully received your payment. Thank you for your continued support!</p>" } },
84
+ { id: "payment-divider", type: "divider", content: { color: "#e5e7eb" } },
85
+ { id: "payment-footer", type: "text", content: { html: '<p style="font-size:13px;color:#71717a">If you have questions about this charge, reach out at {{support_email}}.</p>' } }
86
+ ]
87
+ },
88
+ {
89
+ name: "Notification Digest",
90
+ subject: "Your latest updates — {{agency_name}}",
91
+ description: "Periodic summary of recent activity and notifications.",
92
+ category: "notifications",
93
+ blocks: [
94
+ { id: "digest-header", type: "header", content: { text: "Here's what you missed", level: "h2", align: "left" } },
95
+ { id: "digest-text", type: "text", content: { html: "<p>Hi {{user_name}},</p><p>Here's a summary of recent activity on {{project_name}}.</p>" } },
96
+ { id: "digest-spacer", type: "spacer", content: { height: 16 } },
97
+ { id: "digest-btn", type: "button", content: { text: "View Dashboard", url: "{{dashboard_url}}", align: "center", variant: "primary" } }
98
+ ]
99
+ },
100
+ {
101
+ name: "System Maintenance",
102
+ subject: "Scheduled maintenance — {{agency_name}}",
103
+ description: "Sent before planned system downtime or maintenance windows.",
104
+ category: "system",
105
+ blocks: [
106
+ { id: "maint-header", type: "header", content: { text: "Scheduled Maintenance", level: "h2", align: "left" } },
107
+ { id: "maint-text", type: "text", content: { html: "<p>Hi {{user_name}},</p><p>We'll be performing scheduled maintenance on {{project_name}}. During this time, some services may be temporarily unavailable.</p>" } },
108
+ { id: "maint-divider", type: "divider", content: { color: "#e5e7eb" } },
109
+ { id: "maint-footer", type: "text", content: { html: '<p style="font-size:13px;color:#71717a">No action is required on your part. If you have questions, contact {{support_email}}.</p>' } }
110
+ ]
111
+ },
112
+ {
113
+ name: "Notification",
114
+ subject: "{{notification_title}} — {{agency_name}}",
115
+ description: "Sent when a user receives a notification and has email notifications enabled.",
116
+ category: "notifications",
117
+ status: "active",
118
+ blocks: [
119
+ { id: "notif-header", type: "header", content: { text: "{{notification_title}}", level: "h2", align: "left" } },
120
+ { id: "notif-text", type: "text", content: { html: "<p>Hi {{user_name}},</p><p>{{notification_body}}</p>" } },
121
+ { id: "notif-btn", type: "button", content: { text: "View in Dashboard", url: "{{notification_url}}", align: "center", variant: "primary" } },
122
+ { id: "notif-divider", type: "divider", content: { color: "#e5e7eb" } },
123
+ { id: "notif-footer", type: "text", content: { html: `<p style="font-size:13px;color:#71717a;text-align:center">You're receiving this because you have email notifications enabled. You can update your preferences in your dashboard settings.</p>` } }
124
+ ]
125
+ }
126
+ ];
127
+ function gl() {
128
+ return structuredClone(Ue);
129
+ }
130
+ function et(t, A) {
131
+ const i = pt.find((f) => A ? f.system_key === A : f.name === t);
132
+ return i ? structuredClone(i) : null;
133
+ }
134
+ function yl() {
135
+ return structuredClone(pt);
136
+ }
137
+ function vt(t) {
138
+ const { name: A, subject: i, preheader: f, description: m, category: B, status: g, blocks: I, styles: Y } = t;
139
+ return { name: A, subject: i, preheader: f, description: m, category: B, status: g, blocks: I, styles: Y };
140
+ }
141
+ function ke(t) {
142
+ return JSON.stringify(vt(t));
143
+ }
144
+ function Ve(t, A = 60) {
145
+ let i = [t], f = 0;
146
+ return {
147
+ get canUndo() {
148
+ return f > 0;
149
+ },
150
+ get canRedo() {
151
+ return f < i.length - 1;
152
+ },
153
+ record(m) {
154
+ i[f] !== m && (i = i.slice(0, f + 1), i.push(m), i.length > A && i.shift(), f = i.length - 1);
155
+ },
156
+ undo() {
157
+ return f > 0 ? i[--f] : null;
158
+ },
159
+ redo() {
160
+ return f < i.length - 1 ? i[++f] : null;
161
+ }
162
+ };
163
+ }
164
+ function kl(...t) {
165
+ const A = JSON.stringify(t).matchAll(/\{\{(\w+)\}\}/g);
166
+ return [...new Set(Array.from(A, (i) => i[1]))].sort();
167
+ }
168
+ const hl = { class: "w-full xl:w-[240px] xl:min-w-[240px] border-r bg-card flex flex-col" }, wl = { class: "p-4 border-b" }, Sl = { class: "flex items-center justify-between mb-3" }, Cl = { class: "text-sm font-semibold" }, $l = { class: "ml-1 text-xs text-muted-foreground" }, Bl = { class: "relative" }, Tl = { class: "p-2" }, Vl = ["onClick"], Ul = { class: "flex items-start gap-3" }, Dl = { class: "min-w-0 flex-1" }, zl = { class: "flex items-center gap-2" }, Il = { class: "font-medium text-sm truncate" }, Ml = {
169
+ key: 0,
170
+ class: "size-1.5 shrink-0 rounded-full bg-amber-500",
171
+ title: "Unsaved changes",
172
+ "aria-label": "Unsaved changes"
173
+ }, Ll = { class: "text-xs text-muted-foreground mt-0.5 truncate" }, Al = {
174
+ key: 0,
175
+ class: "text-[11px] text-muted-foreground/60 mt-1"
176
+ }, Rl = {
177
+ key: 0,
178
+ class: "text-center py-12 px-4"
179
+ }, jl = /* @__PURE__ */ me({
180
+ __name: "TemplateList",
181
+ props: /* @__PURE__ */ Xe({
182
+ templates: {},
183
+ selectedTemplateId: {},
184
+ dirtyTemplateIds: {},
185
+ canCreate: { type: Boolean }
186
+ }, {
187
+ searchQuery: { default: "" },
188
+ searchQueryModifiers: {}
189
+ }),
190
+ emits: /* @__PURE__ */ Xe(["select", "create"], ["update:searchQuery"]),
191
+ setup(t, { emit: A }) {
192
+ const i = t, f = A, m = kt(t, "searchQuery"), B = (V) => ({
193
+ onboarding: jt,
194
+ authentication: Rt,
195
+ billing: At,
196
+ notifications: Lt,
197
+ system: Mt
198
+ })[V] ?? Ee, g = (V) => ({
199
+ onboarding: "text-emerald-500",
200
+ authentication: "text-amber-500",
201
+ billing: "text-blue-500",
202
+ notifications: "text-purple-500",
203
+ system: "text-stone-500"
204
+ })[V] ?? "text-stone-400", I = (V) => {
205
+ const v = Math.floor((Date.now() - new Date(V).getTime()) / 1e3);
206
+ if (v < 60) return "just now";
207
+ const b = Math.floor(v / 60);
208
+ if (b < 60) return `${b}m ago`;
209
+ const C = Math.floor(b / 60);
210
+ if (C < 24) return `${C}h ago`;
211
+ const H = Math.floor(C / 24);
212
+ return H < 30 ? `${H}d ago` : `${Math.floor(H / 30)}mo ago`;
213
+ }, Y = j(() => {
214
+ let V = i.templates;
215
+ if (m.value.trim()) {
216
+ const v = m.value.toLowerCase();
217
+ V = V.filter(
218
+ (b) => b.name.toLowerCase().includes(v) || (b.description || "").toLowerCase().includes(v) || b.subject.toLowerCase().includes(v)
219
+ );
220
+ }
221
+ return V;
222
+ });
223
+ return (V, v) => {
224
+ const b = U("Button"), C = U("Input"), H = U("ScrollArea");
225
+ return s(), u("div", hl, [
226
+ l("div", wl, [
227
+ l("div", Sl, [
228
+ l("h2", Cl, [
229
+ v[2] || (v[2] = c("Mail templates ", -1)),
230
+ l("span", $l, $(t.templates.length), 1)
231
+ ]),
232
+ t.canCreate ? (s(), N(b, {
233
+ key: 0,
234
+ variant: "ghost",
235
+ size: "icon",
236
+ class: "size-7",
237
+ "aria-label": "Create template",
238
+ title: "Create template",
239
+ onClick: v[0] || (v[0] = (k) => f("create"))
240
+ }, {
241
+ default: p(() => [
242
+ o(w(Le), { class: "size-4" })
243
+ ]),
244
+ _: 1
245
+ })) : T("", !0)
246
+ ]),
247
+ l("div", Bl, [
248
+ o(C, {
249
+ modelValue: m.value,
250
+ "onUpdate:modelValue": v[1] || (v[1] = (k) => m.value = k),
251
+ type: "search",
252
+ placeholder: "Search templates...",
253
+ "aria-label": "Search templates",
254
+ class: "pl-9 h-9 text-sm appearance-none [&::-webkit-search-cancel-button]:appearance-none"
255
+ }, null, 8, ["modelValue"]),
256
+ o(w(zt), { class: "absolute left-3 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground" })
257
+ ])
258
+ ]),
259
+ o(H, { class: "flex-1" }, {
260
+ default: p(() => [
261
+ l("div", Tl, [
262
+ (s(!0), u(P, null, te(Y.value, (k) => (s(), u("button", {
263
+ key: k.id,
264
+ onClick: (h) => f("select", k.id),
265
+ class: ie(["w-full text-left p-3 rounded-lg mb-1 transition-all duration-150 group", t.selectedTemplateId === k.id ? "bg-primary/5 border border-primary/20 shadow-sm" : "hover:bg-accent/50 border border-transparent"])
266
+ }, [
267
+ l("div", Ul, [
268
+ l("div", {
269
+ class: ie(["mt-0.5 size-8 rounded-lg flex items-center justify-center shrink-0", t.selectedTemplateId === k.id ? "bg-primary/10" : "bg-secondary"])
270
+ }, [
271
+ (s(), N(fe(B(k.category)), {
272
+ class: ie(["size-4", g(k.category)])
273
+ }, null, 8, ["class"]))
274
+ ], 2),
275
+ l("div", Dl, [
276
+ l("div", zl, [
277
+ l("span", Il, $(k.name), 1),
278
+ t.dirtyTemplateIds.includes(k.id) ? (s(), u("span", Ml)) : T("", !0)
279
+ ]),
280
+ l("p", Ll, $(k.description), 1),
281
+ k.updated_at ? (s(), u("p", Al, "Edited " + $(I(k.updated_at)), 1)) : T("", !0)
282
+ ]),
283
+ o(w(It), {
284
+ class: ie(["size-4 text-muted-foreground/40 shrink-0 mt-1 transition-transform", t.selectedTemplateId === k.id ? "text-primary" : "opacity-0 group-hover:opacity-100"])
285
+ }, null, 8, ["class"])
286
+ ])
287
+ ], 10, Vl))), 128)),
288
+ Y.value.length === 0 ? (s(), u("div", Rl, [
289
+ o(w(Ee), { class: "mx-auto size-10 text-muted-foreground/30" }),
290
+ v[3] || (v[3] = l("p", { class: "text-sm text-muted-foreground mt-2" }, "No templates found", -1)),
291
+ v[4] || (v[4] = l("p", { class: "text-xs text-muted-foreground/60 mt-1" }, "Try a different search or create a template", -1))
292
+ ])) : T("", !0)
293
+ ])
294
+ ]),
295
+ _: 1
296
+ })
297
+ ]);
298
+ };
299
+ }
300
+ });
301
+ function ft(t) {
302
+ const A = {}, { color: i, fontSize: f, textAlign: m } = t.style;
303
+ return /^(#[\da-f]{3,8}|[a-z]+|rgba?\([\d.,%\s]+\)|hsla?\([\d.,%\s]+\))$/i.test(i) && (A.color = i), /^\d+(\.\d+)?px$/.test(f) && parseFloat(f) >= 8 && parseFloat(f) <= 72 && (A.fontSize = f), ["left", "center", "right", "justify"].includes(m) && (A.textAlign = m), A;
304
+ }
305
+ function tt(t) {
306
+ return /^(https?:\/\/[^\s]+|mailto:[^\s]+|tel:[+\d\s()-]+|#[\w-]*|\{\{\w+\}\})$/i.test(t.trim());
307
+ }
308
+ const El = /* @__PURE__ */ new Set(["p", "br", "strong", "b", "em", "i", "u", "s", "a", "ul", "ol", "li", "blockquote", "span", "h1", "h2", "h3"]), Nl = /* @__PURE__ */ new Set(["script", "style", "iframe", "object", "embed", "svg", "math", "template", "head"]);
309
+ function Hl(t) {
310
+ if (typeof DOMParser > "u") return [t.replace(/<[^>]*>/g, "")];
311
+ const A = new DOMParser().parseFromString(t, "text/html"), i = (f) => {
312
+ if (f.nodeType === 3) return f.textContent ?? "";
313
+ if (f.nodeType !== 1) return null;
314
+ const m = f, B = m.tagName.toLowerCase();
315
+ if (Nl.has(B)) return null;
316
+ const g = Array.from(m.childNodes, i);
317
+ return El.has(B) ? lt(B === "a" ? "span" : B, {
318
+ style: ft(m),
319
+ ...B === "a" ? { class: "email-preview-link" } : {}
320
+ }, B === "br" ? void 0 : g) : g;
321
+ };
322
+ return Array.from(A.body.childNodes, i);
323
+ }
324
+ const Pl = ["aria-label"], Fl = ["aria-label"], Ol = ["aria-label"], Wl = ["disabled"], Jl = ["disabled"], ql = { class: "p-3 text-center" }, Yl = { class: "mt-1 text-xs text-muted-foreground" }, Kl = ["src", "alt"], Gl = /* @__PURE__ */ me({
325
+ __name: "BlockRenderer",
326
+ props: {
327
+ block: {},
328
+ index: {},
329
+ totalBlocks: {},
330
+ selectedBlockId: {},
331
+ templateStyles: {}
332
+ },
333
+ emits: ["select", "move", "duplicate", "delete", "drag-start", "drag-end"],
334
+ setup(t, { emit: A }) {
335
+ const i = t, f = A, m = j(() => ({ header: "Heading", text: "Text", button: "Button", image: "Image", divider: "Divider", spacer: "Spacer", columns: "Columns" })[i.block.type]), B = j(() => i.selectedBlockId === i.block.id), g = j(() => ["h1", "h2", "h3"].includes(i.block.content.level) ? i.block.content.level : "h2"), I = (k, h, e) => k === "" || k === void 0 || k === null || !Number.isFinite(Number(k)) ? h : Math.min(e, Math.max(0, Number(k))), Y = j(() => ({
336
+ paddingTop: `${I(i.block.content.paddingTop, ["button", "divider"].includes(i.block.type) ? 8 : 0, 80)}px`,
337
+ paddingBottom: `${I(i.block.content.paddingBottom, i.block.type === "spacer" ? 0 : 16, 80)}px`
338
+ })), V = j(() => ({
339
+ color: i.block.content.color || i.templateStyles.textColor,
340
+ fontSize: `${I(i.block.content.fontSize, i.block.type === "header" ? { h1: 28, h2: 22, h3: 18 }[g.value] || 22 : 15, 72)}px`,
341
+ textAlign: i.block.content.align || "left",
342
+ lineHeight: i.block.type === "header" ? "1.3" : "1.6"
343
+ })), v = j(() => /^https?:\/\/[^\s]+$/i.test(i.block.content.src || "") ? i.block.content.src : ""), b = me({
344
+ props: { html: { type: String, default: "" } },
345
+ setup: (k) => () => lt("div", { class: "email-block-rich-text" }, Hl(k.html))
346
+ });
347
+ function C(k) {
348
+ const h = k.target.closest("button");
349
+ if (h && !h.hasAttribute("data-email-drag-handle")) {
350
+ k.preventDefault();
351
+ return;
352
+ }
353
+ if (k.dataTransfer) {
354
+ k.dataTransfer.effectAllowed = "move", k.dataTransfer.setData("text/plain", i.block.id);
355
+ const e = k.currentTarget, x = e.getBoundingClientRect();
356
+ k.dataTransfer.setDragImage(e, k.clientX - x.left, k.clientY - x.top);
357
+ }
358
+ f("drag-start", i.block.id);
359
+ }
360
+ function H(k) {
361
+ k.target === k.currentTarget && (k.key === "Enter" || k.key === " ") && (k.preventDefault(), f("select", i.block.id));
362
+ }
363
+ return (k, h) => (s(), u("div", {
364
+ draggable: "true",
365
+ tabindex: "0",
366
+ role: "group",
367
+ "aria-label": `${m.value} block ${t.index + 1} of ${t.totalBlocks}${B.value ? ", selected" : ""}. Press Enter to edit.`,
368
+ class: ie(["group relative min-h-6 cursor-grab select-none rounded outline-none active:cursor-grabbing focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2", B.value ? "ring-2 ring-primary ring-offset-2" : "hover:ring-1 hover:ring-primary/30 hover:ring-offset-1"]),
369
+ style: K(Y.value),
370
+ onClick: h[6] || (h[6] = ye((e) => f("select", t.block.id), ["stop"])),
371
+ onKeydown: H,
372
+ onDragstart: ye(C, ["stop"]),
373
+ onDragend: h[7] || (h[7] = ye((e) => f("drag-end"), ["stop"]))
374
+ }, [
375
+ l("div", {
376
+ class: ie(["absolute -right-1 -top-3 z-10 flex items-center gap-0.5 rounded border bg-card p-0.5 text-card-foreground shadow-sm transition-opacity group-focus-within:opacity-100", B.value ? "opacity-100" : "opacity-0 group-hover:opacity-100"]),
377
+ onClick: h[5] || (h[5] = ye(() => {
378
+ }, ["stop"]))
379
+ }, [
380
+ l("button", {
381
+ type: "button",
382
+ draggable: "true",
383
+ "data-email-drag-handle": "",
384
+ "aria-label": `Drag ${m.value.toLowerCase()} block to reorder`,
385
+ title: "Drag to reorder; use arrow buttons for keyboard control",
386
+ class: "cursor-grab rounded p-1.5 hover:bg-accent active:cursor-grabbing"
387
+ }, [
388
+ o(w(Et), { class: "size-3.5" })
389
+ ], 8, Fl),
390
+ l("button", {
391
+ type: "button",
392
+ "aria-label": `Edit ${m.value.toLowerCase()} block`,
393
+ title: "Edit block",
394
+ class: "rounded p-1.5 hover:bg-accent",
395
+ onClick: h[0] || (h[0] = (e) => f("select", t.block.id))
396
+ }, [
397
+ o(w(at), { class: "size-3.5" })
398
+ ], 8, Ol),
399
+ l("button", {
400
+ type: "button",
401
+ "aria-label": "Move block up",
402
+ title: "Move block up",
403
+ disabled: t.index === 0,
404
+ class: "rounded p-1.5 hover:bg-accent disabled:pointer-events-none disabled:opacity-30",
405
+ onClick: h[1] || (h[1] = (e) => f("move", t.block.id, "up"))
406
+ }, [
407
+ o(w(Nt), { class: "size-3.5" })
408
+ ], 8, Wl),
409
+ l("button", {
410
+ type: "button",
411
+ "aria-label": "Move block down",
412
+ title: "Move block down",
413
+ disabled: t.index === t.totalBlocks - 1,
414
+ class: "rounded p-1.5 hover:bg-accent disabled:pointer-events-none disabled:opacity-30",
415
+ onClick: h[2] || (h[2] = (e) => f("move", t.block.id, "down"))
416
+ }, [
417
+ o(w(Ht), { class: "size-3.5" })
418
+ ], 8, Jl),
419
+ l("button", {
420
+ type: "button",
421
+ "aria-label": "Duplicate block",
422
+ title: "Duplicate block",
423
+ class: "rounded p-1.5 hover:bg-accent",
424
+ onClick: h[3] || (h[3] = (e) => f("duplicate", t.block.id))
425
+ }, [
426
+ o(w(Oe), { class: "size-3.5" })
427
+ ]),
428
+ l("button", {
429
+ type: "button",
430
+ "aria-label": "Delete block",
431
+ title: "Delete block",
432
+ class: "rounded p-1.5 hover:bg-destructive/10 hover:text-destructive",
433
+ onClick: h[4] || (h[4] = (e) => f("delete", t.block.id))
434
+ }, [
435
+ o(w(st), { class: "size-3.5" })
436
+ ])
437
+ ], 2),
438
+ t.block.type === "header" ? (s(), N(fe(g.value), {
439
+ key: 0,
440
+ class: "m-0 font-bold",
441
+ style: K(V.value)
442
+ }, {
443
+ default: p(() => [
444
+ c($(t.block.content.text), 1)
445
+ ]),
446
+ _: 1
447
+ }, 8, ["style"])) : t.block.type === "text" ? (s(), N(w(b), {
448
+ key: 1,
449
+ html: t.block.content.html || "",
450
+ style: K({ ...V.value, "--email-link-color": t.templateStyles.linkColor })
451
+ }, null, 8, ["html", "style"])) : t.block.type === "button" ? (s(), u("div", {
452
+ key: 2,
453
+ style: K({ textAlign: t.block.content.align || "center" })
454
+ }, [
455
+ l("span", {
456
+ class: "inline-block px-7 py-3 text-[15px] font-semibold",
457
+ style: K({
458
+ backgroundColor: t.block.content.variant === "secondary" ? "transparent" : t.templateStyles.primaryColor,
459
+ color: t.block.content.variant === "secondary" ? t.templateStyles.primaryColor : t.templateStyles.primaryForeground,
460
+ border: t.block.content.variant === "secondary" ? `2px solid ${t.templateStyles.primaryColor}` : "none",
461
+ borderRadius: t.templateStyles.borderRadius + "px"
462
+ })
463
+ }, $(t.block.content.text), 5)
464
+ ], 4)) : t.block.type === "image" ? (s(), u("div", {
465
+ key: 3,
466
+ style: K({ textAlign: t.block.content.align || "center" })
467
+ }, [
468
+ v.value ? (s(), u("img", {
469
+ key: 1,
470
+ src: v.value,
471
+ alt: t.block.content.alt || "",
472
+ style: K({ width: I(t.block.content.width, 600, 800) + "px", maxWidth: "100%" }),
473
+ class: "inline-block h-auto",
474
+ draggable: "false"
475
+ }, null, 12, Kl)) : (s(), u("div", {
476
+ key: 0,
477
+ class: "inline-flex max-w-full items-center justify-center rounded-lg border-2 border-dashed bg-muted/30",
478
+ style: K({ width: Math.min(t.block.content.width || 200, 400) + "px", minHeight: "120px" })
479
+ }, [
480
+ l("div", ql, [
481
+ o(w(We), { class: "mx-auto size-8 text-muted-foreground/40" }),
482
+ l("p", Yl, $(t.block.content.src ? "Image preview available after variables are filled" : "Select to add an image"), 1)
483
+ ])
484
+ ], 4))
485
+ ], 4)) : t.block.type === "divider" ? (s(), u("hr", {
486
+ key: 4,
487
+ class: "m-0 border-0",
488
+ style: K({ borderTopColor: t.block.content.color || "#e5e7eb", borderTopWidth: `${I(t.block.content.thickness, 1, 8)}px`, borderTopStyle: ["solid", "dashed", "dotted"].includes(t.block.content.style) ? t.block.content.style : "solid" })
489
+ }, null, 4)) : t.block.type === "spacer" ? (s(), u("div", {
490
+ key: 5,
491
+ style: K({ height: `${I(t.block.content.height, 24, 200)}px` }),
492
+ class: "min-h-2"
493
+ }, null, 4)) : t.block.type === "columns" ? (s(), u("div", {
494
+ key: 6,
495
+ class: "grid gap-2 p-2",
496
+ style: K({ gridTemplateColumns: `repeat(${Math.min(t.block.content.columns?.length || 2, 4)}, minmax(0, 1fr))`, backgroundColor: t.templateStyles.bodyBg, borderRadius: t.templateStyles.borderRadius + "px" })
497
+ }, [
498
+ (s(!0), u(P, null, te(t.block.content.columns, (e, x) => (s(), u("div", {
499
+ key: x,
500
+ class: "min-w-0 px-3 py-2"
501
+ }, [
502
+ l("p", {
503
+ class: "m-0 text-xs font-semibold uppercase tracking-wide",
504
+ style: K({ color: t.templateStyles.secondaryTextColor })
505
+ }, $(e.label), 5),
506
+ l("p", {
507
+ class: "mb-0 mt-1 break-words text-[15px] font-medium",
508
+ style: K({ color: t.templateStyles.textColor })
509
+ }, $(e.value), 5)
510
+ ]))), 128))
511
+ ], 4)) : T("", !0)
512
+ ], 46, Pl));
513
+ }
514
+ }), Ql = /* @__PURE__ */ ct(Gl, [["__scopeId", "data-v-48c20c32"]]), Zl = {
515
+ class: "flex min-w-0 flex-1 flex-col bg-background",
516
+ "aria-label": "Email builder"
517
+ }, Xl = { class: "flex flex-wrap items-center justify-between gap-3 border-b bg-card px-4 py-3" }, _l = { class: "min-w-0 flex-1" }, eo = { class: "truncate text-sm font-semibold" }, to = {
518
+ class: "mt-0.5 text-xs text-muted-foreground",
519
+ role: "status"
520
+ }, lo = { class: "flex items-center gap-1.5" }, oo = { class: "flex flex-wrap items-center justify-between gap-2 border-b bg-card px-4 py-2" }, no = {
521
+ class: "flex gap-1 rounded-md bg-muted p-0.5",
522
+ "aria-label": "Editor mode"
523
+ }, ao = {
524
+ key: 0,
525
+ class: "flex items-center gap-1",
526
+ "aria-label": "Preview viewport"
527
+ }, so = { class: "ml-1 text-[11px] tabular-nums text-muted-foreground" }, io = {
528
+ key: 1,
529
+ class: "flex items-center gap-2"
530
+ }, ro = {
531
+ key: 0,
532
+ class: "flex flex-wrap gap-1 border-b bg-card/50 px-3 py-2",
533
+ "aria-label": "Add email block"
534
+ }, uo = {
535
+ key: 1,
536
+ class: "border-b bg-card px-4 py-2"
537
+ }, mo = { class: "flex items-center justify-between gap-3" }, co = { class: "truncate text-xs" }, po = {
538
+ key: 0,
539
+ class: "space-y-3 py-3"
540
+ }, vo = { class: "flex items-center gap-2 text-xs" }, fo = { class: "grid max-h-48 grid-cols-1 gap-2 overflow-y-auto sm:grid-cols-2" }, bo = { class: "mb-1 block font-mono text-muted-foreground" }, xo = {
541
+ key: 2,
542
+ class: "flex items-center justify-between gap-2 border-b bg-destructive/5 px-4 py-3 text-sm text-destructive",
543
+ role: "alert"
544
+ }, go = {
545
+ key: 3,
546
+ class: "max-h-28 overflow-auto border-b bg-amber-500/10 px-4 py-2 text-xs",
547
+ role: "alert"
548
+ }, yo = { class: "relative min-h-0 flex-1 overflow-auto bg-muted/40" }, ko = {
549
+ key: 0,
550
+ class: "sticky top-2 z-10 mx-auto flex w-fit items-center gap-2 rounded-full border bg-card px-3 py-1.5 text-xs shadow-sm",
551
+ role: "status"
552
+ }, ho = ["src"], wo = {
553
+ key: 1,
554
+ class: "rounded-lg border-2 border-dashed p-8 text-center"
555
+ }, So = ["data-email-block-id"], Co = {
556
+ key: 0,
557
+ "aria-hidden": "true",
558
+ class: "pointer-events-none absolute -top-1 inset-x-0 z-20 border-t-2 border-primary"
559
+ }, $o = {
560
+ key: 2,
561
+ class: "relative h-8 text-center text-xs leading-8 text-muted-foreground"
562
+ }, Bo = {
563
+ key: 0,
564
+ "aria-hidden": "true",
565
+ class: "pointer-events-none absolute inset-x-0 top-0 border-t-2 border-primary"
566
+ }, To = {
567
+ key: 1,
568
+ class: "mt-3"
569
+ }, Vo = {
570
+ key: 2,
571
+ class: "h-full min-h-[500px] p-3 sm:p-5"
572
+ }, Uo = ["srcdoc"], Do = {
573
+ key: 3,
574
+ class: "h-full p-4"
575
+ }, zo = ["value"], Io = { class: "flex flex-wrap items-center justify-between gap-2 border-t bg-card px-4 py-2 text-[11px] text-muted-foreground" }, Mo = {
576
+ key: 0,
577
+ class: "relative"
578
+ }, Lo = { class: "flex cursor-pointer list-none items-center gap-1 text-amber-600" }, Ao = { class: "absolute bottom-6 right-0 z-20 w-72 space-y-2 rounded-md border bg-card p-3 text-xs shadow-lg" }, Ro = {
579
+ key: 1,
580
+ class: "flex items-center gap-1"
581
+ }, jo = {
582
+ key: 1,
583
+ class: "flex flex-1 flex-col items-center justify-center p-8 text-center"
584
+ }, Eo = /* @__PURE__ */ me({
585
+ __name: "EmailCanvas",
586
+ props: {
587
+ template: {},
588
+ selectedBlockId: {},
589
+ templateStyles: {},
590
+ saving: { type: Boolean },
591
+ hasUnsavedChanges: { type: Boolean },
592
+ canUndo: { type: Boolean },
593
+ canRedo: { type: Boolean },
594
+ dirtyCount: {},
595
+ canEdit: { type: Boolean },
596
+ canCreate: { type: Boolean },
597
+ canDelete: { type: Boolean }
598
+ },
599
+ emits: ["select-block", "add-block", "move-block", "reorder-block", "duplicate-block", "delete-block", "save", "undo", "redo", "duplicate-template", "create", "delete-template"],
600
+ setup(t, { emit: A }) {
601
+ const i = t, f = A, m = nt(), B = (z) => m.post("/render", { body: z }), g = D(i.canEdit ? "edit" : "preview"), I = D("desktop"), Y = D("mjml"), V = j(() => I.value === "mobile" ? 375 : I.value === "tablet" ? 768 : Math.max(680, i.templateStyles.contentWidth + 80)), v = D(null), b = D(!1), C = D(""), H = D(!1), k = D(!1), h = D(!0), e = ht({
602
+ agency_name: "Your agency",
603
+ user_name: "Alex Morgan",
604
+ user_email: "alex@example.com",
605
+ project_name: "Your project",
606
+ year: String((/* @__PURE__ */ new Date()).getFullYear()),
607
+ inviter_name: "Jamie",
608
+ support_email: "support@example.com",
609
+ dashboard_url: "https://example.com/dashboard",
610
+ invite_url: "https://example.com/invitation",
611
+ reset_url: "https://example.com/reset",
612
+ unsubscribe_url: "https://example.com/unsubscribe",
613
+ expires_at: new Date(Date.now() + 7 * 864e5).toLocaleDateString()
614
+ }), x = j(() => kl(
615
+ i.template?.subject,
616
+ i.template?.preheader,
617
+ i.template?.blocks,
618
+ i.templateStyles,
619
+ i.templateStyles.showUnsubscribe ? "{{unsubscribe_url}}" : ""
620
+ )), M = j(() => x.value.filter((z) => !e[z])), W = j(() => {
621
+ const z = [];
622
+ for (const [r, L] of (i.template?.blocks || []).entries())
623
+ L.type === "image" && !L.content.src && z.push(`Block ${r + 1}: add an image URL.`), L.type === "image" && L.content.src && !L.content.alt && z.push(`Block ${r + 1}: add alternative text for accessibility.`), L.type === "button" && (!L.content.url || L.content.url === "#") && z.push(`Block ${r + 1}: add a destination for the button.`);
624
+ return i.template?.subject.trim() || z.unshift("Add an email subject in Settings."), z;
625
+ }), R = j(() => Y.value === "mjml" ? v.value?.mjml || "" : v.value?.html || ""), ee = j(() => v.value ? Math.ceil(new TextEncoder().encode(v.value.html).length / 1024) : 0), oe = j(() => v.value?.subject || i.template?.subject);
626
+ let se, J = 0;
627
+ async function F() {
628
+ const z = ++J;
629
+ if (i.template) {
630
+ b.value = !0, C.value = "";
631
+ try {
632
+ const r = await B({
633
+ blocks: i.template.blocks,
634
+ subject: i.template.subject,
635
+ preheader: i.template.preheader,
636
+ styles: i.templateStyles,
637
+ variables: g.value === "source" || !h.value ? {} : { ...e },
638
+ preserveVariables: g.value === "source" || !h.value
639
+ });
640
+ z === J && (v.value = r);
641
+ } catch (r) {
642
+ z === J && (C.value = r?.data?.statusMessage || (r instanceof Error ? r.message : "Could not compile this email."), v.value = null);
643
+ } finally {
644
+ z === J && (b.value = !1);
645
+ }
646
+ }
647
+ }
648
+ he(() => [i.template, i.templateStyles, e, h.value, g.value], () => {
649
+ if (clearTimeout(se), J++, g.value === "edit") {
650
+ b.value = !1;
651
+ return;
652
+ }
653
+ b.value = !0, se = setTimeout(F, 450);
654
+ }, { deep: !0, immediate: !0 }), he(() => i.template?.id, () => {
655
+ v.value = null, C.value = "", k.value = !1;
656
+ }), ot(() => {
657
+ clearTimeout(se), J++;
658
+ });
659
+ async function be(z) {
660
+ if (!i.template || H.value) return;
661
+ H.value = !0;
662
+ const r = i.template.name;
663
+ try {
664
+ const L = await B({ blocks: i.template.blocks, subject: i.template.subject, preheader: i.template.preheader, styles: i.templateStyles, preserveVariables: !0 }), ve = new Blob([L[z]], { type: z === "html" ? "text/html;charset=utf-8" : "text/plain;charset=utf-8" }), de = URL.createObjectURL(ve), ue = document.createElement("a");
665
+ ue.href = de, ue.download = `${r.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "email"}.${z}`, document.body.appendChild(ue), ue.click(), ue.remove(), setTimeout(() => URL.revokeObjectURL(de), 1e3), ae.success(`${z.toUpperCase()} exported with template variables preserved`);
666
+ } catch (L) {
667
+ ae.error(L?.data?.statusMessage || (L instanceof Error ? L.message : "Export failed"));
668
+ } finally {
669
+ H.value = !1;
670
+ }
671
+ }
672
+ async function ce() {
673
+ try {
674
+ await navigator.clipboard.writeText(R.value), ae.success("Source copied");
675
+ } catch {
676
+ ae.error("Could not copy. Use Download instead.");
677
+ }
678
+ }
679
+ const X = D(null), a = D(null), q = D(!1), Q = D(null);
680
+ function we() {
681
+ X.value = null, a.value = null, q.value = !1;
682
+ }
683
+ function De(z) {
684
+ const r = Array.from(Q.value?.querySelectorAll("[data-email-block-id]") ?? []);
685
+ for (const L of r) {
686
+ const ve = L.getBoundingClientRect();
687
+ if (z < ve.top + ve.height / 2) return L.dataset.emailBlockId ?? null;
688
+ }
689
+ return null;
690
+ }
691
+ function re(z) {
692
+ !X.value || !i.canEdit || (z.preventDefault(), z.dataTransfer && (z.dataTransfer.dropEffect = "move"), a.value = De(z.clientY), q.value = !0);
693
+ }
694
+ function Se(z) {
695
+ !X.value || !i.canEdit || (z.preventDefault(), f("reorder-block", X.value, De(z.clientY)), we());
696
+ }
697
+ function pe(z) {
698
+ (!(z.relatedTarget instanceof Node) || !z.currentTarget.contains(z.relatedTarget)) && (q.value = !1);
699
+ }
700
+ he(() => [i.template?.id, g.value], we);
701
+ const Ce = [
702
+ { type: "header", label: "Heading", icon: rt },
703
+ { type: "text", label: "Text", icon: Pe },
704
+ { type: "button", label: "Button", icon: dt },
705
+ { type: "image", label: "Image", icon: We },
706
+ { type: "columns", label: "Columns", icon: ut },
707
+ { type: "divider", label: "Divider", icon: mt },
708
+ { type: "spacer", label: "Spacer", icon: Fe }
709
+ ];
710
+ return (z, r) => {
711
+ const L = U("Button"), ve = U("DropdownMenuTrigger"), de = U("DropdownMenuItem"), ue = U("DropdownMenuSeparator"), Ae = U("DropdownMenuContent"), Re = U("DropdownMenu"), ze = U("Input");
712
+ return s(), u("section", Zl, [
713
+ t.template ? (s(), u(P, { key: 0 }, [
714
+ l("header", Xl, [
715
+ l("div", _l, [
716
+ l("h1", eo, $(t.template.name), 1),
717
+ l("p", to, $(t.hasUnsavedChanges ? `Unsaved changes${t.dirtyCount > 1 ? ` in ${t.dirtyCount} templates` : ""}` : "All changes saved"), 1)
718
+ ]),
719
+ l("div", lo, [
720
+ t.canEdit ? (s(), N(L, {
721
+ key: 0,
722
+ variant: "ghost",
723
+ size: "icon",
724
+ class: "size-8",
725
+ disabled: !t.canUndo,
726
+ "aria-label": "Undo",
727
+ title: "Undo (⌘/Ctrl Z)",
728
+ onClick: r[0] || (r[0] = (y) => f("undo"))
729
+ }, {
730
+ default: p(() => [
731
+ o(w(Pt), { class: "size-4" })
732
+ ]),
733
+ _: 1
734
+ }, 8, ["disabled"])) : T("", !0),
735
+ t.canEdit ? (s(), N(L, {
736
+ key: 1,
737
+ variant: "ghost",
738
+ size: "icon",
739
+ class: "size-8",
740
+ disabled: !t.canRedo,
741
+ "aria-label": "Redo",
742
+ title: "Redo (⌘/Ctrl Shift Z)",
743
+ onClick: r[1] || (r[1] = (y) => f("redo"))
744
+ }, {
745
+ default: p(() => [
746
+ o(w(Ft), { class: "size-4" })
747
+ ]),
748
+ _: 1
749
+ }, 8, ["disabled"])) : T("", !0),
750
+ o(Re, null, {
751
+ default: p(() => [
752
+ o(ve, { "as-child": "" }, {
753
+ default: p(() => [
754
+ o(L, {
755
+ variant: "outline",
756
+ size: "sm",
757
+ class: "h-8",
758
+ "aria-label": "Template actions"
759
+ }, {
760
+ default: p(() => [
761
+ o(w(Ot), { class: "size-3.5" }),
762
+ r[17] || (r[17] = l("span", { class: "hidden 2xl:inline" }, "Export", -1))
763
+ ]),
764
+ _: 1
765
+ })
766
+ ]),
767
+ _: 1
768
+ }),
769
+ o(Ae, { align: "end" }, {
770
+ default: p(() => [
771
+ o(de, {
772
+ disabled: H.value,
773
+ onSelect: r[2] || (r[2] = (y) => be("mjml"))
774
+ }, {
775
+ default: p(() => [...r[18] || (r[18] = [
776
+ c("Download MJML", -1)
777
+ ])]),
778
+ _: 1
779
+ }, 8, ["disabled"]),
780
+ o(de, {
781
+ disabled: H.value,
782
+ onSelect: r[3] || (r[3] = (y) => be("html"))
783
+ }, {
784
+ default: p(() => [...r[19] || (r[19] = [
785
+ c("Download HTML", -1)
786
+ ])]),
787
+ _: 1
788
+ }, 8, ["disabled"]),
789
+ o(ue),
790
+ t.canCreate ? (s(), N(de, {
791
+ key: 0,
792
+ onSelect: r[4] || (r[4] = (y) => f("duplicate-template"))
793
+ }, {
794
+ default: p(() => [...r[20] || (r[20] = [
795
+ c("Duplicate template", -1)
796
+ ])]),
797
+ _: 1
798
+ })) : T("", !0),
799
+ t.canDelete ? (s(), N(de, {
800
+ key: 1,
801
+ class: "text-destructive",
802
+ onSelect: r[5] || (r[5] = (y) => f("delete-template"))
803
+ }, {
804
+ default: p(() => [...r[21] || (r[21] = [
805
+ c("Delete template", -1)
806
+ ])]),
807
+ _: 1
808
+ })) : T("", !0)
809
+ ]),
810
+ _: 1
811
+ })
812
+ ]),
813
+ _: 1
814
+ }),
815
+ t.canEdit ? (s(), N(L, {
816
+ key: 2,
817
+ size: "sm",
818
+ class: "h-8",
819
+ disabled: !t.hasUnsavedChanges || t.saving,
820
+ onClick: r[6] || (r[6] = (y) => f("save"))
821
+ }, {
822
+ default: p(() => [
823
+ t.saving ? (s(), N(w(Ne), {
824
+ key: 0,
825
+ class: "size-3.5 animate-spin"
826
+ })) : (s(), N(w(He), {
827
+ key: 1,
828
+ class: "size-3.5"
829
+ })),
830
+ c($(t.saving ? "Saving…" : "Save changes"), 1)
831
+ ]),
832
+ _: 1
833
+ }, 8, ["disabled"])) : T("", !0)
834
+ ])
835
+ ]),
836
+ l("div", oo, [
837
+ l("div", no, [
838
+ (s(!0), u(P, null, te([{ value: "edit", label: "Build", icon: w(at) }, { value: "preview", label: "Preview", icon: w(Wt) }, { value: "source", label: "Source", icon: w(it) }], (y) => G((s(), N(L, {
839
+ key: y.value,
840
+ variant: g.value === y.value ? "secondary" : "ghost",
841
+ size: "sm",
842
+ class: "h-7 px-2.5 text-xs",
843
+ "aria-pressed": g.value === y.value,
844
+ onClick: (Z) => g.value = y.value
845
+ }, {
846
+ default: p(() => [
847
+ (s(), N(fe(y.icon), { class: "size-3.5" })),
848
+ c($(y.label), 1)
849
+ ]),
850
+ _: 2
851
+ }, 1032, ["variant", "aria-pressed", "onClick"])), [
852
+ [wt, y.value !== "edit" || t.canEdit]
853
+ ])), 128))
854
+ ]),
855
+ g.value !== "source" ? (s(), u("div", ao, [
856
+ (s(!0), u(P, null, te([{ value: "desktop", label: "Desktop", icon: w(Jt) }, { value: "tablet", label: "Tablet", icon: w(qt) }, { value: "mobile", label: "Mobile", icon: w(Yt) }], (y) => (s(), N(L, {
857
+ key: y.value,
858
+ variant: I.value === y.value ? "secondary" : "ghost",
859
+ size: "icon",
860
+ class: "size-7",
861
+ "aria-label": y.label,
862
+ title: y.label,
863
+ "aria-pressed": I.value === y.value,
864
+ onClick: (Z) => I.value = y.value
865
+ }, {
866
+ default: p(() => [
867
+ (s(), N(fe(y.icon), { class: "size-3.5" }))
868
+ ]),
869
+ _: 2
870
+ }, 1032, ["variant", "aria-label", "title", "aria-pressed", "onClick"]))), 128)),
871
+ l("span", so, $(V.value) + "px", 1)
872
+ ])) : (s(), u("div", io, [
873
+ G(l("select", {
874
+ "onUpdate:modelValue": r[7] || (r[7] = (y) => Y.value = y),
875
+ "aria-label": "Source format",
876
+ class: "h-7 rounded border bg-background px-2 text-xs"
877
+ }, [...r[22] || (r[22] = [
878
+ l("option", { value: "mjml" }, "MJML", -1),
879
+ l("option", { value: "html" }, "HTML", -1)
880
+ ])], 512), [
881
+ [Me, Y.value]
882
+ ]),
883
+ o(L, {
884
+ variant: "ghost",
885
+ size: "sm",
886
+ class: "h-7 text-xs",
887
+ disabled: !R.value || b.value,
888
+ onClick: ce
889
+ }, {
890
+ default: p(() => [
891
+ o(w(Oe), { class: "size-3.5" }),
892
+ r[23] || (r[23] = c(" Copy", -1))
893
+ ]),
894
+ _: 1
895
+ }, 8, ["disabled"])
896
+ ]))
897
+ ]),
898
+ g.value === "edit" ? (s(), u("div", ro, [
899
+ (s(), u(P, null, te(Ce, (y) => o(L, {
900
+ key: y.type,
901
+ variant: "ghost",
902
+ size: "sm",
903
+ class: "h-8 gap-1.5 px-2 text-xs",
904
+ title: `Add ${y.label.toLowerCase()}${t.selectedBlockId ? " after selection" : ""}`,
905
+ onClick: (Z) => f("add-block", y.type)
906
+ }, {
907
+ default: p(() => [
908
+ (s(), N(fe(y.icon), { class: "size-3.5" })),
909
+ c($(y.label), 1)
910
+ ]),
911
+ _: 2
912
+ }, 1032, ["title", "onClick"])), 64))
913
+ ])) : g.value === "preview" ? (s(), u("div", uo, [
914
+ l("div", mo, [
915
+ l("p", co, [
916
+ r[24] || (r[24] = l("span", { class: "text-muted-foreground" }, "Subject: ", -1)),
917
+ c($(oe.value), 1)
918
+ ]),
919
+ o(L, {
920
+ variant: "ghost",
921
+ size: "sm",
922
+ class: "h-7 shrink-0 text-xs",
923
+ onClick: r[8] || (r[8] = (y) => k.value = !k.value)
924
+ }, {
925
+ default: p(() => [
926
+ c("Sample data" + $(M.value.length ? ` (${M.value.length} missing)` : ""), 1)
927
+ ]),
928
+ _: 1
929
+ })
930
+ ]),
931
+ k.value ? (s(), u("div", po, [
932
+ l("label", vo, [
933
+ G(l("input", {
934
+ "onUpdate:modelValue": r[9] || (r[9] = (y) => h.value = y),
935
+ type: "checkbox"
936
+ }, null, 512), [
937
+ [St, h.value]
938
+ ]),
939
+ r[25] || (r[25] = c(" Preview with sample values", -1))
940
+ ]),
941
+ r[26] || (r[26] = l("p", { class: "text-xs text-muted-foreground" }, "Preview only. Saved HTML and downloads preserve your template variables.", -1)),
942
+ l("div", fo, [
943
+ (s(!0), u(P, null, te(x.value, (y) => (s(), u("label", {
944
+ key: y,
945
+ class: "text-xs"
946
+ }, [
947
+ l("span", bo, $(y), 1),
948
+ o(ze, {
949
+ modelValue: e[y],
950
+ "onUpdate:modelValue": (Z) => e[y] = Z,
951
+ disabled: !h.value,
952
+ placeholder: `Sample ${y.replaceAll("_", " ")}`,
953
+ class: "h-8 text-xs"
954
+ }, null, 8, ["modelValue", "onUpdate:modelValue", "disabled", "placeholder"])
955
+ ]))), 128))
956
+ ])
957
+ ])) : T("", !0)
958
+ ])) : T("", !0),
959
+ C.value && g.value !== "edit" ? (s(), u("div", xo, [
960
+ l("span", null, $(C.value), 1),
961
+ o(L, {
962
+ variant: "outline",
963
+ size: "sm",
964
+ onClick: F
965
+ }, {
966
+ default: p(() => [...r[27] || (r[27] = [
967
+ c("Retry", -1)
968
+ ])]),
969
+ _: 1
970
+ })
971
+ ])) : T("", !0),
972
+ g.value !== "edit" && v.value?.errors?.length ? (s(), u("div", go, [
973
+ (s(!0), u(P, null, te(v.value.errors, (y, Z) => (s(), u("p", { key: Z }, $(y.line ? `Line ${y.line}: ` : "") + $(y.message), 1))), 128))
974
+ ])) : T("", !0),
975
+ l("div", yo, [
976
+ b.value && g.value !== "edit" ? (s(), u("div", ko, [
977
+ o(w(Ne), { class: "size-3 animate-spin" }),
978
+ r[28] || (r[28] = c(" Compiling email…", -1))
979
+ ])) : T("", !0),
980
+ g.value === "edit" ? (s(), u("div", {
981
+ key: 1,
982
+ class: "min-h-full p-4 sm:p-6",
983
+ style: K({ backgroundColor: t.templateStyles.bodyBg }),
984
+ onDragenter: re,
985
+ onDragover: re,
986
+ onDrop: Se,
987
+ onDragleave: pe
988
+ }, [
989
+ l("div", {
990
+ class: "mx-auto w-full overflow-visible rounded-lg shadow-sm",
991
+ style: K({ maxWidth: Math.min(V.value, t.templateStyles.contentWidth) + "px", backgroundColor: t.templateStyles.contentBg, fontFamily: t.templateStyles.fontFamily, borderRadius: t.templateStyles.borderRadius + "px" })
992
+ }, [
993
+ l("div", {
994
+ ref_key: "blockList",
995
+ ref: Q,
996
+ style: K({ padding: Math.min(t.templateStyles.contentPadding, I.value === "mobile" ? 20 : 64) + "px" })
997
+ }, [
998
+ t.templateStyles.logoUrl ? (s(), u("img", {
999
+ key: 0,
1000
+ src: t.templateStyles.logoUrl,
1001
+ alt: "Agency logo",
1002
+ class: "mx-auto mb-6 max-h-12 max-w-full"
1003
+ }, null, 8, ho)) : T("", !0),
1004
+ t.template.blocks.length ? T("", !0) : (s(), u("div", wo, [
1005
+ o(w(Le), { class: "mx-auto mb-3 size-5 text-muted-foreground" }),
1006
+ r[30] || (r[30] = l("p", { class: "text-sm text-muted-foreground" }, "Add your first block using the toolbar.", -1)),
1007
+ o(L, {
1008
+ variant: "outline",
1009
+ size: "sm",
1010
+ class: "mt-3",
1011
+ onClick: r[10] || (r[10] = (y) => f("add-block", "text"))
1012
+ }, {
1013
+ default: p(() => [...r[29] || (r[29] = [
1014
+ c("Add text", -1)
1015
+ ])]),
1016
+ _: 1
1017
+ })
1018
+ ])),
1019
+ (s(!0), u(P, null, te(t.template.blocks, (y, Z) => (s(), u("div", {
1020
+ key: y.id,
1021
+ "data-email-block-id": y.id,
1022
+ class: ie(["relative", { "opacity-40": X.value === y.id }])
1023
+ }, [
1024
+ X.value && q.value && a.value === y.id ? (s(), u("div", Co)) : T("", !0),
1025
+ o(Ql, {
1026
+ block: y,
1027
+ index: Z,
1028
+ "total-blocks": t.template.blocks.length,
1029
+ "selected-block-id": t.selectedBlockId,
1030
+ "template-styles": t.templateStyles,
1031
+ onSelect: r[11] || (r[11] = (_) => f("select-block", _)),
1032
+ onMove: r[12] || (r[12] = (_, xe) => f("move-block", _, xe)),
1033
+ onDuplicate: r[13] || (r[13] = (_) => f("duplicate-block", _)),
1034
+ onDelete: r[14] || (r[14] = (_) => f("delete-block", _)),
1035
+ onDragStart: r[15] || (r[15] = (_) => X.value = _),
1036
+ onDragEnd: we
1037
+ }, null, 8, ["block", "index", "total-blocks", "selected-block-id", "template-styles"])
1038
+ ], 10, So))), 128)),
1039
+ X.value ? (s(), u("div", $o, [
1040
+ q.value && a.value === null ? (s(), u("div", Bo)) : T("", !0),
1041
+ r[31] || (r[31] = c("Drop here to move to end", -1))
1042
+ ])) : T("", !0)
1043
+ ], 4),
1044
+ t.templateStyles.footerText || t.templateStyles.showUnsubscribe || t.templateStyles.showSocialLinks ? (s(), u("div", {
1045
+ key: 0,
1046
+ class: "rounded-b-lg px-6 py-6 text-center text-xs",
1047
+ style: K({ backgroundColor: t.templateStyles.footerBg, color: t.templateStyles.footerTextColor })
1048
+ }, [
1049
+ l("p", null, $(t.templateStyles.footerText), 1),
1050
+ t.templateStyles.showUnsubscribe ? (s(), u("p", {
1051
+ key: 0,
1052
+ class: "mt-3 underline",
1053
+ style: K({ color: t.templateStyles.linkColor })
1054
+ }, "Unsubscribe", 4)) : T("", !0),
1055
+ t.templateStyles.showSocialLinks ? (s(), u("p", To, "Social links appear when their URL variables are supplied.")) : T("", !0)
1056
+ ], 4)) : T("", !0)
1057
+ ], 4)
1058
+ ], 36)) : g.value === "preview" && v.value ? (s(), u("div", Vo, [
1059
+ l("iframe", {
1060
+ srcdoc: v.value.html,
1061
+ title: "Compiled email preview",
1062
+ sandbox: "",
1063
+ referrerpolicy: "no-referrer",
1064
+ class: "mx-auto block h-full min-h-[480px] max-w-none border bg-white shadow-sm",
1065
+ style: K({ width: V.value + "px" })
1066
+ }, null, 12, Uo)
1067
+ ])) : g.value === "source" ? (s(), u("div", Do, [
1068
+ r[32] || (r[32] = l("p", { class: "mb-3 text-xs text-muted-foreground" }, "Generated from your blocks. Downloads preserve template variables.", -1)),
1069
+ l("textarea", {
1070
+ value: R.value,
1071
+ readonly: "",
1072
+ "aria-label": "Generated email source",
1073
+ spellcheck: "false",
1074
+ class: "h-[calc(100%-2rem)] min-h-[350px] w-full resize-none rounded-md border bg-card p-4 font-mono text-xs leading-5 outline-none focus:ring-2 focus:ring-ring"
1075
+ }, null, 8, zo)
1076
+ ])) : T("", !0)
1077
+ ]),
1078
+ l("footer", Io, [
1079
+ l("span", null, $(t.template.blocks.length) + " blocks · " + $(g.value === "edit" ? "Select a block to edit · Drag to reorder" : `MJML preview${ee.value ? ` · ${ee.value} KB HTML` : ""}`), 1),
1080
+ W.value.length ? (s(), u("details", Mo, [
1081
+ l("summary", Lo, [
1082
+ o(w(Kt), { class: "size-3" }),
1083
+ c($(W.value.length) + " " + $(W.value.length === 1 ? "check" : "checks") + " to review", 1)
1084
+ ]),
1085
+ l("ul", Ao, [
1086
+ (s(!0), u(P, null, te(W.value, (y) => (s(), u("li", { key: y }, $(y), 1))), 128))
1087
+ ])
1088
+ ])) : g.value !== "edit" && v.value && !b.value && !v.value.errors?.length ? (s(), u("span", Ro, [
1089
+ o(w(He), { class: "size-3" }),
1090
+ r[33] || (r[33] = c("Compiled successfully", -1))
1091
+ ])) : T("", !0)
1092
+ ])
1093
+ ], 64)) : (s(), u("div", jo, [
1094
+ o(w(Ee), { class: "mb-4 size-10 text-muted-foreground/40" }),
1095
+ r[35] || (r[35] = l("h1", { class: "text-lg font-semibold" }, "Build your next email", -1)),
1096
+ r[36] || (r[36] = l("p", { class: "mt-2 max-w-xs text-sm text-muted-foreground" }, "Choose a template or create one with responsive blocks and a live email preview.", -1)),
1097
+ t.canCreate ? (s(), N(L, {
1098
+ key: 0,
1099
+ class: "mt-5",
1100
+ onClick: r[16] || (r[16] = (y) => f("create"))
1101
+ }, {
1102
+ default: p(() => [
1103
+ o(w(Le), { class: "size-4" }),
1104
+ r[34] || (r[34] = c("Create template", -1))
1105
+ ]),
1106
+ _: 1
1107
+ })) : T("", !0)
1108
+ ]))
1109
+ ]);
1110
+ };
1111
+ }
1112
+ }), No = { class: "overflow-hidden rounded-md border bg-background focus-within:ring-2 focus-within:ring-ring/30" }, Ho = {
1113
+ class: "flex flex-wrap items-center gap-0.5 border-b bg-muted/30 p-1",
1114
+ role: "toolbar",
1115
+ "aria-label": "Text formatting"
1116
+ }, Po = ["title", "aria-label", "aria-pressed", "onClick"], Fo = ["aria-expanded"], Oo = ["aria-pressed", "title"], Wo = {
1117
+ key: 0,
1118
+ class: "space-y-2 border-b p-2"
1119
+ }, Jo = { class: "block text-xs font-medium" }, qo = {
1120
+ key: 0,
1121
+ role: "alert",
1122
+ class: "text-xs text-destructive"
1123
+ }, Yo = { class: "flex justify-end gap-1" }, Ko = ["value", "aria-label"], Go = /* @__PURE__ */ me({
1124
+ __name: "RichTextEditor",
1125
+ props: {
1126
+ modelValue: {},
1127
+ label: {}
1128
+ },
1129
+ emits: ["update:modelValue"],
1130
+ setup(t, { emit: A }) {
1131
+ const i = t, f = A, m = D(!1), B = D(!1), g = D(""), I = D(""), V = {
1132
+ default: null,
1133
+ parseHTML: (e) => Object.entries(ft(e)).map(([x, M]) => `${x.replace(/[A-Z]/g, (W) => `-${W.toLowerCase()}`)}: ${M}`).join("; ") || null,
1134
+ renderHTML: (e) => e.emailStyle ? { style: e.emailStyle } : {}
1135
+ }, v = pl.create({
1136
+ name: "emailTextStyles",
1137
+ addGlobalAttributes() {
1138
+ return [{
1139
+ types: ["paragraph", "heading", "blockquote", "listItem"],
1140
+ attributes: {
1141
+ emailStyle: V
1142
+ }
1143
+ }];
1144
+ }
1145
+ }), b = vl.create({
1146
+ name: "emailInlineStyle",
1147
+ addAttributes: () => ({ emailStyle: V }),
1148
+ parseHTML: () => [{ tag: "span[style]" }],
1149
+ renderHTML: ({ HTMLAttributes: e }) => ["span", e, 0]
1150
+ }), C = fl({
1151
+ content: i.modelValue || "",
1152
+ extensions: [
1153
+ bl.configure({
1154
+ heading: { levels: [1, 2, 3] },
1155
+ code: !1,
1156
+ codeBlock: !1,
1157
+ horizontalRule: !1,
1158
+ link: { openOnClick: !1, defaultProtocol: "https", isAllowedUri: tt }
1159
+ }),
1160
+ v,
1161
+ b
1162
+ ],
1163
+ editorProps: {
1164
+ attributes: {
1165
+ class: "email-text-editor min-h-36 px-3 py-2 text-sm focus:outline-none",
1166
+ "aria-label": i.label || "Email text content",
1167
+ role: "textbox",
1168
+ "aria-multiline": "true"
1169
+ }
1170
+ },
1171
+ onUpdate: ({ editor: e }) => f("update:modelValue", e.getHTML())
1172
+ });
1173
+ he(() => i.modelValue, (e) => {
1174
+ C.value && C.value.getHTML() !== e && C.value.commands.setContent(e || "", { emitUpdate: !1 });
1175
+ });
1176
+ const H = j(() => [
1177
+ { label: "Bold", icon: Gt, active: C.value?.isActive("bold"), action: () => C.value?.chain().focus().toggleBold().run() },
1178
+ { label: "Italic", icon: Qt, active: C.value?.isActive("italic"), action: () => C.value?.chain().focus().toggleItalic().run() },
1179
+ { label: "Underline", icon: Zt, active: C.value?.isActive("underline"), action: () => C.value?.chain().focus().toggleUnderline().run() },
1180
+ { label: "Strikethrough", icon: Xt, active: C.value?.isActive("strike"), action: () => C.value?.chain().focus().toggleStrike().run() },
1181
+ { label: "Bullet list", icon: _t, active: C.value?.isActive("bulletList"), action: () => C.value?.chain().focus().toggleBulletList().run() },
1182
+ { label: "Numbered list", icon: el, active: C.value?.isActive("orderedList"), action: () => C.value?.chain().focus().toggleOrderedList().run() }
1183
+ ]);
1184
+ function k() {
1185
+ g.value = C.value?.getAttributes("link").href || "", I.value = "", B.value = !B.value;
1186
+ }
1187
+ function h() {
1188
+ const e = g.value.trim();
1189
+ if (e && !tt(e)) {
1190
+ I.value = "Use https://, mailto:, tel:, or a template variable.";
1191
+ return;
1192
+ }
1193
+ e ? C.value?.chain().focus().extendMarkRange("link").setLink({ href: e }).run() : C.value?.chain().focus().extendMarkRange("link").unsetLink().run(), B.value = !1;
1194
+ }
1195
+ return (e, x) => {
1196
+ const M = U("Input"), W = U("Button");
1197
+ return s(), u("div", No, [
1198
+ l("div", Ho, [
1199
+ m.value ? T("", !0) : (s(), u(P, { key: 0 }, [
1200
+ (s(!0), u(P, null, te(H.value, (R) => (s(), u("button", {
1201
+ key: R.label,
1202
+ type: "button",
1203
+ title: R.label,
1204
+ "aria-label": R.label,
1205
+ "aria-pressed": !!R.active,
1206
+ class: ie(["rounded p-1.5 hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring", R.active ? "bg-accent text-foreground" : "text-muted-foreground"]),
1207
+ onClick: R.action
1208
+ }, [
1209
+ (s(), N(fe(R.icon), { class: "size-3.5" }))
1210
+ ], 10, Po))), 128)),
1211
+ l("button", {
1212
+ type: "button",
1213
+ title: "Add or edit link",
1214
+ "aria-label": "Add or edit link",
1215
+ "aria-expanded": B.value,
1216
+ class: "rounded p-1.5 hover:bg-accent",
1217
+ onClick: k
1218
+ }, [
1219
+ o(w(tl), { class: "size-3.5" })
1220
+ ], 8, Fo),
1221
+ w(C)?.isActive("link") ? (s(), u("button", {
1222
+ key: 0,
1223
+ type: "button",
1224
+ title: "Remove link",
1225
+ "aria-label": "Remove link",
1226
+ class: "rounded p-1.5 hover:bg-accent",
1227
+ onClick: x[0] || (x[0] = (R) => w(C)?.chain().focus().extendMarkRange("link").unsetLink().run())
1228
+ }, [
1229
+ o(w(ll), { class: "size-3.5" })
1230
+ ])) : T("", !0),
1231
+ l("button", {
1232
+ type: "button",
1233
+ title: "Clear formatting",
1234
+ "aria-label": "Clear formatting",
1235
+ class: "rounded p-1.5 hover:bg-accent",
1236
+ onClick: x[1] || (x[1] = (R) => w(C)?.chain().focus().unsetAllMarks().clearNodes().run())
1237
+ }, [
1238
+ o(w(ol), { class: "size-3.5" })
1239
+ ])
1240
+ ], 64)),
1241
+ l("button", {
1242
+ type: "button",
1243
+ "aria-pressed": m.value,
1244
+ class: "ml-auto inline-flex items-center gap-1 rounded px-1.5 py-1 text-[11px] hover:bg-accent",
1245
+ title: m.value ? "Switch to visual editor" : "Edit HTML source",
1246
+ onClick: x[2] || (x[2] = (R) => {
1247
+ m.value = !m.value, B.value = !1;
1248
+ })
1249
+ }, [
1250
+ o(w(it), { class: "size-3.5" }),
1251
+ c($(m.value ? "Visual" : "HTML"), 1)
1252
+ ], 8, Oo)
1253
+ ]),
1254
+ B.value && !m.value ? (s(), u("div", Wo, [
1255
+ l("label", Jo, [
1256
+ x[7] || (x[7] = c("Link URL ", -1)),
1257
+ o(M, {
1258
+ modelValue: g.value,
1259
+ "onUpdate:modelValue": x[3] || (x[3] = (R) => g.value = R),
1260
+ class: "mt-1 h-8 text-xs",
1261
+ placeholder: "https://example.com",
1262
+ onKeydown: [
1263
+ _e(ye(h, ["prevent"]), ["enter"]),
1264
+ x[4] || (x[4] = _e(ye((R) => B.value = !1, ["prevent"]), ["esc"]))
1265
+ ]
1266
+ }, null, 8, ["modelValue", "onKeydown"])
1267
+ ]),
1268
+ I.value ? (s(), u("p", qo, $(I.value), 1)) : T("", !0),
1269
+ l("div", Yo, [
1270
+ o(W, {
1271
+ type: "button",
1272
+ size: "sm",
1273
+ variant: "ghost",
1274
+ class: "h-7 text-xs",
1275
+ onClick: x[5] || (x[5] = (R) => B.value = !1)
1276
+ }, {
1277
+ default: p(() => [...x[8] || (x[8] = [
1278
+ c("Cancel", -1)
1279
+ ])]),
1280
+ _: 1
1281
+ }),
1282
+ o(W, {
1283
+ type: "button",
1284
+ size: "sm",
1285
+ class: "h-7 text-xs",
1286
+ onClick: h
1287
+ }, {
1288
+ default: p(() => [...x[9] || (x[9] = [
1289
+ c("Apply link", -1)
1290
+ ])]),
1291
+ _: 1
1292
+ })
1293
+ ])
1294
+ ])) : T("", !0),
1295
+ m.value ? (s(), u("textarea", {
1296
+ key: 1,
1297
+ value: t.modelValue,
1298
+ "aria-label": `${t.label || "Email text"} HTML source`,
1299
+ rows: "8",
1300
+ class: "block min-h-36 w-full resize-y bg-transparent p-3 font-mono text-xs outline-none",
1301
+ spellcheck: "false",
1302
+ onInput: x[6] || (x[6] = (R) => f("update:modelValue", R.target.value))
1303
+ }, null, 40, Ko)) : (s(), N(w(xl), {
1304
+ key: 2,
1305
+ editor: w(C)
1306
+ }, null, 8, ["editor"]))
1307
+ ]);
1308
+ };
1309
+ }
1310
+ }), Qo = /* @__PURE__ */ ct(Go, [["__scopeId", "data-v-accbd7a8"]]), Zo = { class: "p-4 space-y-6" }, Xo = { class: "flex items-center justify-between" }, _o = { class: "flex items-center gap-2" }, en = { class: "text-sm font-semibold" }, tn = { class: "block text-xs font-medium text-muted-foreground" }, ln = {
1311
+ key: 1,
1312
+ class: "space-y-1.5"
1313
+ }, on = { class: "block text-xs font-medium text-muted-foreground" }, nn = { class: "block text-xs font-medium text-muted-foreground" }, an = { class: "block text-xs font-medium text-muted-foreground" }, sn = { class: "block text-xs font-medium text-muted-foreground" }, rn = { class: "block text-xs font-medium text-muted-foreground" }, dn = { class: "block text-xs font-medium text-muted-foreground" }, un = { class: "flex items-center gap-2" }, mn = ["value"], cn = { class: "block text-xs font-medium text-muted-foreground" }, pn = {
1314
+ key: 5,
1315
+ class: "block text-xs font-medium text-muted-foreground"
1316
+ }, vn = { class: "flex items-center justify-between" }, fn = { class: "text-xs font-medium" }, bn = ["aria-label", "title", "disabled", "onClick"], xn = { class: "block text-xs text-muted-foreground" }, gn = { class: "block text-xs text-muted-foreground" }, yn = { class: "mb-1.5 flex items-center justify-between" }, kn = { class: "flex items-center gap-2" }, hn = ["value"], wn = { class: "block text-xs font-medium text-muted-foreground" }, Sn = { key: 8 }, Cn = { class: "border-t pt-4" }, $n = { class: "grid grid-cols-2 gap-3" }, Bn = { class: "text-xs text-muted-foreground" }, Tn = { class: "text-xs text-muted-foreground" }, Vn = { class: "block text-xs font-medium text-muted-foreground" }, Un = { class: "space-y-3" }, Dn = { class: "flex items-center gap-2" }, zn = { class: "flex items-center gap-2" }, In = { class: "flex items-center gap-2" }, Mn = { class: "flex items-center gap-2" }, Ln = { class: "flex items-center gap-2" }, An = { class: "flex items-center gap-2" }, Rn = { class: "flex items-center gap-2" }, jn = { class: "flex items-center gap-2" }, En = { class: "flex items-center gap-2" }, Nn = { class: "space-y-3" }, Hn = { class: "space-y-3" }, Pn = { class: "flex items-center gap-3" }, Fn = { class: "text-xs text-muted-foreground font-mono w-12 text-right" }, On = { class: "flex items-center gap-3" }, Wn = { class: "text-xs text-muted-foreground font-mono w-12 text-right" }, Jn = { class: "flex items-center gap-3" }, qn = { class: "text-xs text-muted-foreground font-mono w-12 text-right" }, Yn = { class: "space-y-3" }, Kn = { class: "flex items-center justify-between" }, Gn = /* @__PURE__ */ me({
1317
+ __name: "DesignPanel",
1318
+ props: {
1319
+ selectedBlock: {},
1320
+ templateStyles: {}
1321
+ },
1322
+ emits: ["deselect-block", "update:hasUnsavedChanges"],
1323
+ setup(t, { emit: A }) {
1324
+ const i = t, f = A, m = () => f("update:hasUnsavedChanges", !0), B = [
1325
+ { value: "left", label: "Align left", icon: Pe },
1326
+ { value: "center", label: "Align center", icon: al },
1327
+ { value: "right", label: "Align right", icon: sl }
1328
+ ], g = j(() => i.selectedBlock?.content.columns || []), I = j(() => i.selectedBlock?.type === "header" ? { h1: 28, h2: 22, h3: 18 }[i.selectedBlock.content.level] || 22 : 15), Y = j(() => ["button", "divider"].includes(i.selectedBlock?.type || "") ? 8 : 0);
1329
+ function V(h, e) {
1330
+ i.selectedBlock && (i.selectedBlock.content[h] = e, m());
1331
+ }
1332
+ function v(h, e, x, M, W = !1) {
1333
+ if (e === "") {
1334
+ i.selectedBlock && delete i.selectedBlock.content[h], m();
1335
+ return;
1336
+ }
1337
+ const R = Number(e);
1338
+ Number.isFinite(R) && V(h, W ? Math.min(M, Math.max(x, R)) : R);
1339
+ }
1340
+ function b() {
1341
+ g.value.length >= 4 || V("columns", [...g.value, { label: "Label", value: "Value" }]);
1342
+ }
1343
+ function C(h) {
1344
+ g.value.length <= 1 || V("columns", g.value.filter((e, x) => x !== h));
1345
+ }
1346
+ const H = (h) => ({
1347
+ header: "Heading",
1348
+ text: "Text Block",
1349
+ button: "Button",
1350
+ image: "Image",
1351
+ divider: "Divider",
1352
+ spacer: "Spacer",
1353
+ columns: "Columns"
1354
+ })[h] ?? h, k = (h) => ({
1355
+ header: rt,
1356
+ text: Pe,
1357
+ button: dt,
1358
+ image: We,
1359
+ divider: mt,
1360
+ spacer: Fe,
1361
+ columns: ut
1362
+ })[h] ?? Fe;
1363
+ return (h, e) => {
1364
+ const x = U("Input"), M = U("SegmentedControlButton"), W = U("SegmentedControl"), R = U("Button"), ee = U("Separator"), oe = U("SelectValue"), se = U("SelectTrigger"), J = U("SelectItem"), F = U("SelectContent"), be = U("Select"), ce = U("Textarea"), X = U("Switch");
1365
+ return s(), u("div", Zo, [
1366
+ t.selectedBlock ? (s(), u(P, { key: 0 }, [
1367
+ (s(), u("section", {
1368
+ key: t.selectedBlock.id,
1369
+ "aria-label": "Selected block design",
1370
+ class: "space-y-4"
1371
+ }, [
1372
+ l("div", Xo, [
1373
+ l("div", _o, [
1374
+ (s(), N(fe(k(t.selectedBlock.type)), { class: "size-4 text-muted-foreground" })),
1375
+ l("h4", en, $(H(t.selectedBlock.type)), 1)
1376
+ ]),
1377
+ l("button", {
1378
+ type: "button",
1379
+ "aria-label": "Deselect block",
1380
+ title: "Deselect block",
1381
+ class: "rounded p-1 hover:bg-accent",
1382
+ onClick: e[0] || (e[0] = (a) => f("deselect-block"))
1383
+ }, [
1384
+ o(w(nl), { class: "size-3.5 text-muted-foreground" })
1385
+ ])
1386
+ ]),
1387
+ t.selectedBlock.type === "header" ? (s(), u(P, { key: 0 }, [
1388
+ l("label", tn, [
1389
+ e[54] || (e[54] = c("Heading text ", -1)),
1390
+ o(x, {
1391
+ modelValue: t.selectedBlock.content.text,
1392
+ "onUpdate:modelValue": [
1393
+ e[1] || (e[1] = (a) => t.selectedBlock.content.text = a),
1394
+ m
1395
+ ],
1396
+ class: "mt-1.5 h-9 text-sm"
1397
+ }, null, 8, ["modelValue"])
1398
+ ]),
1399
+ l("div", null, [
1400
+ e[58] || (e[58] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Heading level", -1)),
1401
+ o(W, {
1402
+ "model-value": t.selectedBlock.content.level || "h2",
1403
+ class: "w-full",
1404
+ "aria-label": "Heading level",
1405
+ "onUpdate:modelValue": e[2] || (e[2] = (a) => V("level", a))
1406
+ }, {
1407
+ default: p(() => [
1408
+ o(M, {
1409
+ value: "h1",
1410
+ class: "text-xs"
1411
+ }, {
1412
+ default: p(() => [...e[55] || (e[55] = [
1413
+ c("H1", -1)
1414
+ ])]),
1415
+ _: 1
1416
+ }),
1417
+ o(M, {
1418
+ value: "h2",
1419
+ class: "text-xs"
1420
+ }, {
1421
+ default: p(() => [...e[56] || (e[56] = [
1422
+ c("H2", -1)
1423
+ ])]),
1424
+ _: 1
1425
+ }),
1426
+ o(M, {
1427
+ value: "h3",
1428
+ class: "text-xs"
1429
+ }, {
1430
+ default: p(() => [...e[57] || (e[57] = [
1431
+ c("H3", -1)
1432
+ ])]),
1433
+ _: 1
1434
+ })
1435
+ ]),
1436
+ _: 1
1437
+ }, 8, ["model-value"])
1438
+ ])
1439
+ ], 64)) : t.selectedBlock.type === "text" ? (s(), u("div", ln, [
1440
+ e[59] || (e[59] = l("p", { class: "text-xs font-medium text-muted-foreground" }, "Content", -1)),
1441
+ (s(), N(Qo, {
1442
+ key: t.selectedBlock.id,
1443
+ "model-value": t.selectedBlock.content.html || "",
1444
+ "onUpdate:modelValue": e[3] || (e[3] = (a) => V("html", a))
1445
+ }, null, 8, ["model-value"])),
1446
+ e[60] || (e[60] = l("p", { class: "text-[11px] leading-relaxed text-muted-foreground" }, [
1447
+ c("Variables work in text and links, e.g. "),
1448
+ l("code", null, "{{user_name}}"),
1449
+ c(".")
1450
+ ], -1))
1451
+ ])) : t.selectedBlock.type === "button" ? (s(), u(P, { key: 2 }, [
1452
+ l("label", on, [
1453
+ e[61] || (e[61] = c("Button text ", -1)),
1454
+ o(x, {
1455
+ modelValue: t.selectedBlock.content.text,
1456
+ "onUpdate:modelValue": [
1457
+ e[4] || (e[4] = (a) => t.selectedBlock.content.text = a),
1458
+ m
1459
+ ],
1460
+ class: "mt-1.5 h-9 text-sm"
1461
+ }, null, 8, ["modelValue"])
1462
+ ]),
1463
+ l("label", nn, [
1464
+ e[62] || (e[62] = c("Link URL ", -1)),
1465
+ o(x, {
1466
+ modelValue: t.selectedBlock.content.url,
1467
+ "onUpdate:modelValue": [
1468
+ e[5] || (e[5] = (a) => t.selectedBlock.content.url = a),
1469
+ m
1470
+ ],
1471
+ class: "mt-1.5 h-9 text-sm",
1472
+ placeholder: "https://… or {{invite_url}}"
1473
+ }, null, 8, ["modelValue"])
1474
+ ]),
1475
+ l("div", null, [
1476
+ e[65] || (e[65] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Style", -1)),
1477
+ o(W, {
1478
+ "model-value": t.selectedBlock.content.variant || "primary",
1479
+ class: "w-full",
1480
+ "aria-label": "Button style",
1481
+ "onUpdate:modelValue": e[6] || (e[6] = (a) => V("variant", a))
1482
+ }, {
1483
+ default: p(() => [
1484
+ o(M, {
1485
+ value: "primary",
1486
+ class: "text-xs"
1487
+ }, {
1488
+ default: p(() => [...e[63] || (e[63] = [
1489
+ c("Filled", -1)
1490
+ ])]),
1491
+ _: 1
1492
+ }),
1493
+ o(M, {
1494
+ value: "secondary",
1495
+ class: "text-xs"
1496
+ }, {
1497
+ default: p(() => [...e[64] || (e[64] = [
1498
+ c("Outline", -1)
1499
+ ])]),
1500
+ _: 1
1501
+ })
1502
+ ]),
1503
+ _: 1
1504
+ }, 8, ["model-value"])
1505
+ ])
1506
+ ], 64)) : t.selectedBlock.type === "image" ? (s(), u(P, { key: 3 }, [
1507
+ l("label", an, [
1508
+ e[66] || (e[66] = c("Image URL ", -1)),
1509
+ o(x, {
1510
+ modelValue: t.selectedBlock.content.src,
1511
+ "onUpdate:modelValue": [
1512
+ e[7] || (e[7] = (a) => t.selectedBlock.content.src = a),
1513
+ m
1514
+ ],
1515
+ class: "mt-1.5 h-9 text-sm",
1516
+ placeholder: "https://…"
1517
+ }, null, 8, ["modelValue"])
1518
+ ]),
1519
+ l("label", sn, [
1520
+ e[67] || (e[67] = c("Alt text ", -1)),
1521
+ o(x, {
1522
+ modelValue: t.selectedBlock.content.alt,
1523
+ "onUpdate:modelValue": [
1524
+ e[8] || (e[8] = (a) => t.selectedBlock.content.alt = a),
1525
+ m
1526
+ ],
1527
+ class: "mt-1.5 h-9 text-sm",
1528
+ placeholder: "Describe the image"
1529
+ }, null, 8, ["modelValue"])
1530
+ ]),
1531
+ l("label", rn, [
1532
+ e[68] || (e[68] = c("Link URL (optional) ", -1)),
1533
+ o(x, {
1534
+ modelValue: t.selectedBlock.content.href,
1535
+ "onUpdate:modelValue": [
1536
+ e[9] || (e[9] = (a) => t.selectedBlock.content.href = a),
1537
+ m
1538
+ ],
1539
+ class: "mt-1.5 h-9 text-sm",
1540
+ placeholder: "https://…"
1541
+ }, null, 8, ["modelValue"])
1542
+ ]),
1543
+ l("label", dn, [
1544
+ e[69] || (e[69] = c("Width (px) ", -1)),
1545
+ o(x, {
1546
+ "model-value": t.selectedBlock.content.width ?? 600,
1547
+ type: "number",
1548
+ min: "24",
1549
+ max: "800",
1550
+ class: "mt-1.5 h-9 text-sm",
1551
+ "onUpdate:modelValue": e[10] || (e[10] = (a) => v("width", a, 24, 800)),
1552
+ onChange: e[11] || (e[11] = (a) => v("width", a.target.value, 24, 800, !0))
1553
+ }, null, 8, ["model-value"])
1554
+ ]),
1555
+ e[70] || (e[70] = l("p", { class: "text-[11px] text-muted-foreground" }, "Images scale down to fit the email on smaller screens.", -1))
1556
+ ], 64)) : t.selectedBlock.type === "divider" ? (s(), u(P, { key: 4 }, [
1557
+ l("div", null, [
1558
+ e[71] || (e[71] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Line color", -1)),
1559
+ l("div", un, [
1560
+ l("input", {
1561
+ type: "color",
1562
+ value: t.selectedBlock.content.color || "#e5e7eb",
1563
+ "aria-label": "Divider color picker",
1564
+ class: "size-9 shrink-0 cursor-pointer rounded border",
1565
+ onInput: e[12] || (e[12] = (a) => V("color", a.target.value))
1566
+ }, null, 40, mn),
1567
+ o(x, {
1568
+ "model-value": t.selectedBlock.content.color || "#e5e7eb",
1569
+ "aria-label": "Divider color",
1570
+ class: "h-9 flex-1 font-mono text-sm",
1571
+ "onUpdate:modelValue": e[13] || (e[13] = (a) => V("color", a))
1572
+ }, null, 8, ["model-value"])
1573
+ ])
1574
+ ]),
1575
+ l("label", cn, [
1576
+ e[72] || (e[72] = c("Thickness (px) ", -1)),
1577
+ o(x, {
1578
+ "model-value": t.selectedBlock.content.thickness ?? 1,
1579
+ type: "number",
1580
+ min: "1",
1581
+ max: "8",
1582
+ class: "mt-1.5 h-9 text-sm",
1583
+ "onUpdate:modelValue": e[14] || (e[14] = (a) => v("thickness", a, 1, 8)),
1584
+ onChange: e[15] || (e[15] = (a) => v("thickness", a.target.value, 1, 8, !0))
1585
+ }, null, 8, ["model-value"])
1586
+ ]),
1587
+ l("div", null, [
1588
+ e[76] || (e[76] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Line style", -1)),
1589
+ o(W, {
1590
+ "model-value": t.selectedBlock.content.style || "solid",
1591
+ class: "w-full",
1592
+ "aria-label": "Divider line style",
1593
+ "onUpdate:modelValue": e[16] || (e[16] = (a) => V("style", a))
1594
+ }, {
1595
+ default: p(() => [
1596
+ o(M, {
1597
+ value: "solid",
1598
+ class: "px-2 text-xs"
1599
+ }, {
1600
+ default: p(() => [...e[73] || (e[73] = [
1601
+ c("Solid", -1)
1602
+ ])]),
1603
+ _: 1
1604
+ }),
1605
+ o(M, {
1606
+ value: "dashed",
1607
+ class: "px-2 text-xs"
1608
+ }, {
1609
+ default: p(() => [...e[74] || (e[74] = [
1610
+ c("Dashed", -1)
1611
+ ])]),
1612
+ _: 1
1613
+ }),
1614
+ o(M, {
1615
+ value: "dotted",
1616
+ class: "px-2 text-xs"
1617
+ }, {
1618
+ default: p(() => [...e[75] || (e[75] = [
1619
+ c("Dotted", -1)
1620
+ ])]),
1621
+ _: 1
1622
+ })
1623
+ ]),
1624
+ _: 1
1625
+ }, 8, ["model-value"])
1626
+ ])
1627
+ ], 64)) : t.selectedBlock.type === "spacer" ? (s(), u("label", pn, [
1628
+ e[77] || (e[77] = c("Height (px) ", -1)),
1629
+ o(x, {
1630
+ "model-value": t.selectedBlock.content.height ?? 24,
1631
+ type: "number",
1632
+ min: "0",
1633
+ max: "200",
1634
+ class: "mt-1.5 h-9 text-sm",
1635
+ "onUpdate:modelValue": e[17] || (e[17] = (a) => v("height", a, 0, 200)),
1636
+ onChange: e[18] || (e[18] = (a) => v("height", a.target.value, 0, 200, !0))
1637
+ }, null, 8, ["model-value"])
1638
+ ])) : t.selectedBlock.type === "columns" ? (s(), u(P, { key: 6 }, [
1639
+ e[81] || (e[81] = l("p", { class: "text-xs leading-relaxed text-muted-foreground" }, "Present details side by side. Columns stack on mobile.", -1)),
1640
+ (s(!0), u(P, null, te(g.value, (a, q) => (s(), u("div", {
1641
+ key: q,
1642
+ class: "space-y-2 rounded-md border p-3"
1643
+ }, [
1644
+ l("div", vn, [
1645
+ l("p", fn, "Column " + $(q + 1), 1),
1646
+ l("button", {
1647
+ type: "button",
1648
+ "aria-label": `Remove column ${q + 1}`,
1649
+ title: `Remove column ${q + 1}`,
1650
+ disabled: g.value.length <= 1,
1651
+ class: "rounded p-1 text-muted-foreground hover:bg-accent hover:text-destructive disabled:opacity-30",
1652
+ onClick: (Q) => C(q)
1653
+ }, [
1654
+ o(w(st), { class: "size-3.5" })
1655
+ ], 8, bn)
1656
+ ]),
1657
+ l("label", xn, [
1658
+ e[78] || (e[78] = c("Label", -1)),
1659
+ o(x, {
1660
+ modelValue: a.label,
1661
+ "onUpdate:modelValue": [(Q) => a.label = Q, m],
1662
+ class: "mt-1 h-8 text-xs"
1663
+ }, null, 8, ["modelValue", "onUpdate:modelValue"])
1664
+ ]),
1665
+ l("label", gn, [
1666
+ e[79] || (e[79] = c("Value", -1)),
1667
+ o(x, {
1668
+ modelValue: a.value,
1669
+ "onUpdate:modelValue": [(Q) => a.value = Q, m],
1670
+ class: "mt-1 h-8 text-xs"
1671
+ }, null, 8, ["modelValue", "onUpdate:modelValue"])
1672
+ ])
1673
+ ]))), 128)),
1674
+ o(R, {
1675
+ type: "button",
1676
+ variant: "outline",
1677
+ size: "sm",
1678
+ class: "w-full gap-1.5",
1679
+ disabled: g.value.length >= 4,
1680
+ onClick: b
1681
+ }, {
1682
+ default: p(() => [
1683
+ o(w(Le), { class: "size-3.5" }),
1684
+ e[80] || (e[80] = c("Add column", -1))
1685
+ ]),
1686
+ _: 1
1687
+ }, 8, ["disabled"])
1688
+ ], 64)) : T("", !0),
1689
+ ["header", "text"].includes(t.selectedBlock.type) ? (s(), u(P, { key: 7 }, [
1690
+ l("div", null, [
1691
+ l("div", yn, [
1692
+ e[82] || (e[82] = l("p", { class: "text-xs font-medium text-muted-foreground" }, "Text color", -1)),
1693
+ t.selectedBlock.content.color ? (s(), u("button", {
1694
+ key: 0,
1695
+ type: "button",
1696
+ class: "text-[11px] text-muted-foreground hover:text-foreground",
1697
+ onClick: e[19] || (e[19] = (a) => {
1698
+ delete t.selectedBlock.content.color, m();
1699
+ })
1700
+ }, "Use template color")) : T("", !0)
1701
+ ]),
1702
+ l("div", kn, [
1703
+ l("input", {
1704
+ type: "color",
1705
+ value: t.selectedBlock.content.color || t.templateStyles.textColor,
1706
+ "aria-label": "Block text color picker",
1707
+ class: "size-9 shrink-0 cursor-pointer rounded border",
1708
+ onInput: e[20] || (e[20] = (a) => V("color", a.target.value))
1709
+ }, null, 40, hn),
1710
+ o(x, {
1711
+ "model-value": t.selectedBlock.content.color || t.templateStyles.textColor,
1712
+ "aria-label": "Block text color",
1713
+ class: "h-9 flex-1 font-mono text-sm",
1714
+ "onUpdate:modelValue": e[21] || (e[21] = (a) => V("color", a))
1715
+ }, null, 8, ["model-value"])
1716
+ ])
1717
+ ]),
1718
+ l("label", wn, [
1719
+ e[83] || (e[83] = c("Font size (px) ", -1)),
1720
+ o(x, {
1721
+ "model-value": t.selectedBlock.content.fontSize ?? I.value,
1722
+ type: "number",
1723
+ min: "8",
1724
+ max: "72",
1725
+ class: "mt-1.5 h-9 text-sm",
1726
+ "onUpdate:modelValue": e[22] || (e[22] = (a) => v("fontSize", a, 8, 72)),
1727
+ onChange: e[23] || (e[23] = (a) => v("fontSize", a.target.value, 8, 72, !0))
1728
+ }, null, 8, ["model-value"])
1729
+ ])
1730
+ ], 64)) : T("", !0),
1731
+ ["header", "text", "button", "image"].includes(t.selectedBlock.type) ? (s(), u("div", Sn, [
1732
+ e[84] || (e[84] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Alignment", -1)),
1733
+ o(W, {
1734
+ "model-value": t.selectedBlock.content.align || (["button", "image"].includes(t.selectedBlock.type) ? "center" : "left"),
1735
+ class: "w-full",
1736
+ "aria-label": "Block alignment",
1737
+ "onUpdate:modelValue": e[24] || (e[24] = (a) => V("align", a))
1738
+ }, {
1739
+ default: p(() => [
1740
+ (s(), u(P, null, te(B, (a) => o(M, {
1741
+ key: a.value,
1742
+ value: a.value,
1743
+ "aria-label": a.label,
1744
+ title: a.label
1745
+ }, {
1746
+ default: p(() => [
1747
+ (s(), N(fe(a.icon), { class: "mx-auto size-3.5" }))
1748
+ ]),
1749
+ _: 2
1750
+ }, 1032, ["value", "aria-label", "title"])), 64))
1751
+ ]),
1752
+ _: 1
1753
+ }, 8, ["model-value"])
1754
+ ])) : T("", !0),
1755
+ l("div", Cn, [
1756
+ e[87] || (e[87] = l("p", { class: "mb-2 text-xs font-medium text-muted-foreground" }, "Spacing (px)", -1)),
1757
+ l("div", $n, [
1758
+ l("label", Bn, [
1759
+ e[85] || (e[85] = c("Above", -1)),
1760
+ o(x, {
1761
+ "model-value": t.selectedBlock.content.paddingTop ?? Y.value,
1762
+ type: "number",
1763
+ min: "0",
1764
+ max: "80",
1765
+ class: "mt-1 h-8 text-xs",
1766
+ "onUpdate:modelValue": e[25] || (e[25] = (a) => v("paddingTop", a, 0, 80)),
1767
+ onChange: e[26] || (e[26] = (a) => v("paddingTop", a.target.value, 0, 80, !0))
1768
+ }, null, 8, ["model-value"])
1769
+ ]),
1770
+ l("label", Tn, [
1771
+ e[86] || (e[86] = c("Below", -1)),
1772
+ o(x, {
1773
+ "model-value": t.selectedBlock.content.paddingBottom ?? (t.selectedBlock.type === "spacer" ? 0 : 16),
1774
+ type: "number",
1775
+ min: "0",
1776
+ max: "80",
1777
+ class: "mt-1 h-8 text-xs",
1778
+ "onUpdate:modelValue": e[27] || (e[27] = (a) => v("paddingBottom", a, 0, 80)),
1779
+ onChange: e[28] || (e[28] = (a) => v("paddingBottom", a.target.value, 0, 80, !0))
1780
+ }, null, 8, ["model-value"])
1781
+ ])
1782
+ ])
1783
+ ])
1784
+ ])),
1785
+ o(ee)
1786
+ ], 64)) : T("", !0),
1787
+ e[118] || (e[118] = l("div", { class: "rounded-lg bg-muted/50 border border-border/50 p-3 mb-2" }, [
1788
+ l("h4", { class: "mb-1 text-xs font-semibold" }, "Template design"),
1789
+ l("p", { class: "text-[11px] text-muted-foreground leading-snug" }, [
1790
+ c("These design settings apply to "),
1791
+ l("strong", null, "this template"),
1792
+ c(".")
1793
+ ])
1794
+ ], -1)),
1795
+ l("div", null, [
1796
+ e[89] || (e[89] = l("h4", { class: "mb-3 text-sm font-semibold" }, "Branding", -1)),
1797
+ l("label", Vn, [
1798
+ e[88] || (e[88] = c("Logo URL ", -1)),
1799
+ o(x, {
1800
+ modelValue: t.templateStyles.logoUrl,
1801
+ "onUpdate:modelValue": [
1802
+ e[29] || (e[29] = (a) => t.templateStyles.logoUrl = a),
1803
+ m
1804
+ ],
1805
+ class: "mt-1.5 h-9 text-sm",
1806
+ placeholder: "https://example.com/logo.png"
1807
+ }, null, 8, ["modelValue"])
1808
+ ]),
1809
+ e[90] || (e[90] = l("p", { class: "mt-1.5 text-[11px] text-muted-foreground" }, "Appears above the email content. Leave empty to hide it.", -1))
1810
+ ]),
1811
+ l("div", null, [
1812
+ e[101] || (e[101] = l("h4", { class: "text-sm font-semibold mb-3" }, "Colors", -1)),
1813
+ l("div", Un, [
1814
+ l("div", null, [
1815
+ e[91] || (e[91] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Body Background", -1)),
1816
+ l("div", Dn, [
1817
+ G(l("input", {
1818
+ type: "color",
1819
+ "onUpdate:modelValue": e[30] || (e[30] = (a) => t.templateStyles.bodyBg = a),
1820
+ class: "size-9 rounded border cursor-pointer",
1821
+ onInput: m
1822
+ }, null, 544), [
1823
+ [ne, t.templateStyles.bodyBg]
1824
+ ]),
1825
+ o(x, {
1826
+ modelValue: t.templateStyles.bodyBg,
1827
+ "onUpdate:modelValue": e[31] || (e[31] = (a) => t.templateStyles.bodyBg = a),
1828
+ class: "h-9 text-sm flex-1 font-mono",
1829
+ onInput: m
1830
+ }, null, 8, ["modelValue"])
1831
+ ])
1832
+ ]),
1833
+ l("div", null, [
1834
+ e[92] || (e[92] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Content Background", -1)),
1835
+ l("div", zn, [
1836
+ G(l("input", {
1837
+ type: "color",
1838
+ "onUpdate:modelValue": e[32] || (e[32] = (a) => t.templateStyles.contentBg = a),
1839
+ class: "size-9 rounded border cursor-pointer",
1840
+ onInput: m
1841
+ }, null, 544), [
1842
+ [ne, t.templateStyles.contentBg]
1843
+ ]),
1844
+ o(x, {
1845
+ modelValue: t.templateStyles.contentBg,
1846
+ "onUpdate:modelValue": e[33] || (e[33] = (a) => t.templateStyles.contentBg = a),
1847
+ class: "h-9 text-sm flex-1 font-mono",
1848
+ onInput: m
1849
+ }, null, 8, ["modelValue"])
1850
+ ])
1851
+ ]),
1852
+ l("div", null, [
1853
+ e[93] || (e[93] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Footer Background", -1)),
1854
+ l("div", In, [
1855
+ G(l("input", {
1856
+ type: "color",
1857
+ "onUpdate:modelValue": e[34] || (e[34] = (a) => t.templateStyles.footerBg = a),
1858
+ class: "size-9 rounded border cursor-pointer",
1859
+ onInput: m
1860
+ }, null, 544), [
1861
+ [ne, t.templateStyles.footerBg]
1862
+ ]),
1863
+ o(x, {
1864
+ modelValue: t.templateStyles.footerBg,
1865
+ "onUpdate:modelValue": e[35] || (e[35] = (a) => t.templateStyles.footerBg = a),
1866
+ class: "h-9 text-sm flex-1 font-mono",
1867
+ onInput: m
1868
+ }, null, 8, ["modelValue"])
1869
+ ])
1870
+ ]),
1871
+ l("div", null, [
1872
+ e[94] || (e[94] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Footer Text Color", -1)),
1873
+ l("div", Mn, [
1874
+ G(l("input", {
1875
+ type: "color",
1876
+ "onUpdate:modelValue": e[36] || (e[36] = (a) => t.templateStyles.footerTextColor = a),
1877
+ class: "size-9 rounded border cursor-pointer",
1878
+ onInput: m
1879
+ }, null, 544), [
1880
+ [ne, t.templateStyles.footerTextColor]
1881
+ ]),
1882
+ o(x, {
1883
+ modelValue: t.templateStyles.footerTextColor,
1884
+ "onUpdate:modelValue": e[37] || (e[37] = (a) => t.templateStyles.footerTextColor = a),
1885
+ class: "h-9 text-sm flex-1 font-mono",
1886
+ onInput: m
1887
+ }, null, 8, ["modelValue"])
1888
+ ])
1889
+ ]),
1890
+ l("div", null, [
1891
+ e[95] || (e[95] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Primary / Button Color", -1)),
1892
+ l("div", Ln, [
1893
+ G(l("input", {
1894
+ type: "color",
1895
+ "onUpdate:modelValue": e[38] || (e[38] = (a) => t.templateStyles.primaryColor = a),
1896
+ class: "size-9 rounded border cursor-pointer",
1897
+ onInput: m
1898
+ }, null, 544), [
1899
+ [ne, t.templateStyles.primaryColor]
1900
+ ]),
1901
+ o(x, {
1902
+ modelValue: t.templateStyles.primaryColor,
1903
+ "onUpdate:modelValue": e[39] || (e[39] = (a) => t.templateStyles.primaryColor = a),
1904
+ class: "h-9 text-sm flex-1 font-mono",
1905
+ onInput: m
1906
+ }, null, 8, ["modelValue"])
1907
+ ])
1908
+ ]),
1909
+ l("div", null, [
1910
+ e[96] || (e[96] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Button Text Color", -1)),
1911
+ l("div", An, [
1912
+ G(l("input", {
1913
+ type: "color",
1914
+ "onUpdate:modelValue": e[40] || (e[40] = (a) => t.templateStyles.primaryForeground = a),
1915
+ "aria-label": "Button text color picker",
1916
+ class: "size-9 shrink-0 cursor-pointer rounded border",
1917
+ onInput: m
1918
+ }, null, 544), [
1919
+ [ne, t.templateStyles.primaryForeground]
1920
+ ]),
1921
+ o(x, {
1922
+ modelValue: t.templateStyles.primaryForeground,
1923
+ "onUpdate:modelValue": [
1924
+ e[41] || (e[41] = (a) => t.templateStyles.primaryForeground = a),
1925
+ m
1926
+ ],
1927
+ "aria-label": "Button text color",
1928
+ class: "h-9 flex-1 font-mono text-sm"
1929
+ }, null, 8, ["modelValue"])
1930
+ ])
1931
+ ]),
1932
+ l("div", null, [
1933
+ e[97] || (e[97] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Text Color", -1)),
1934
+ l("div", Rn, [
1935
+ G(l("input", {
1936
+ type: "color",
1937
+ "onUpdate:modelValue": e[42] || (e[42] = (a) => t.templateStyles.textColor = a),
1938
+ class: "size-9 rounded border cursor-pointer",
1939
+ onInput: m
1940
+ }, null, 544), [
1941
+ [ne, t.templateStyles.textColor]
1942
+ ]),
1943
+ o(x, {
1944
+ modelValue: t.templateStyles.textColor,
1945
+ "onUpdate:modelValue": e[43] || (e[43] = (a) => t.templateStyles.textColor = a),
1946
+ class: "h-9 text-sm flex-1 font-mono",
1947
+ onInput: m
1948
+ }, null, 8, ["modelValue"])
1949
+ ])
1950
+ ]),
1951
+ l("div", null, [
1952
+ e[98] || (e[98] = l("p", { class: "mb-1.5 text-xs font-medium text-muted-foreground" }, "Secondary Text Color", -1)),
1953
+ l("div", jn, [
1954
+ G(l("input", {
1955
+ type: "color",
1956
+ "onUpdate:modelValue": e[44] || (e[44] = (a) => t.templateStyles.secondaryTextColor = a),
1957
+ "aria-label": "Secondary text color picker",
1958
+ class: "size-9 shrink-0 cursor-pointer rounded border",
1959
+ onInput: m
1960
+ }, null, 544), [
1961
+ [ne, t.templateStyles.secondaryTextColor]
1962
+ ]),
1963
+ o(x, {
1964
+ modelValue: t.templateStyles.secondaryTextColor,
1965
+ "onUpdate:modelValue": [
1966
+ e[45] || (e[45] = (a) => t.templateStyles.secondaryTextColor = a),
1967
+ m
1968
+ ],
1969
+ "aria-label": "Secondary text color",
1970
+ class: "h-9 flex-1 font-mono text-sm"
1971
+ }, null, 8, ["modelValue"])
1972
+ ]),
1973
+ e[99] || (e[99] = l("p", { class: "mt-1.5 text-[11px] text-muted-foreground" }, "Used for column labels and supporting text.", -1))
1974
+ ]),
1975
+ l("div", null, [
1976
+ e[100] || (e[100] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Link Color", -1)),
1977
+ l("div", En, [
1978
+ G(l("input", {
1979
+ type: "color",
1980
+ "onUpdate:modelValue": e[46] || (e[46] = (a) => t.templateStyles.linkColor = a),
1981
+ class: "size-9 rounded border cursor-pointer",
1982
+ onInput: m
1983
+ }, null, 544), [
1984
+ [ne, t.templateStyles.linkColor]
1985
+ ]),
1986
+ o(x, {
1987
+ modelValue: t.templateStyles.linkColor,
1988
+ "onUpdate:modelValue": e[47] || (e[47] = (a) => t.templateStyles.linkColor = a),
1989
+ class: "h-9 text-sm flex-1 font-mono",
1990
+ onInput: m
1991
+ }, null, 8, ["modelValue"])
1992
+ ])
1993
+ ])
1994
+ ])
1995
+ ]),
1996
+ o(ee),
1997
+ l("div", null, [
1998
+ e[110] || (e[110] = l("h4", { class: "text-sm font-semibold mb-3" }, "Typography", -1)),
1999
+ l("div", Nn, [
2000
+ l("div", null, [
2001
+ e[109] || (e[109] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Font Family", -1)),
2002
+ o(be, {
2003
+ modelValue: t.templateStyles.fontFamily,
2004
+ "onUpdate:modelValue": [
2005
+ e[48] || (e[48] = (a) => t.templateStyles.fontFamily = a),
2006
+ m
2007
+ ]
2008
+ }, {
2009
+ default: p(() => [
2010
+ o(se, { class: "h-9 text-sm" }, {
2011
+ default: p(() => [
2012
+ o(oe)
2013
+ ]),
2014
+ _: 1
2015
+ }),
2016
+ o(F, null, {
2017
+ default: p(() => [
2018
+ o(J, { value: "Arial, Helvetica, sans-serif" }, {
2019
+ default: p(() => [...e[102] || (e[102] = [
2020
+ c("Arial", -1)
2021
+ ])]),
2022
+ _: 1
2023
+ }),
2024
+ o(J, { value: "'Helvetica Neue', Helvetica, Arial, sans-serif" }, {
2025
+ default: p(() => [...e[103] || (e[103] = [
2026
+ c("Helvetica", -1)
2027
+ ])]),
2028
+ _: 1
2029
+ }),
2030
+ o(J, { value: "Georgia, 'Times New Roman', serif" }, {
2031
+ default: p(() => [...e[104] || (e[104] = [
2032
+ c("Georgia", -1)
2033
+ ])]),
2034
+ _: 1
2035
+ }),
2036
+ o(J, { value: "Verdana, Geneva, sans-serif" }, {
2037
+ default: p(() => [...e[105] || (e[105] = [
2038
+ c("Verdana", -1)
2039
+ ])]),
2040
+ _: 1
2041
+ }),
2042
+ o(J, { value: "Tahoma, Geneva, sans-serif" }, {
2043
+ default: p(() => [...e[106] || (e[106] = [
2044
+ c("Tahoma", -1)
2045
+ ])]),
2046
+ _: 1
2047
+ }),
2048
+ o(J, { value: "'Trebuchet MS', Helvetica, sans-serif" }, {
2049
+ default: p(() => [...e[107] || (e[107] = [
2050
+ c("Trebuchet MS", -1)
2051
+ ])]),
2052
+ _: 1
2053
+ }),
2054
+ o(J, { value: "'Courier New', Courier, monospace" }, {
2055
+ default: p(() => [...e[108] || (e[108] = [
2056
+ c("Courier New", -1)
2057
+ ])]),
2058
+ _: 1
2059
+ })
2060
+ ]),
2061
+ _: 1
2062
+ })
2063
+ ]),
2064
+ _: 1
2065
+ }, 8, ["modelValue"])
2066
+ ])
2067
+ ])
2068
+ ]),
2069
+ o(ee),
2070
+ l("div", null, [
2071
+ e[114] || (e[114] = l("h4", { class: "text-sm font-semibold mb-3" }, "Layout", -1)),
2072
+ l("div", Hn, [
2073
+ l("div", null, [
2074
+ e[111] || (e[111] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Content Width", -1)),
2075
+ l("div", Pn, [
2076
+ G(l("input", {
2077
+ type: "range",
2078
+ "onUpdate:modelValue": e[49] || (e[49] = (a) => t.templateStyles.contentWidth = a),
2079
+ min: "400",
2080
+ max: "800",
2081
+ step: "10",
2082
+ class: "flex-1 accent-primary",
2083
+ onInput: m
2084
+ }, null, 544), [
2085
+ [
2086
+ ne,
2087
+ t.templateStyles.contentWidth,
2088
+ void 0,
2089
+ { number: !0 }
2090
+ ]
2091
+ ]),
2092
+ l("span", Fn, $(t.templateStyles.contentWidth) + "px", 1)
2093
+ ])
2094
+ ]),
2095
+ l("div", null, [
2096
+ e[112] || (e[112] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Content Padding", -1)),
2097
+ l("div", On, [
2098
+ G(l("input", {
2099
+ type: "range",
2100
+ "onUpdate:modelValue": e[50] || (e[50] = (a) => t.templateStyles.contentPadding = a),
2101
+ min: "16",
2102
+ max: "64",
2103
+ step: "4",
2104
+ class: "flex-1 accent-primary",
2105
+ onInput: m
2106
+ }, null, 544), [
2107
+ [
2108
+ ne,
2109
+ t.templateStyles.contentPadding,
2110
+ void 0,
2111
+ { number: !0 }
2112
+ ]
2113
+ ]),
2114
+ l("span", Wn, $(t.templateStyles.contentPadding) + "px", 1)
2115
+ ])
2116
+ ]),
2117
+ l("div", null, [
2118
+ e[113] || (e[113] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Border Radius", -1)),
2119
+ l("div", Jn, [
2120
+ G(l("input", {
2121
+ type: "range",
2122
+ "onUpdate:modelValue": e[51] || (e[51] = (a) => t.templateStyles.borderRadius = a),
2123
+ min: "0",
2124
+ max: "24",
2125
+ step: "2",
2126
+ class: "flex-1 accent-primary",
2127
+ onInput: m
2128
+ }, null, 544), [
2129
+ [
2130
+ ne,
2131
+ t.templateStyles.borderRadius,
2132
+ void 0,
2133
+ { number: !0 }
2134
+ ]
2135
+ ]),
2136
+ l("span", qn, $(t.templateStyles.borderRadius) + "px", 1)
2137
+ ])
2138
+ ])
2139
+ ])
2140
+ ]),
2141
+ o(ee),
2142
+ l("div", null, [
2143
+ e[117] || (e[117] = l("h4", { class: "text-sm font-semibold mb-3" }, "Footer", -1)),
2144
+ l("div", Yn, [
2145
+ l("div", null, [
2146
+ e[115] || (e[115] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Footer Text", -1)),
2147
+ o(ce, {
2148
+ modelValue: t.templateStyles.footerText,
2149
+ "onUpdate:modelValue": e[52] || (e[52] = (a) => t.templateStyles.footerText = a),
2150
+ rows: "2",
2151
+ class: "text-sm resize-none",
2152
+ onInput: m
2153
+ }, null, 8, ["modelValue"])
2154
+ ]),
2155
+ l("div", Kn, [
2156
+ e[116] || (e[116] = l("label", { class: "text-sm" }, "Show Unsubscribe Link", -1)),
2157
+ o(X, {
2158
+ modelValue: t.templateStyles.showUnsubscribe,
2159
+ "onUpdate:modelValue": [
2160
+ e[53] || (e[53] = (a) => t.templateStyles.showUnsubscribe = a),
2161
+ m
2162
+ ]
2163
+ }, null, 8, ["modelValue"])
2164
+ ])
2165
+ ])
2166
+ ])
2167
+ ]);
2168
+ };
2169
+ }
2170
+ }), Qn = { class: "p-4 space-y-6" }, Zn = { class: "space-y-3" }, Xn = { class: "space-y-1.5" }, _n = ["onClick"], ea = { class: "text-xs font-mono flex-1" }, ta = { class: "space-y-2" }, la = { class: "text-[11px] text-muted-foreground/60" }, oa = /* @__PURE__ */ me({
2171
+ __name: "SettingsPanel",
2172
+ props: {
2173
+ template: {},
2174
+ templateStyles: {}
2175
+ },
2176
+ emits: ["update:hasUnsavedChanges", "reset-styles", "reset-template"],
2177
+ setup(t, { emit: A }) {
2178
+ const i = t, f = A, m = () => f("update:hasUnsavedChanges", !0), B = j(() => !!et(i.template.name, i.template.system_key)), g = () => {
2179
+ f("reset-styles", gl());
2180
+ const v = et(i.template.name, i.template.system_key);
2181
+ v && f("reset-template", v.blocks), f("update:hasUnsavedChanges", !0);
2182
+ }, I = D(null), Y = async (v) => {
2183
+ try {
2184
+ await navigator.clipboard.writeText(v);
2185
+ } catch {
2186
+ return;
2187
+ }
2188
+ I.value = v, setTimeout(() => {
2189
+ I.value === v && (I.value = null);
2190
+ }, 1500);
2191
+ }, V = [
2192
+ "{{agency_name}}",
2193
+ "{{user_name}}",
2194
+ "{{user_email}}",
2195
+ "{{dashboard_url}}",
2196
+ "{{project_name}}",
2197
+ "{{year}}",
2198
+ "{{reset_url}}",
2199
+ "{{invite_url}}",
2200
+ "{{support_email}}",
2201
+ "{{inviter_name}}",
2202
+ "{{expires_at}}"
2203
+ ];
2204
+ return (v, b) => {
2205
+ const C = U("Input"), H = U("Textarea"), k = U("Separator"), h = U("Button");
2206
+ return s(), u("div", Qn, [
2207
+ l("div", null, [
2208
+ b[14] || (b[14] = l("h4", { class: "text-sm font-semibold mb-3" }, "Template Info", -1)),
2209
+ l("div", Zn, [
2210
+ l("div", null, [
2211
+ b[6] || (b[6] = l("label", {
2212
+ for: "email-template-name",
2213
+ class: "mb-1.5 block text-xs font-medium text-muted-foreground"
2214
+ }, "Name", -1)),
2215
+ o(C, {
2216
+ id: "email-template-name",
2217
+ modelValue: t.template.name,
2218
+ "onUpdate:modelValue": [
2219
+ b[0] || (b[0] = (e) => t.template.name = e),
2220
+ m
2221
+ ],
2222
+ class: "h-9 text-sm"
2223
+ }, null, 8, ["modelValue"])
2224
+ ]),
2225
+ l("div", null, [
2226
+ b[7] || (b[7] = l("label", {
2227
+ for: "email-template-description",
2228
+ class: "mb-1.5 block text-xs font-medium text-muted-foreground"
2229
+ }, "Description", -1)),
2230
+ o(H, {
2231
+ id: "email-template-description",
2232
+ modelValue: t.template.description,
2233
+ "onUpdate:modelValue": [
2234
+ b[1] || (b[1] = (e) => t.template.description = e),
2235
+ m
2236
+ ],
2237
+ rows: "2",
2238
+ class: "text-sm"
2239
+ }, null, 8, ["modelValue"])
2240
+ ]),
2241
+ l("div", null, [
2242
+ b[9] || (b[9] = l("label", {
2243
+ for: "email-template-category",
2244
+ class: "mb-1.5 block text-xs font-medium text-muted-foreground"
2245
+ }, "Category", -1)),
2246
+ G(l("select", {
2247
+ id: "email-template-category",
2248
+ "onUpdate:modelValue": b[2] || (b[2] = (e) => t.template.category = e),
2249
+ class: "h-9 w-full rounded-md border bg-background px-2 text-sm",
2250
+ onChange: m
2251
+ }, [...b[8] || (b[8] = [
2252
+ Ct('<option value="authentication">Authentication</option><option value="billing">Billing</option><option value="notifications">Notifications</option><option value="onboarding">Onboarding</option><option value="system">System</option>', 5)
2253
+ ])], 544), [
2254
+ [Me, t.template.category]
2255
+ ])
2256
+ ]),
2257
+ l("div", null, [
2258
+ b[11] || (b[11] = l("label", {
2259
+ for: "email-template-status",
2260
+ class: "mb-1.5 block text-xs font-medium text-muted-foreground"
2261
+ }, "Status", -1)),
2262
+ G(l("select", {
2263
+ id: "email-template-status",
2264
+ "onUpdate:modelValue": b[3] || (b[3] = (e) => t.template.status = e),
2265
+ class: "h-9 w-full rounded-md border bg-background px-2 text-sm",
2266
+ onChange: m
2267
+ }, [...b[10] || (b[10] = [
2268
+ l("option", { value: "draft" }, "Draft", -1),
2269
+ l("option", { value: "active" }, "Active", -1),
2270
+ l("option", { value: "inactive" }, "Inactive", -1)
2271
+ ])], 544), [
2272
+ [Me, t.template.status]
2273
+ ])
2274
+ ]),
2275
+ l("div", null, [
2276
+ b[12] || (b[12] = l("label", { class: "text-xs font-medium text-muted-foreground mb-1.5 block" }, "Subject", -1)),
2277
+ o(C, {
2278
+ modelValue: t.template.subject,
2279
+ "onUpdate:modelValue": [
2280
+ b[4] || (b[4] = (e) => t.template.subject = e),
2281
+ m
2282
+ ],
2283
+ class: "h-9 text-sm"
2284
+ }, null, 8, ["modelValue"]),
2285
+ b[13] || (b[13] = l("p", { class: "text-[11px] text-muted-foreground/60 mt-1" }, [
2286
+ c("Use "),
2287
+ l("code", { class: "text-[10px] bg-muted px-1 py-0.5 rounded" }, "{{variables}}"),
2288
+ c(" for dynamic content")
2289
+ ], -1))
2290
+ ])
2291
+ ])
2292
+ ]),
2293
+ l("div", null, [
2294
+ b[15] || (b[15] = l("label", {
2295
+ for: "email-preheader",
2296
+ class: "mb-1.5 block text-xs font-medium text-muted-foreground"
2297
+ }, "Inbox preview text", -1)),
2298
+ o(H, {
2299
+ id: "email-preheader",
2300
+ modelValue: t.template.preheader,
2301
+ "onUpdate:modelValue": [
2302
+ b[5] || (b[5] = (e) => t.template.preheader = e),
2303
+ m
2304
+ ],
2305
+ rows: "2",
2306
+ maxlength: "300",
2307
+ class: "text-sm",
2308
+ placeholder: "A short preview shown beside the subject…"
2309
+ }, null, 8, ["modelValue"]),
2310
+ b[16] || (b[16] = l("p", { class: "mt-1 text-[11px] text-muted-foreground" }, "Keep it short. Variables are supported.", -1))
2311
+ ]),
2312
+ o(k),
2313
+ l("div", null, [
2314
+ b[17] || (b[17] = l("h4", { class: "text-sm font-semibold mb-3" }, "Available Variables", -1)),
2315
+ l("div", Xn, [
2316
+ (s(), u(P, null, te(V, (e) => l("button", {
2317
+ type: "button",
2318
+ key: e,
2319
+ class: ie(["w-full flex items-center gap-2 px-2.5 py-1.5 rounded-md hover:bg-muted transition-all cursor-pointer group", I.value === e ? "bg-primary/10" : "bg-muted/50"]),
2320
+ onClick: (x) => Y(e)
2321
+ }, [
2322
+ o(w(il), { class: "size-3 text-muted-foreground" }),
2323
+ l("code", ea, $(e), 1),
2324
+ o($t, {
2325
+ name: "fade",
2326
+ mode: "out-in"
2327
+ }, {
2328
+ default: p(() => [
2329
+ I.value === e ? (s(), N(w(He), {
2330
+ key: 0,
2331
+ class: "size-3 text-primary"
2332
+ })) : (s(), N(w(Oe), {
2333
+ key: 1,
2334
+ class: "size-3 text-muted-foreground/0 group-hover:text-muted-foreground transition-colors"
2335
+ }))
2336
+ ]),
2337
+ _: 2
2338
+ }, 1024)
2339
+ ], 10, _n)), 64))
2340
+ ])
2341
+ ]),
2342
+ o(k),
2343
+ l("div", null, [
2344
+ b[19] || (b[19] = l("h4", { class: "text-sm font-semibold text-destructive mb-3" }, "Danger Zone", -1)),
2345
+ l("div", ta, [
2346
+ o(h, {
2347
+ variant: "outline",
2348
+ size: "sm",
2349
+ class: "w-full justify-start gap-2 h-9 text-sm",
2350
+ onClick: g
2351
+ }, {
2352
+ default: p(() => [
2353
+ o(w(rl), { class: "size-3.5" }),
2354
+ b[18] || (b[18] = c(" Reset to Default ", -1))
2355
+ ]),
2356
+ _: 1
2357
+ }),
2358
+ l("p", la, " Resets this template’s design" + $(B.value ? " and restores the template content." : "."), 1)
2359
+ ])
2360
+ ])
2361
+ ]);
2362
+ };
2363
+ }
2364
+ }), na = {
2365
+ class: "w-full min-w-0 xl:w-[300px] xl:shrink-0 border-t xl:border-t-0 xl:border-l bg-card flex flex-col",
2366
+ "aria-label": "Email design and settings"
2367
+ }, aa = { class: "p-3 border-b" }, sa = /* @__PURE__ */ me({
2368
+ __name: "RightSidebar",
2369
+ props: {
2370
+ template: {},
2371
+ selectedBlock: {},
2372
+ templateStyles: {}
2373
+ },
2374
+ emits: ["deselect-block", "update:hasUnsavedChanges", "reset-styles", "reset-template"],
2375
+ setup(t, { emit: A }) {
2376
+ const i = t, f = A, m = D("style");
2377
+ return he(() => i.selectedBlock?.id, (B) => {
2378
+ B && (m.value = "style");
2379
+ }), (B, g) => {
2380
+ const I = U("SegmentedControlButton"), Y = U("SegmentedControl"), V = U("ScrollArea");
2381
+ return s(), u("aside", na, [
2382
+ l("div", aa, [
2383
+ o(Y, {
2384
+ modelValue: m.value,
2385
+ "onUpdate:modelValue": g[0] || (g[0] = (v) => m.value = v),
2386
+ class: "w-full",
2387
+ "aria-label": "Email settings panels"
2388
+ }, {
2389
+ default: p(() => [
2390
+ o(I, {
2391
+ value: "style",
2392
+ class: "flex justify-center items-center gap-1.5"
2393
+ }, {
2394
+ default: p(() => [
2395
+ o(w(dl), { class: "size-3.5" }),
2396
+ g[6] || (g[6] = c(" Design ", -1))
2397
+ ]),
2398
+ _: 1
2399
+ }),
2400
+ o(I, {
2401
+ value: "settings",
2402
+ class: "flex justify-center items-center gap-1.5"
2403
+ }, {
2404
+ default: p(() => [
2405
+ o(w(ul), { class: "size-3.5" }),
2406
+ g[7] || (g[7] = c(" Settings ", -1))
2407
+ ]),
2408
+ _: 1
2409
+ })
2410
+ ]),
2411
+ _: 1
2412
+ }, 8, ["modelValue"])
2413
+ ]),
2414
+ o(V, { class: "flex-1 min-h-0" }, {
2415
+ default: p(() => [
2416
+ m.value === "style" ? (s(), N(Gn, {
2417
+ key: 0,
2418
+ "selected-block": t.selectedBlock,
2419
+ "template-styles": t.templateStyles,
2420
+ onDeselectBlock: g[1] || (g[1] = (v) => f("deselect-block")),
2421
+ "onUpdate:hasUnsavedChanges": g[2] || (g[2] = (v) => f("update:hasUnsavedChanges", v))
2422
+ }, null, 8, ["selected-block", "template-styles"])) : m.value === "settings" ? (s(), N(oa, {
2423
+ key: 1,
2424
+ template: t.template,
2425
+ "template-styles": t.templateStyles,
2426
+ "onUpdate:hasUnsavedChanges": g[3] || (g[3] = (v) => f("update:hasUnsavedChanges", v)),
2427
+ onResetStyles: g[4] || (g[4] = (v) => f("reset-styles", v)),
2428
+ onResetTemplate: g[5] || (g[5] = (v) => f("reset-template", v))
2429
+ }, null, 8, ["template", "template-styles"])) : T("", !0)
2430
+ ]),
2431
+ _: 1
2432
+ })
2433
+ ]);
2434
+ };
2435
+ }
2436
+ }), ia = { class: "mail-builder -m-4 flex h-[calc(100dvh-8rem)] min-h-[500px] flex-col overflow-hidden" }, ra = {
2437
+ key: 0,
2438
+ class: "flex flex-1 items-center justify-center gap-2 text-sm text-muted-foreground"
2439
+ }, da = {
2440
+ key: 1,
2441
+ class: "flex flex-1 flex-col items-center justify-center gap-4"
2442
+ }, ua = {
2443
+ key: 0,
2444
+ class: "flex items-center justify-between gap-3 border-b bg-amber-500/10 px-4 py-2 text-xs",
2445
+ role: "alert"
2446
+ }, ma = { class: "flex items-center justify-between border-b bg-card px-3 py-2 xl:hidden" }, ca = { class: "relative flex min-h-0 flex-1" }, pa = {
2447
+ key: 0,
2448
+ value: "duplicate"
2449
+ }, va = ["value"], ha = /* @__PURE__ */ me({
2450
+ __name: "TemplateBuilder",
2451
+ setup(t) {
2452
+ const A = nt(), { hasPermission: i } = Tt(), f = Vt(), m = Ut();
2453
+ Dt(() => []);
2454
+ const B = j(() => i("edit-template")), g = j(() => i("create-template")), I = j(() => i("delete-template")), Y = () => A.get("/templates"), V = (d) => A.post("/templates", { body: d }), v = (d, n) => A.patch(`/templates/${encodeURIComponent(d)}`, { body: n }), b = (d, n) => d?.data?.statusMessage || d?.message || n, C = D(!0), H = D(""), k = D(""), h = D(null), e = D(null), x = D(!1), M = D([]), W = j(() => F.value?.styles ?? { ...Ue }), R = D({}), ee = D({}), oe = D(null), se = D(!1), J = D(!1), F = j(() => M.value.find((d) => d.id === h.value) ?? null), be = j(() => F.value?.blocks.find((d) => d.id === e.value) ?? null), ce = j(() => M.value.filter((d) => ke(d) !== R.value[d.id]).map((d) => d.id)), X = j(() => !C.value && !H.value && ce.value.length > 0), a = () => JSON.stringify({ templates: M.value });
2455
+ let q = Ve(a());
2456
+ const Q = D(0), we = j(() => (Q.value, q.canUndo)), De = j(() => (Q.value, q.canRedo));
2457
+ let re, Se = !1;
2458
+ function pe() {
2459
+ clearTimeout(re), q.record(a()), Q.value++;
2460
+ }
2461
+ he(M, () => {
2462
+ C.value || Se || (clearTimeout(re), re = setTimeout(pe, 400));
2463
+ }, { deep: !0, flush: "sync" });
2464
+ function Ce(d) {
2465
+ if (!B.value) return;
2466
+ pe();
2467
+ const n = q[d]();
2468
+ if (!n) return;
2469
+ Se = !0;
2470
+ const S = JSON.parse(n);
2471
+ M.value = S.templates, M.value.some((O) => O.id === h.value) || (h.value = M.value[0]?.id ?? null), e.value = null, Se = !1, Q.value++;
2472
+ }
2473
+ function z(d) {
2474
+ pe(), h.value = d, e.value = null, se.value = !1;
2475
+ }
2476
+ function r(d) {
2477
+ e.value = d, J.value = !0;
2478
+ }
2479
+ function L(d) {
2480
+ !F.value || !B.value || (pe(), d(F.value.blocks), pe());
2481
+ }
2482
+ function ve(d) {
2483
+ const n = { id: crypto.randomUUID(), type: d, content: je(d) };
2484
+ L((S) => {
2485
+ const O = S.findIndex((le) => le.id === e.value);
2486
+ S.splice(O < 0 ? S.length : O + 1, 0, n);
2487
+ }), r(n.id);
2488
+ }
2489
+ function de(d) {
2490
+ L((n) => {
2491
+ const S = n.findIndex((O) => O.id === d);
2492
+ S >= 0 && n.splice(S, 1);
2493
+ }), e.value === d && (e.value = null);
2494
+ }
2495
+ function ue(d, n) {
2496
+ L((S) => {
2497
+ const O = S.findIndex((ge) => ge.id === d), le = O + (n === "up" ? -1 : 1);
2498
+ O >= 0 && le >= 0 && le < S.length && ([S[O], S[le]] = [S[le], S[O]]);
2499
+ });
2500
+ }
2501
+ function Ae(d, n) {
2502
+ d !== n && L((S) => {
2503
+ const O = S.findIndex((Te) => Te.id === d);
2504
+ if (O < 0) return;
2505
+ const [le] = S.splice(O, 1), ge = n ? S.findIndex((Te) => Te.id === n) : S.length;
2506
+ S.splice(ge < 0 ? S.length : ge, 0, le);
2507
+ });
2508
+ }
2509
+ function Re(d) {
2510
+ L((n) => {
2511
+ const S = n.findIndex((le) => le.id === d);
2512
+ if (S < 0) return;
2513
+ const O = { ...JSON.parse(JSON.stringify(n[S])), id: crypto.randomUUID() };
2514
+ n.splice(S + 1, 0, O), e.value = O.id;
2515
+ });
2516
+ }
2517
+ async function ze() {
2518
+ if (x.value || !X.value || !B.value) return;
2519
+ pe();
2520
+ const d = JSON.parse(JSON.stringify(M.value.filter((n) => ce.value.includes(n.id))));
2521
+ for (const n of d) {
2522
+ const S = !n.name.trim() || !n.subject.trim() ? "Every template needs a name and subject." : null;
2523
+ if (S) {
2524
+ ae.error(S), z(n.id);
2525
+ return;
2526
+ }
2527
+ }
2528
+ x.value = !0;
2529
+ try {
2530
+ for (const n of d) {
2531
+ const S = await v(n.id, { ...vt(n), updatedAt: ee.value[n.id] });
2532
+ ee.value[n.id] = S.updatedAt, oe.value === n.id && (oe.value = null), R.value[n.id] = ke(n);
2533
+ }
2534
+ ae.success("All changes saved");
2535
+ } catch (n) {
2536
+ (n?.statusCode === 409 || n?.status === 409) && (oe.value = d.find((S) => ke(S) !== R.value[S.id])?.id ?? null), ae.error(b(n, "Could not save changes. Your drafts are still here."));
2537
+ } finally {
2538
+ x.value = !1;
2539
+ }
2540
+ }
2541
+ const y = D(!1), Z = D(""), _ = D("blank"), xe = D(!1), Je = yl().filter((d) => !d.system_key);
2542
+ function Ie(d = !1) {
2543
+ Z.value = d && F.value ? `${F.value.name} copy` : "", _.value = d ? "duplicate" : "blank", y.value = !0;
2544
+ }
2545
+ async function bt() {
2546
+ if (!Z.value.trim() || xe.value || !g.value) return;
2547
+ xe.value = !0;
2548
+ const d = _.value === "duplicate" ? F.value : Je.find((n) => n.name === _.value);
2549
+ try {
2550
+ const n = await V({
2551
+ name: Z.value.trim(),
2552
+ subject: d?.subject || Z.value.trim(),
2553
+ preheader: d?.preheader || "",
2554
+ description: d?.description || "",
2555
+ category: d?.category || "notifications",
2556
+ status: "draft",
2557
+ styles: JSON.parse(JSON.stringify(d?.styles || Ue)),
2558
+ blocks: (d?.blocks || [{ type: "header", content: je("header") }, { type: "text", content: je("text") }]).map((S) => ({ ...JSON.parse(JSON.stringify(S)), id: crypto.randomUUID() }))
2559
+ });
2560
+ M.value.push(n), R.value[n.id] = ke(n), ee.value[n.id] = n.updatedAt, clearTimeout(re), q = Ve(a()), Q.value++, z(n.id), y.value = !1, ae.success("Template created");
2561
+ } catch (n) {
2562
+ ae.error(b(n, "Could not create template"));
2563
+ } finally {
2564
+ xe.value = !1;
2565
+ }
2566
+ }
2567
+ const $e = D(!1), Be = D(!1);
2568
+ async function xt() {
2569
+ if (!F.value || !I.value || Be.value) return;
2570
+ const d = F.value.id;
2571
+ Be.value = !0;
2572
+ try {
2573
+ await A.del(`/templates/${encodeURIComponent(d)}`), M.value = M.value.filter((n) => n.id !== d), delete R.value[d], delete ee.value[d], oe.value === d && (oe.value = null), h.value = M.value[0]?.id ?? null, e.value = null, clearTimeout(re), q = Ve(a()), Q.value++, $e.value = !1, ae.success("Template deleted");
2574
+ } catch (n) {
2575
+ ae.error(b(n, "Could not delete template"));
2576
+ } finally {
2577
+ Be.value = !1;
2578
+ }
2579
+ }
2580
+ async function gt() {
2581
+ const d = oe.value;
2582
+ if (!(!d || !window.confirm("Reload the saved version? This discards your local changes to this template. You can duplicate or export your draft first.")))
2583
+ try {
2584
+ const n = await A.get(`/templates/${encodeURIComponent(d)}`), S = M.value.findIndex((O) => O.id === d);
2585
+ if (S < 0) return;
2586
+ M.value[S] = { ...n, styles: { ...Ue, ...n.styles } }, R.value[d] = ke(M.value[S]), ee.value[d] = n.updatedAt, oe.value = null, clearTimeout(re), q = Ve(a()), Q.value++;
2587
+ } catch (n) {
2588
+ ae.error(b(n, "Could not reload the template"));
2589
+ }
2590
+ }
2591
+ function qe(d) {
2592
+ X.value && (d.preventDefault(), d.returnValue = "");
2593
+ }
2594
+ function Ye(d) {
2595
+ if (!(d.metaKey || d.ctrlKey) || d.altKey) return;
2596
+ const n = d.key.toLowerCase();
2597
+ if (n === "s") {
2598
+ d.preventDefault(), ze();
2599
+ return;
2600
+ }
2601
+ d.target.closest('input, textarea, [contenteditable="true"]') || (n === "z" || n === "y") && (d.preventDefault(), Ce(n === "y" || d.shiftKey ? "redo" : "undo"));
2602
+ }
2603
+ const yt = m.beforeEach((d, n) => d.fullPath === n.fullPath || !X.value || window.confirm("You have unsaved email changes. Leave without saving?"));
2604
+ async function Ke() {
2605
+ C.value = !0, H.value = "";
2606
+ try {
2607
+ const d = (await Y()).map((n) => ({ ...n, styles: { ...Ue, ...n.styles }, updated_at: n.updatedAt || n.updated_at }));
2608
+ M.value = d, R.value = Object.fromEntries(d.map((n) => [n.id, ke(n)])), ee.value = Object.fromEntries(d.map((n) => [n.id, n.updatedAt])), h.value = d.find((n) => n.id === f.params.value.optionId)?.id ?? d[0]?.id ?? null, f.currentPath.value === "new" && g.value && Ie(), q = Ve(a()), Q.value++;
2609
+ } catch (d) {
2610
+ H.value = b(d, "Could not load templates. Check the module’s Firebase integration and collection settings.");
2611
+ } finally {
2612
+ C.value = !1;
2613
+ }
2614
+ }
2615
+ return Bt(() => {
2616
+ Ke(), window.addEventListener("beforeunload", qe), window.addEventListener("keydown", Ye);
2617
+ }), ot(() => {
2618
+ yt(), clearTimeout(re), window.removeEventListener("beforeunload", qe), window.removeEventListener("keydown", Ye);
2619
+ }), (d, n) => {
2620
+ const S = U("Button"), O = U("DialogTitle"), le = U("DialogDescription"), ge = U("DialogHeader"), Te = U("Input"), Ge = U("DialogFooter"), Qe = U("DialogContent"), Ze = U("Dialog");
2621
+ return s(), u("div", ia, [
2622
+ C.value ? (s(), u("div", ra, [
2623
+ o(w(Ne), { class: "size-4 animate-spin" }),
2624
+ n[18] || (n[18] = c(" Loading email workspace…", -1))
2625
+ ])) : H.value ? (s(), u("div", da, [
2626
+ l("p", null, $(H.value), 1),
2627
+ o(S, { onClick: Ke }, {
2628
+ default: p(() => [...n[19] || (n[19] = [
2629
+ c("Try again", -1)
2630
+ ])]),
2631
+ _: 1
2632
+ })
2633
+ ])) : (s(), u(P, { key: 2 }, [
2634
+ oe.value ? (s(), u("div", ua, [
2635
+ n[21] || (n[21] = l("span", null, "A template changed elsewhere. Your local draft is intact; duplicate or export it to keep a copy.", -1)),
2636
+ o(S, {
2637
+ variant: "outline",
2638
+ size: "sm",
2639
+ onClick: gt
2640
+ }, {
2641
+ default: p(() => [...n[20] || (n[20] = [
2642
+ c("Reload latest", -1)
2643
+ ])]),
2644
+ _: 1
2645
+ })
2646
+ ])) : T("", !0),
2647
+ l("div", ma, [
2648
+ o(S, {
2649
+ variant: "outline",
2650
+ size: "sm",
2651
+ onClick: n[0] || (n[0] = (E) => {
2652
+ se.value = !se.value, J.value = !1;
2653
+ })
2654
+ }, {
2655
+ default: p(() => [
2656
+ o(w(ml), { class: "size-4" }),
2657
+ n[22] || (n[22] = c(" Templates", -1))
2658
+ ]),
2659
+ _: 1
2660
+ }),
2661
+ F.value && B.value ? (s(), N(S, {
2662
+ key: 0,
2663
+ variant: "outline",
2664
+ size: "sm",
2665
+ onClick: n[1] || (n[1] = (E) => {
2666
+ J.value = !J.value, se.value = !1;
2667
+ })
2668
+ }, {
2669
+ default: p(() => [
2670
+ o(w(cl), { class: "size-4" }),
2671
+ c(" " + $(be.value ? "Edit block" : "Design"), 1)
2672
+ ]),
2673
+ _: 1
2674
+ })) : T("", !0)
2675
+ ]),
2676
+ l("div", ca, [
2677
+ l("div", {
2678
+ class: ie(se.value ? "absolute inset-0 z-30 bg-card xl:static" : "hidden xl:flex")
2679
+ }, [
2680
+ o(jl, {
2681
+ templates: M.value,
2682
+ "selected-template-id": h.value,
2683
+ "dirty-template-ids": ce.value,
2684
+ "can-create": g.value,
2685
+ "search-query": k.value,
2686
+ "onUpdate:searchQuery": n[2] || (n[2] = (E) => k.value = E),
2687
+ onSelect: z,
2688
+ onCreate: n[3] || (n[3] = (E) => Ie())
2689
+ }, null, 8, ["templates", "selected-template-id", "dirty-template-ids", "can-create", "search-query"])
2690
+ ], 2),
2691
+ o(Eo, {
2692
+ template: F.value,
2693
+ "selected-block-id": e.value,
2694
+ "template-styles": W.value,
2695
+ saving: x.value,
2696
+ "has-unsaved-changes": X.value,
2697
+ "can-undo": we.value,
2698
+ "can-redo": De.value,
2699
+ "dirty-count": ce.value.length,
2700
+ "can-edit": B.value,
2701
+ "can-create": g.value,
2702
+ "can-delete": I.value,
2703
+ onSelectBlock: r,
2704
+ onAddBlock: ve,
2705
+ onMoveBlock: ue,
2706
+ onReorderBlock: Ae,
2707
+ onDuplicateBlock: Re,
2708
+ onDeleteBlock: de,
2709
+ onSave: ze,
2710
+ onUndo: n[4] || (n[4] = (E) => Ce("undo")),
2711
+ onRedo: n[5] || (n[5] = (E) => Ce("redo")),
2712
+ onDuplicateTemplate: n[6] || (n[6] = (E) => Ie(!0)),
2713
+ onCreate: n[7] || (n[7] = (E) => Ie()),
2714
+ onDeleteTemplate: n[8] || (n[8] = (E) => $e.value = !0)
2715
+ }, null, 8, ["template", "selected-block-id", "template-styles", "saving", "has-unsaved-changes", "can-undo", "can-redo", "dirty-count", "can-edit", "can-create", "can-delete"]),
2716
+ F.value && B.value ? (s(), u("div", {
2717
+ key: 0,
2718
+ class: ie(J.value ? "absolute inset-0 z-20 overflow-auto bg-card xl:static xl:flex" : "hidden xl:flex")
2719
+ }, [
2720
+ o(sa, {
2721
+ template: F.value,
2722
+ "selected-block": be.value,
2723
+ "template-styles": W.value,
2724
+ onDeselectBlock: n[9] || (n[9] = (E) => e.value = null),
2725
+ onResetStyles: n[10] || (n[10] = (E) => Object.assign(W.value, E)),
2726
+ onResetTemplate: n[11] || (n[11] = (E) => {
2727
+ F.value && (F.value.blocks = E);
2728
+ })
2729
+ }, null, 8, ["template", "selected-block", "template-styles"])
2730
+ ], 2)) : T("", !0)
2731
+ ])
2732
+ ], 64)),
2733
+ o(Ze, {
2734
+ open: y.value,
2735
+ "onUpdate:open": n[15] || (n[15] = (E) => y.value = E)
2736
+ }, {
2737
+ default: p(() => [
2738
+ o(Qe, { class: "sm:max-w-md" }, {
2739
+ default: p(() => [
2740
+ o(ge, null, {
2741
+ default: p(() => [
2742
+ o(O, null, {
2743
+ default: p(() => [...n[23] || (n[23] = [
2744
+ c("New email template", -1)
2745
+ ])]),
2746
+ _: 1
2747
+ }),
2748
+ o(le, null, {
2749
+ default: p(() => [...n[24] || (n[24] = [
2750
+ c("Start fresh, use a starter, or make a copy of your current design.", -1)
2751
+ ])]),
2752
+ _: 1
2753
+ })
2754
+ ]),
2755
+ _: 1
2756
+ }),
2757
+ l("form", {
2758
+ class: "space-y-4",
2759
+ onSubmit: ye(bt, ["prevent"])
2760
+ }, [
2761
+ l("div", null, [
2762
+ n[25] || (n[25] = l("label", {
2763
+ for: "template-name",
2764
+ class: "mb-1.5 block text-sm font-medium"
2765
+ }, "Template name", -1)),
2766
+ o(Te, {
2767
+ id: "template-name",
2768
+ modelValue: Z.value,
2769
+ "onUpdate:modelValue": n[12] || (n[12] = (E) => Z.value = E),
2770
+ placeholder: "e.g. Product announcement",
2771
+ maxlength: "120",
2772
+ required: ""
2773
+ }, null, 8, ["modelValue"])
2774
+ ]),
2775
+ l("div", null, [
2776
+ n[27] || (n[27] = l("label", {
2777
+ for: "template-starter",
2778
+ class: "mb-1.5 block text-sm font-medium"
2779
+ }, "Start from", -1)),
2780
+ G(l("select", {
2781
+ id: "template-starter",
2782
+ "onUpdate:modelValue": n[13] || (n[13] = (E) => _.value = E),
2783
+ class: "h-10 w-full rounded-md border bg-background px-3 text-sm"
2784
+ }, [
2785
+ n[26] || (n[26] = l("option", { value: "blank" }, "Blank email", -1)),
2786
+ F.value ? (s(), u("option", pa, "Copy of " + $(F.value.name), 1)) : T("", !0),
2787
+ (s(!0), u(P, null, te(w(Je), (E) => (s(), u("option", {
2788
+ key: E.name,
2789
+ value: E.name
2790
+ }, $(E.name), 9, va))), 128))
2791
+ ], 512), [
2792
+ [Me, _.value]
2793
+ ])
2794
+ ]),
2795
+ o(Ge, null, {
2796
+ default: p(() => [
2797
+ o(S, {
2798
+ type: "button",
2799
+ variant: "outline",
2800
+ onClick: n[14] || (n[14] = (E) => y.value = !1)
2801
+ }, {
2802
+ default: p(() => [...n[28] || (n[28] = [
2803
+ c("Cancel", -1)
2804
+ ])]),
2805
+ _: 1
2806
+ }),
2807
+ o(S, {
2808
+ type: "submit",
2809
+ disabled: xe.value || !Z.value.trim()
2810
+ }, {
2811
+ default: p(() => [
2812
+ c($(xe.value ? "Creating…" : "Create template"), 1)
2813
+ ]),
2814
+ _: 1
2815
+ }, 8, ["disabled"])
2816
+ ]),
2817
+ _: 1
2818
+ })
2819
+ ], 32)
2820
+ ]),
2821
+ _: 1
2822
+ })
2823
+ ]),
2824
+ _: 1
2825
+ }, 8, ["open"]),
2826
+ o(Ze, {
2827
+ open: $e.value,
2828
+ "onUpdate:open": n[17] || (n[17] = (E) => $e.value = E)
2829
+ }, {
2830
+ default: p(() => [
2831
+ o(Qe, { class: "sm:max-w-md" }, {
2832
+ default: p(() => [
2833
+ o(ge, null, {
2834
+ default: p(() => [
2835
+ o(O, null, {
2836
+ default: p(() => [
2837
+ c("Delete " + $(F.value?.name) + "?", 1)
2838
+ ]),
2839
+ _: 1
2840
+ }),
2841
+ o(le, null, {
2842
+ default: p(() => [...n[29] || (n[29] = [
2843
+ c("This permanently removes the saved template from the configured collection.", -1)
2844
+ ])]),
2845
+ _: 1
2846
+ })
2847
+ ]),
2848
+ _: 1
2849
+ }),
2850
+ o(Ge, null, {
2851
+ default: p(() => [
2852
+ o(S, {
2853
+ variant: "outline",
2854
+ onClick: n[16] || (n[16] = (E) => $e.value = !1)
2855
+ }, {
2856
+ default: p(() => [...n[30] || (n[30] = [
2857
+ c("Cancel", -1)
2858
+ ])]),
2859
+ _: 1
2860
+ }),
2861
+ o(S, {
2862
+ variant: "destructive",
2863
+ disabled: Be.value,
2864
+ onClick: xt
2865
+ }, {
2866
+ default: p(() => [
2867
+ c($(Be.value ? "Deleting…" : "Delete template"), 1)
2868
+ ]),
2869
+ _: 1
2870
+ }, 8, ["disabled"])
2871
+ ]),
2872
+ _: 1
2873
+ })
2874
+ ]),
2875
+ _: 1
2876
+ })
2877
+ ]),
2878
+ _: 1
2879
+ }, 8, ["open"])
2880
+ ]);
2881
+ };
2882
+ }
2883
+ });
2884
+ export {
2885
+ ha as _
2886
+ };