@oneclick.dev/cms-core-modules 0.0.124 → 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 (149) 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-DX1bTQKs.mjs → ContentEditor-D754iLJS.mjs} +8074 -27026
  5. package/dist/{Detail-B7pe808q.mjs → Detail-BOxWQ1QQ.mjs} +2 -2
  6. package/dist/{Detail-B_Q7Qkuz.mjs → Detail-BfKW0uZE.mjs} +2 -2
  7. package/dist/Detail-DFVu2F38.mjs +11 -0
  8. package/dist/{Detail-t3tOcy3X.js → Detail-DJea_fCd.js} +1 -1
  9. package/dist/{Detail-CNiLIEh9.js → Detail-DPJacXfm.js} +1 -1
  10. package/dist/Detail-DSLZ7_bM.js +1 -0
  11. package/dist/{Detail-BESGmY7z.js → Detail-DUGThL9Y.js} +1 -1
  12. package/dist/{Detail-DNxAzeCs.mjs → Detail-D_LlEeHu.mjs} +2 -2
  13. package/dist/Overview-0hFXiuYo.js +1 -0
  14. package/dist/Overview-BTx5LF4J.js +1 -0
  15. package/dist/Overview-CCu2PHai.mjs +289 -0
  16. package/dist/Overview-D2u-leeO.js +1 -0
  17. package/dist/Overview-D_2wozCG.mjs +1733 -0
  18. package/dist/Overview-Dffo-zH4.mjs +11 -0
  19. package/dist/{TableCalculationWidget-CrqcLGfU.mjs → TableCalculationWidget-B_LFoOYm.mjs} +3 -3
  20. package/dist/{TableCalculationWidget-CkQPrVUd.js → TableCalculationWidget-CahOIcbk.js} +1 -1
  21. package/dist/TableDataWidget-BwqWFH4A.js +1 -0
  22. package/dist/TableDataWidget-RsVxcDsL.mjs +112 -0
  23. package/dist/TableOverviewCard-BPWCqo56.js +1 -0
  24. package/dist/{TableOverviewCard-Ci0d4o4w.mjs → TableOverviewCard-D667DDag.mjs} +113 -127
  25. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-C3XiOXgb.js +1 -0
  26. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-sp0TLio0.mjs +547 -0
  27. package/dist/{TableRowActionCard-BhdnnPaq.mjs → TableRowActionCard-BPYJ-Kjy.mjs} +95 -101
  28. package/dist/TableRowActionCard-Bnqj1YIe.js +1 -0
  29. package/dist/TableView-CwhZ9YN2.js +4 -0
  30. package/dist/TableView-DX9PKS8N.mjs +9673 -0
  31. package/dist/TemplateBuilder.vue_vue_type_script_setup_true_lang-BgDdzbLe.js +1 -0
  32. package/dist/TemplateBuilder.vue_vue_type_script_setup_true_lang-D85V4nrQ.mjs +2886 -0
  33. package/dist/cms-core-modules.css +1 -1
  34. package/dist/dateRangePresets-CaPVagHY.mjs +453 -0
  35. package/dist/dateRangePresets-gxQCiZ6c.js +1 -0
  36. package/dist/index-6hZ6MYY6.js +1 -0
  37. package/dist/index-BVmmicu3.mjs +14 -0
  38. package/dist/index-ChHD_1Cf.js +144 -0
  39. package/dist/index-CvV4nVWI.js +1 -0
  40. package/dist/index-DH2z0W_w.mjs +19012 -0
  41. package/dist/index-DZKzj48V.mjs +17 -0
  42. package/dist/index.cjs.js +1 -1
  43. package/dist/index.mjs +237 -103
  44. package/dist/orders-C_sz8J9b.js +1 -0
  45. package/dist/{orders-BfTLIm7U.mjs → orders-Cgdggzvx.mjs} +84 -84
  46. package/dist/server-handlers.cjs.js +1 -1
  47. package/dist/server-handlers.mjs +2055 -1123
  48. package/dist/src/appointments/chat-components/AppointmentListTable.vue.d.ts +3 -0
  49. package/dist/src/appointments/index.d.ts +93 -3
  50. package/dist/src/appointments/reservation-summary.d.ts +48 -0
  51. package/dist/src/appointments/server.d.ts +1 -0
  52. package/dist/src/appointments/tools.d.ts +93 -3
  53. package/dist/src/filezone/config.d.ts +31 -0
  54. package/dist/src/filezone/index.d.ts +43 -0
  55. package/dist/src/filezone/index.vue.d.ts +2 -0
  56. package/dist/src/filezone/metadata.d.ts +2 -0
  57. package/dist/src/filezone/pages/Overview.vue.d.ts +4 -0
  58. package/dist/src/filezone/permissions.d.ts +5 -0
  59. package/dist/src/filezone/routes.d.ts +5 -0
  60. package/dist/src/filezone/server.d.ts +36 -0
  61. package/dist/src/index.d.ts +2 -0
  62. package/dist/src/mailTemplates/builder-types.d.ts +40 -0
  63. package/dist/src/mailTemplates/components/BlockRenderer.vue.d.ts +24 -0
  64. package/dist/src/mailTemplates/components/DesignPanel.vue.d.ts +13 -0
  65. package/dist/src/mailTemplates/components/EmailCanvas.vue.d.ts +44 -0
  66. package/dist/src/mailTemplates/components/RichTextEditor.vue.d.ts +10 -0
  67. package/dist/src/mailTemplates/components/RightSidebar.vue.d.ts +18 -0
  68. package/dist/src/mailTemplates/components/SettingsPanel.vue.d.ts +15 -0
  69. package/dist/src/mailTemplates/components/TemplateBuilder.vue.d.ts +2 -0
  70. package/dist/src/mailTemplates/components/TemplateList.vue.d.ts +19 -1
  71. package/dist/src/mailTemplates/components/rich-text.d.ts +6 -0
  72. package/dist/src/mailTemplates/config.d.ts +10 -4
  73. package/dist/src/mailTemplates/defaults.d.ts +10 -0
  74. package/dist/src/mailTemplates/editor-state.d.ts +21 -0
  75. package/dist/src/mailTemplates/index.d.ts +11 -5
  76. package/dist/src/mailTemplates/index.vue.d.ts +2 -4
  77. package/dist/src/mailTemplates/metadata.d.ts +1 -1
  78. package/dist/src/mailTemplates/pages/Detail.vue.d.ts +1 -13
  79. package/dist/src/mailTemplates/pages/Overview.vue.d.ts +1 -13
  80. package/dist/src/mailTemplates/server.d.ts +23 -0
  81. package/dist/src/server-handlers.d.ts +4 -0
  82. package/dist/src/table/badge-filter-utils.d.ts +8 -0
  83. package/dist/src/table/chat-components/TableOverviewCard.vue.d.ts +2 -7
  84. package/dist/src/table/chat-components/TableResultView.vue.d.ts +3 -7
  85. package/dist/src/table/components/TableDisplayCell.vue.d.ts +8 -0
  86. package/dist/src/table/components/columns/BadgeColumnSettings.vue.d.ts +9 -0
  87. package/dist/src/table/components/columns/ColumnColorSelect.vue.d.ts +11 -0
  88. package/dist/src/table/components/columns/ColumnDisplaySettings.vue.d.ts +9 -0
  89. package/dist/src/table/components/columns/ColumnTypeSelect.vue.d.ts +11 -0
  90. package/dist/src/table/components/columns/ColumnValueSourceInput.vue.d.ts +15 -0
  91. package/dist/src/table/components/columns/DialogTableColumnItem.vue.d.ts +8 -11
  92. package/dist/src/table/components/columns/ProgressColumnSettings.vue.d.ts +8 -0
  93. package/dist/src/table/components/stats/StatDialog.vue.d.ts +6 -10
  94. package/dist/src/table/components/stats/Stats.vue.d.ts +9 -15
  95. package/dist/src/table/composables/useTableClock.d.ts +4 -0
  96. package/dist/src/table/display-utils.d.ts +35 -0
  97. package/dist/src/table/row-value.d.ts +1 -0
  98. package/dist/src/table/stat-utils.d.ts +9 -0
  99. package/dist/src/table/tool-utils.d.ts +1 -1
  100. package/dist/src/table/types.d.ts +54 -1
  101. package/dist/src/whatsappBusiness/analytics.d.ts +4 -0
  102. package/dist/src/whatsappBusiness/components/AccountPanel.vue.d.ts +2 -0
  103. package/dist/src/whatsappBusiness/components/InsightsPanel.vue.d.ts +5 -0
  104. package/dist/src/whatsappBusiness/components/TemplateDialog.vue.d.ts +14 -0
  105. package/dist/src/whatsappBusiness/components/TemplatesPanel.vue.d.ts +5 -0
  106. package/dist/src/whatsappBusiness/components/presentation.d.ts +4 -0
  107. package/dist/src/whatsappBusiness/config.d.ts +51 -0
  108. package/dist/src/whatsappBusiness/connection.d.ts +77 -0
  109. package/dist/src/whatsappBusiness/index.d.ts +63 -0
  110. package/dist/src/whatsappBusiness/index.vue.d.ts +5 -0
  111. package/dist/src/whatsappBusiness/metadata.d.ts +2 -0
  112. package/dist/src/whatsappBusiness/pages/Overview.vue.d.ts +2 -0
  113. package/dist/src/whatsappBusiness/permissions.d.ts +5 -0
  114. package/dist/src/whatsappBusiness/provider.d.ts +21 -0
  115. package/dist/src/whatsappBusiness/routes.d.ts +5 -0
  116. package/dist/src/whatsappBusiness/server.d.ts +14 -0
  117. package/dist/src/whatsappBusiness/templates.d.ts +94 -0
  118. package/dist/src/whatsappBusiness/types.d.ts +162 -0
  119. package/dist/{tool-sandbox-DoF1PsyS.js → tool-sandbox-BSkKdH7V.js} +1 -1
  120. package/dist/{tool-sandbox-DdkMLkDK.mjs → tool-sandbox-DU9b1B7v.mjs} +1 -1
  121. package/dist/{types-ibC3-e1N.mjs → types-B5MifmeF.mjs} +339 -273
  122. package/dist/types-D5dgTskW.js +1 -0
  123. package/dist/{useTableAgentTools-D5mzGf3A.js → useTableAgentTools-BrUot49I.js} +1 -1
  124. package/dist/{useTableAgentTools-DcN3kYRL.mjs → useTableAgentTools-r5InEI4p.mjs} +8 -8
  125. package/dist/{vee-validate-zod-BQElPD0m.js → vee-validate-zod-CWZwNTWE.js} +1 -1
  126. package/dist/{vee-validate-zod-CN16K2x9.mjs → vee-validate-zod-D0WaDgDZ.mjs} +1 -1
  127. package/package.json +2 -2
  128. package/src/appointments/tools.ts +52 -2
  129. package/dist/AppointmentListTable-DZJNmTMb.mjs +0 -177
  130. package/dist/AppointmentListTable-Dieu9US_.js +0 -1
  131. package/dist/ContentEditor-BcIUumah.js +0 -467
  132. package/dist/Detail-Byk781b4.mjs +0 -26
  133. package/dist/Detail-mvSGbnFU.js +0 -1
  134. package/dist/Overview-BDlBCUI_.js +0 -1
  135. package/dist/Overview-Su8ZUbMs.mjs +0 -26
  136. package/dist/TableDataWidget-7qvC3Egd.js +0 -1
  137. package/dist/TableDataWidget-DMTSoGRO.mjs +0 -121
  138. package/dist/TableOverviewCard-AFq-puJs.js +0 -1
  139. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-CBn-Oxl9.mjs +0 -534
  140. package/dist/TableResultView.vue_vue_type_script_setup_true_lang-C_Lv-SmJ.js +0 -1
  141. package/dist/TableRowActionCard-IzB6tNN-.js +0 -1
  142. package/dist/TableView-6mdrL3zx.js +0 -4
  143. package/dist/TableView-Du5nOE6R.mjs +0 -8228
  144. package/dist/TemplateList.vue_vue_type_script_setup_true_lang-B_AtWnHa.js +0 -1
  145. package/dist/TemplateList.vue_vue_type_script_setup_true_lang-Cmovy7kk.mjs +0 -40
  146. package/dist/dateRangePresets-B-l5b_wR.mjs +0 -48
  147. package/dist/dateRangePresets-CPWqst_x.js +0 -1
  148. package/dist/orders-DUa2PVoa.js +0 -1
  149. package/dist/types-BMraG1kN.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
+ };