🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@templatical/editor

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@templatical/editor - npm Package Compare versions

Comparing version
0.21.1
to
0.21.2
+1163
dist/cdn/chunks/CloudEditor-C0Y4RD4c.js
import { $ as e, A as t, H as n, J as r, M as i, N as a, P as o, V as s, Z as c, _ as l, b as u, ct as d, f, g as p, h as m, it as h, j as g, l as _, m as v, n as y, ot as b, p as x, s as S, st as C, u as w, v as T, x as E, y as D, z as O } from "./draggable-D840DIZB.js";
import { t as k } from "./timeouts-Bmi_yePw.js";
import { F as A } from "./src-BKI1x1k7.js";
import { T as j, b as M, j as N, t as P } from "./useEditorCore-BA6mspzD.js";
import { _ as F } from "./dist-CiBEt0VR.js";
import { t as I } from "./dist-CxTt8FRE.js";
import { A as L, F as R, c as z, r as B, s as V, t as H, u as ee } from "./keys-D7kUmfpE.js";
import { t as U } from "./useI18n-8Wd7G-cq.js";
import { At as W, Dt as G, F as te, Ft as K, P as q, et as J, j as ne, rt as Y, u as re, w as ie } from "./icons-CYWw8Xfp.js";
import { t as ae } from "./_plugin-vue_export-helper-B3ysoDQm.js";
import { n as X } from "./useCloudI18n-BjNENqkM.js";
import { a as Z, c as oe, d as se, f as Q, i as ce, l as le, n as ue, o as de, p as fe, r as pe, s as me, t as he, u as ge } from "./styles-DMOEiSX9.js";
import { d as $ } from "./ColorPicker-DZSzZ5ZP.js";
import { S as _e, _ as ve, a as ye, c as be, d as xe, f as Se, h as Ce, i as we, l as Te, m as Ee, n as De, o as Oe, r as ke, s as Ae, t as je, u as Me, v as Ne } from "./cloud-BJlbXGTJ.js";
//#region src/cloud/composables/useSnapshotPreview.ts
function Pe(t) {
let { authManager: n, editor: i, history: a, conditionPreview: o, autoSave: s, onError: l } = t, u = e(null), d = c(null), p = c(null), m = !1;
r(() => {
m = !0;
});
let h = f(() => d.value !== null), g = f(() => u.value?.snapshots.value ?? []), _ = f(() => u.value?.isLoading.value ?? !1), v = f(() => u.value?.isRestoring.value ?? !1);
function y() {
i.state.template?.id && !u.value && (u.value = Oe({
authManager: n,
templateId: i.state.template.id,
onRestore: b,
onError: l
}), u.value.loadSnapshots());
}
function b(e) {
i.setContent(e.content, !1), a.clear(), o.reset();
}
async function x(e) {
if (!m) {
if (d.value) {
d.value = e, i.setContent(e.content, !1);
return;
}
i.state.isDirty && i.hasTemplate() && (await i.createSnapshot(), m) || (p.value = structuredClone(i.content.value), s?.pause(), d.value = e, i.setContent(e.content, !1));
}
}
async function S() {
if (!(!d.value || !u.value)) try {
if (await u.value.restoreSnapshot(d.value.id), m || (await u.value.loadSnapshots(), m)) return;
} catch (e) {
throw !m && p.value && i.setContent(p.value, !1), e;
} finally {
m || (d.value = null, p.value = null, s?.resume());
}
}
function C() {
!d.value || !p.value || (i.setContent(p.value, !1), d.value = null, p.value = null, s?.resume());
}
async function w() {
m || u.value && await u.value.loadSnapshots();
}
return {
snapshotHistoryInstance: u,
previewingSnapshot: d,
contentBeforePreview: p,
isPreviewingSnapshot: h,
snapshotHistorySnapshots: g,
snapshotHistoryIsLoading: _,
snapshotHistoryIsRestoring: v,
initSnapshotHistory: y,
handleRestore: b,
handleSnapshotNavigate: x,
confirmRestoreSnapshot: S,
cancelPreview: C,
loadSnapshotHistory: w
};
}
//#endregion
//#region src/cloud/composables/useCloudPanelState.ts
function Fe() {
let e = c(null), t = f({
get: () => e.value === "ai-chat",
set: (t) => e.value = t ? "ai-chat" : null
}), n = f({
get: () => e.value === "scoring",
set: (t) => e.value = t ? "scoring" : null
}), r = f({
get: () => e.value === "design-reference",
set: (t) => e.value = t ? "design-reference" : null
}), i = f({
get: () => e.value === "comments",
set: (t) => e.value = t ? "comments" : null
}), a = c(!1), o = c(!1), s = c(void 0), l = c(!1), u = c(null), d = f(() => e.value !== null), p = f(() => {
let t = e.value;
return t === "ai-chat" || t === "design-reference" || t === "scoring" ? t : null;
}), m = f(() => l.value || e.value === "ai-chat" || e.value === "design-reference" || e.value === "scoring");
function h() {
l.value = !l.value;
}
function g(t) {
l.value = !1, e.value = e.value === t ? null : t;
}
return I(u, () => {
l.value = !1;
}), {
activePanel: e,
aiChatOpen: t,
scoringPanelOpen: n,
designReferenceOpen: r,
commentsOpen: i,
testEmailModalOpen: a,
mediaLibraryOpen: o,
mediaLibraryAccept: s,
aiMenuOpen: l,
aiMenuRef: u,
rightPanelOpen: d,
activeAiFeature: p,
aiButtonActive: m,
toggleAiMenu: h,
handleAiFeatureSelect: g
};
}
//#endregion
//#region src/cloud/composables/useCollabUndoWarning.ts
function Ie(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = c(!1), a = c(!1), { start: o } = F(() => {
a.value = !1;
}, k, { immediate: !1 });
function s() {
i.value || !t.value || n() === 0 || !r.value || (i.value = !0, a.value = !0, o());
}
return {
collabUndoWarningVisible: a,
showCollabUndoWarning: s
};
}
//#endregion
//#region src/cloud/composables/useCloudFeatureFlags.ts
function Le(e) {
let { planConfigInstance: t, aiConfig: n, editor: r } = e, i = f(() => t.hasFeature("ai_generation") && n.hasAnyMenuFeature.value), a = f(() => t.hasFeature("test_email")), o = f(() => !!r.state.template?.id), s = f(() => t.hasFeature("white_label")), l = f(() => t.config.value?.limits.max_templates ?? null), u = f(() => t.config.value?.template_count ?? 0), d = c(!1), p = c("idle"), m = c(""), { start: h } = F(() => {
p.value = "idle";
}, 3e3, { immediate: !1 });
return {
canUseAiGeneration: i,
canSendTestEmail: a,
hasTemplateSaved: o,
isWhiteLabeled: s,
templateLimit: l,
templateCount: u,
isSaveExporting: d,
saveStatus: p,
saveErrorMessage: m,
startSaveStatusClear: h
};
}
//#endregion
//#region src/cloud/composables/useCloudMediaLibrary.ts
function Re(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: i, authManager: a, getMediaConfig: o, onError: s } = e, c = null;
function l(e) {
return {
url: e.url,
alt: e.alt_text || void 0
};
}
async function u(e) {
let r = e?.accept ?? ["images"];
if (e?.files?.length) {
if (t) {
let n = await t({
accept: r,
files: e.files
});
return n ? l(n) : null;
}
return d(e.files[0]);
}
if (t) {
let e = await t({ accept: r });
return e ? l(e) : null;
}
return c &&= (c(null), null), i.value = r, n.value = !0, new Promise((e) => {
c = (t) => {
e(t);
};
});
}
async function d(e) {
let t = f(e);
if (t) return s?.(t), null;
try {
let { MediaApiClient: t } = await import("./src-D6F_3XkE.js");
return l(await new t(a).uploadMedia(e));
} catch (e) {
return s?.(e), null;
}
}
function f(e) {
let t = o?.() ?? null;
if (!t) return null;
let n = t.categories?.images?.mime_types ?? [];
return n.length > 0 && !n.includes(e.type) ? /* @__PURE__ */ Error(`Unsupported image type: ${e.type || "unknown"}. Accepted: ${n.join(", ")}.`) : t.max_file_size > 0 && e.size > t.max_file_size ? /* @__PURE__ */ Error(`Image is too large (${e.size} bytes). Maximum allowed is ${t.max_file_size} bytes.`) : null;
}
function p(e) {
n.value = !1, c?.(l(e)), c = null;
}
function m() {
n.value = !1, c?.(null), c = null;
}
return r(() => {
c &&= (c(null), null);
}), {
handleRequestMedia: u,
handleMediaSelect: p,
handleMediaLibraryClose: m
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function ze(e) {
let { config: t, translations: n, fontsManager: r, emit: i, getCommentsSidebar: o } = e, s = c(!0), l = c(!1), u = c(null), d = !1, p = { value: null }, m = null, h = null, g = new _e({
...t.auth,
onError: t.onError
}), _ = ke({
authManager: g,
onError: t.onError
}), v = c(/* @__PURE__ */ new Map()), y = ve({
authManager: g,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: v
}), b = be({
authManager: g,
onError: t.onError
});
t.mcp?.enabled && je({
editor: y,
channel: b.channel,
onOperation: t.mcp.onOperation
});
let x = null;
t.collaboration?.enabled && (x = Me({
authManager: g,
editor: y,
channel: b.channel,
onError: t.onError,
onCollaboratorJoined: t.collaboration.onCollaboratorJoined,
onCollaboratorLeft: t.collaboration.onCollaboratorLeft,
onBlockLocked: t.collaboration.onBlockLocked,
onBlockUnlocked: t.collaboration.onBlockUnlocked
}), O(() => x.lockedBlocks.value, (e) => {
v.value = e;
}, { immediate: !0 }), Te(y, x));
let S = f(() => !!t.collaboration?.enabled && _.hasFeature("collaboration")), C = P({
editor: y,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
templateDefaults: t.templateDefaults,
customBlocks: [],
paletteBlocks: t.paletteBlocks,
htmlBlockPreview: t.htmlBlockPreview,
colors: t.colors,
mergeTags: t.mergeTags,
logicTags: t.logicTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: Q(t),
onSave: () => {
p.value?.().catch((e) => {
t.onError?.(e);
});
}
},
translations: n,
fontsManager: r,
historyOptions: x ? { isRemoteOperation: () => x._isProcessingRemoteOperation() } : void 0,
autoSaveOptions: {
onChange: async () => {
y.hasTemplate() && (await y.createSnapshot(), m?.snapshotHistoryInstance.value?.loadSnapshots());
},
debounce: t.autoSaveDebounce ?? 5e3,
enabled: () => t.autoSave !== !1 && _.hasFeature("auto_save")
},
themeExtraStyles: () => ({ "--tpl-drop-text": `"${n.canvas.dropHere}"` }),
keyboardOptions: { onBeforeUndo: () => h?.showCollabUndoWarning() },
editorRoot: e.editorRoot,
containerEl: e.containerEl
}), w = Ie({
isCollaborationEnabled: S,
getCollaboratorCount: () => x?.collaborators.value.length ?? 0,
canUndo: C.history.canUndo
});
h = w;
let T = Pe({
authManager: g,
editor: y,
history: C.history,
conditionPreview: C.conditionPreview,
autoSave: C.autoSave,
onError: t.onError
});
m = T;
let E = Fe(), D = Ce(t.ai), k = Le({
planConfigInstance: _,
aiConfig: D,
editor: y
}), A = Re({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: E.mediaLibraryOpen,
mediaLibraryAccept: E.mediaLibraryAccept,
authManager: g,
getMediaConfig: () => _.config.value?.media ?? null,
onError: t.onError
});
j({
onBlockMove: y.moveBlock,
onBlockAdd: y.addBlock
});
let M = we({
authManager: g,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => _.hasFeature("custom_fonts")
}), F = ye({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null,
save: () => y.save(),
exportHtml: (e) => M.exportHtml(e),
onError: t.onError,
isAuthReady: l,
onBeforeTestEmail: t.onBeforeTestEmail
}), I = Se({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null,
getSocketId: () => b.getSocketId(),
onComment: t.onComment,
onError: t.onError,
isAuthReady: l,
hasCommentingFeature: () => t.commenting !== !1 && _.hasFeature("commenting")
});
xe({
comments: I,
channel: b.channel
});
let z = typeof t.savedBlocks == "object" && t.savedBlocks !== null ? t.savedBlocks : null, U = fe({
provider: z ?? Ae(g),
editor: y,
onError: t.onError,
isAvailable: z ? () => !0 : () => t.savedBlocks !== !1 && _.hasFeature("saved_modules")
}), W = Ee({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null
});
function G(e) {
E.commentsOpen.value = !0, queueMicrotask(() => {
o()?.filterByBlock(e);
});
}
a(L, A.handleRequestMedia), a(B, g), a(H, D), a(ee, I), a(R, W), a(V, {
plan: _,
ai: D,
comments: {
getBlockCount: (e) => I.commentCountByBlock.value.get(e) ?? 0,
openForBlock: G
},
savedBlocks: U.capability
});
function te(e) {
_.hasFeature("theme_customization") && (C.themeOverrides.value = e);
}
function K(e) {
y.setUiTheme(e);
}
async function q() {
s.value = !0, u.value = null;
try {
if (await g.initialize(), d) return;
l.value = !0;
let e = await De({ authManager: g });
if (d) return;
if (!e.api.ok) throw Error("Health check failed: API is not reachable");
if (!e.auth.ok) throw Error(`Health check failed: authentication error${e.auth.error ? ` - ${e.auth.error}` : ""}`);
if (e.websocket.ok || N.warn("WebSocket health check failed:", e.websocket.error ?? "unknown error", "-- real-time features will be disabled."), await _.fetchConfig(), d) return;
r.setCustomFontsEnabled(_.hasFeature("custom_fonts")), t.customBlocks?.length && _.hasFeature("custom_blocks") && C.registerCustomBlocks(t.customBlocks), t.theme && _.hasFeature("theme_customization") && (C.themeOverrides.value = t.theme), i("ready");
} catch (e) {
if (d) return;
let n = e instanceof Error ? e : Error("Initialization failed", { cause: e });
u.value = n, t.onError?.(n);
} finally {
d || (s.value = !1);
}
}
function J() {
d = !0, r.cleanupFontLinks(), b.disconnect(), C.destroy(), t.onUnmount?.();
}
return {
isInitializing: s,
isAuthReady: l,
initError: u,
isDestroyed: () => d,
authManager: g,
planConfigInstance: _,
websocket: b,
collaboration: x,
isCollaborationEnabled: S,
editor: y,
core: C,
aiConfig: D,
featureFlags: k,
mediaLib: A,
exporter: M,
testEmail: F,
commentsInstance: I,
savedBlocks: U,
scoringInstance: W,
panelState: E,
snapshotPreview: T,
collabWarning: w,
onSaveHook: p,
initialize: q,
destroy: J,
setThemeOverrides: te,
setUiTheme: K,
openCommentsForBlock: G
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Be(e, t) {
let n = async (e) => {
if (A(e)) {
let n = e;
try {
n.renderedHtml = await t.renderCustomBlock(n);
} catch {
n.renderedHtml = `<!-- Custom block render error: ${n.customType} -->`;
}
}
if (e.type === "section" && "children" in e) {
let t = e;
for (let e of t.children) for (let t of e) await n(t);
}
};
for (let t of e.blocks) await n(t);
}
//#endregion
//#region src/cloud/composables/useCloudLifecycle.ts
function Ve(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return Ne(i.config.value.websocket);
}
async function d(e) {
let i = await n.create(e);
return l() ? i : (t.onCreate?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function f(e) {
let i = await n.load(e);
return l() ? i : (t.onLoad?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function p() {
c.isSaveExporting.value = !0, c.saveStatus.value = "idle";
try {
if (await Be(n.content.value, o.registry), l()) throw Error("Component unmounted during save");
let e = await n.save();
if (l()) throw Error("Component unmounted during save");
a.initSnapshotHistory(), a.snapshotHistoryInstance.value?.loadSnapshots();
let r = await s.exportHtml(e.id);
if (l()) throw Error("Component unmounted during save");
let i = {
templateId: e.id,
html: r.html,
mjml: r.mjml,
content: e.content
};
return t.onSave?.(i), c.saveStatus.value = "saved", c.startSaveStatusClear(), i;
} catch (e) {
throw l() || (c.saveStatus.value = "error", c.saveErrorMessage.value = e instanceof Error ? e.message : "Save failed"), e;
} finally {
l() || (c.isSaveExporting.value = !1);
}
}
return {
createTemplate: d,
loadTemplate: f,
saveTemplate: p
};
}
//#endregion
//#region src/cloud/composables/useCloudSaveGate.ts
function He(e) {
let t = c(!1), n = null, r = f(() => e.planConfig.value?.accessibility?.blockOnError === !0), i = f(() => r.value ? e.issues.value.filter((e) => e.severity === "error") : []), a = f(() => i.value.length > 0);
async function o(e) {
return a.value ? (n = e, t.value = !0, !1) : (await e(), !0);
}
async function s() {
let e = n;
n = null, t.value = !1, e && await e();
}
function l() {
n = null, t.value = !1;
}
return {
shouldBlock: a,
blockingIssues: i,
modalOpen: t,
tryRunSave: o,
confirmAndSave: s,
cancel: l
};
}
//#endregion
//#region src/cloud/components/CloudSaveGateModal.vue?vue&type=script&setup=true&lang.ts
var Ue = ["aria-label"], We = { class: "tpl:flex tpl:max-h-[80vh] tpl:w-full tpl:max-w-md tpl:flex-col tpl:gap-4 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:p-5 tpl:shadow-[var(--tpl-shadow-md)]" }, Ge = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Ke = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, qe = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Je = { class: "tpl:m-0 tpl:flex tpl:max-h-64 tpl:list-none tpl:flex-col tpl:gap-1.5 tpl:overflow-y-auto tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2" }, Ye = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, Xe = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Ze = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, Qe = /* @__PURE__ */ E({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = X();
return (t, a) => (i(), v(y, {
"enter-active-class": "tpl:transition-opacity tpl:duration-150",
"leave-active-class": "tpl:transition-opacity tpl:duration-150",
"enter-from-class": "tpl:opacity-0",
"leave-to-class": "tpl:opacity-0"
}, {
default: s(() => [e.open ? (i(), p("div", {
key: 0,
role: "dialog",
"aria-modal": "true",
"aria-label": h(r).saveGate.title,
class: "tpl:fixed tpl:inset-0 tpl:z-50 tpl:flex tpl:items-center tpl:justify-center tpl:bg-black/40 tpl:p-6",
onClick: a[2] ||= _((e) => n("cancel"), ["self"])
}, [x("div", We, [
x("header", Ge, [D(h(re), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), x("h2", Ke, d(h(r).saveGate.title), 1)]),
x("p", qe, d(h(r).saveGate.body), 1),
x("ul", Je, [(i(!0), p(w, null, o(e.issues, (e) => (i(), p("li", {
key: `${e.ruleId}-${e.blockId ?? "template"}`,
class: "tpl:flex tpl:flex-col tpl:gap-0.5 tpl:rounded tpl:px-2 tpl:py-1.5"
}, [x("span", Ye, d(e.message), 1), x("span", Xe, d(e.ruleId), 1)]))), 128))]),
x("footer", Ze, [x("button", {
type: "button",
class: "tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]",
onClick: a[0] ||= (e) => n("cancel")
}, d(h(r).saveGate.cancel), 1), x("button", {
type: "button",
class: "tpl:rounded-md tpl:bg-[var(--tpl-danger)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-white",
onClick: a[1] ||= (e) => n("confirm")
}, d(h(r).saveGate.confirm), 1)])
])], 8, Ue)) : m("", !0)]),
_: 1
}));
}
}), $e = {
class: "tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4",
style: {
"background-color": "color-mix(in srgb, var(--tpl-bg) 80%, transparent)",
"backdrop-filter": "blur(12px)",
"-webkit-backdrop-filter": "blur(12px)",
"box-shadow": "var(--tpl-shadow-md)",
"border-bottom": "1px solid var(--tpl-border)"
}
}, et = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, tt = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, nt = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, rt = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, it = ["data-tooltip"], at = {
key: 1,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-success)]"
}, ot = {
key: 2,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-text-muted)]"
}, st = ["aria-label", "aria-expanded"], ct = {
key: 0,
class: "tpl:inline-flex tpl:size-4.5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:text-[10px] tpl:font-semibold tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]"
}, lt = ["aria-expanded"], ut = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, dt = ["disabled"], ft = ["disabled"], pt = /* @__PURE__ */ E({
__name: "CloudHeader",
props: {
editor: {},
core: {},
featureFlags: {},
panelState: {},
snapshotPreview: {},
commentsInstance: {},
testEmail: {},
websocket: {},
collaboration: {},
isCollaborationEnabled: { type: Boolean },
isSaveDisabled: { type: Boolean },
isSaving: { type: Boolean }
},
emits: ["save"],
setup(e) {
let t = u(() => import("./CollaboratorBar-BS3rJy6-.js")), n = u(() => import("./SnapshotHistory-Bf1uovti.js")), r = u(() => import("./AiFeatureMenu-Duwg413F.js")), { t: a, format: o } = X();
return (c, l) => (i(), p("header", $e, [
x("div", et, [e.featureFlags.templateLimit.value === null ? m("", !0) : (i(), p("span", tt, d(h(o)(h(a).header.templatesUsed, {
used: e.featureFlags.templateCount.value,
max: e.featureFlags.templateLimit.value
})), 1))]),
x("div", nt, [
D(de, {
viewport: e.editor.state.viewport,
onChange: e.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
D(ce, {
"dark-mode": e.editor.state.darkMode,
onChange: e.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
D(Z, {
"preview-mode": e.editor.state.previewMode,
onChange: e.editor.setPreviewMode
}, null, 8, ["preview-mode", "onChange"]),
e.collaboration && e.isCollaborationEnabled ? (i(), v(h(t), {
key: 0,
collaborators: e.collaboration.collaborators.value,
"is-connected": e.websocket.isConnected.value
}, null, 8, ["collaborators", "is-connected"])) : m("", !0),
e.snapshotPreview.snapshotHistoryInstance.value ? (i(), v(h(n), {
key: 1,
snapshots: e.snapshotPreview.snapshotHistorySnapshots.value,
"is-loading": e.snapshotPreview.snapshotHistoryIsLoading.value,
"is-restoring": e.snapshotPreview.snapshotHistoryIsRestoring.value,
onLoad: e.snapshotPreview.loadSnapshotHistory,
onNavigate: e.snapshotPreview.handleSnapshotNavigate
}, null, 8, [
"snapshots",
"is-loading",
"is-restoring",
"onLoad",
"onNavigate"
])) : m("", !0)
]),
x("div", rt, [
e.featureFlags.saveStatus.value === "error" ? (i(), p("div", {
key: 0,
"aria-live": "assertive",
class: "tpl-tooltip tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-danger)]",
"data-tooltip": e.featureFlags.saveErrorMessage.value
}, [D(h(W), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saveFailed), 1)], 8, it)) : e.featureFlags.saveStatus.value === "saved" ? (i(), p("div", at, [D(h(K), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saved), 1)])) : e.editor.state.isDirty ? (i(), p("div", ot, [l[4] ||= x("span", { class: "tpl-pulse tpl:size-1.5 tpl:rounded-full tpl:bg-[var(--tpl-primary)]" }, null, -1), T(" " + d(h(a).header.unsaved), 1)])) : m("", !0),
e.commentsInstance.isEnabled.value && e.featureFlags.hasTemplateSaved.value ? (i(), p("button", {
key: 3,
"aria-label": e.commentsInstance.unresolvedCount.value > 0 ? `${h(a).comments.button} (${e.commentsInstance.unresolvedCount.value})` : h(a).comments.button,
"aria-expanded": e.panelState.commentsOpen.value,
class: b(h($)),
style: C({
backgroundColor: e.panelState.commentsOpen.value ? "var(--tpl-primary)" : "transparent",
color: e.panelState.commentsOpen.value ? "var(--tpl-bg)" : "var(--tpl-primary)",
borderColor: "var(--tpl-primary)"
}),
onClick: l[0] ||= (t) => e.panelState.commentsOpen.value = !e.panelState.commentsOpen.value
}, [
D(h(J), {
size: 16,
"stroke-width": 2
}),
T(" " + d(h(a).comments.button) + " ", 1),
e.commentsInstance.unresolvedCount.value > 0 && !e.panelState.commentsOpen.value ? (i(), p("span", ct, d(e.commentsInstance.unresolvedCount.value), 1)) : m("", !0)
], 14, st)) : m("", !0),
e.featureFlags.canUseAiGeneration.value && e.featureFlags.hasTemplateSaved.value ? (i(), p("div", {
key: 4,
ref: (t) => e.panelState.aiMenuRef.value = t,
class: "tpl:relative"
}, [x("button", {
"aria-expanded": e.panelState.aiMenuOpen.value,
class: b(["tpl-ai-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-4 tpl:py-2 tpl:text-sm tpl:font-semibold tpl:whitespace-nowrap tpl:transition-all tpl:duration-200", e.panelState.aiButtonActive.value ? "tpl-ai-btn--active" : "tpl-ai-btn--idle"]),
onClick: l[1] ||= _((...t) => e.panelState.toggleAiMenu && e.panelState.toggleAiMenu(...t), ["stop"])
}, [D(h(ie), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), T(" " + d(h(a).aiChat.button), 1)], 10, lt), D(y, {
"enter-active-class": "tpl:transition-all tpl:duration-150 tpl:ease-out",
"enter-from-class": "tpl:scale-95 tpl:opacity-0",
"enter-to-class": "tpl:scale-100 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-100 tpl:ease-in",
"leave-from-class": "tpl:scale-100 tpl:opacity-100",
"leave-to-class": "tpl:scale-95 tpl:opacity-0"
}, {
default: s(() => [e.panelState.aiMenuOpen.value ? (i(), p("div", ut, [D(h(r), {
"active-feature": e.panelState.activeAiFeature.value,
onSelect: e.panelState.handleAiFeatureSelect
}, null, 8, ["active-feature", "onSelect"])])) : m("", !0)]),
_: 1
})], 512)) : m("", !0),
e.testEmail.isEnabled.value && e.featureFlags.canSendTestEmail.value ? (i(), p("button", {
key: 5,
class: b(h($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.testEmail.isSending.value || !e.featureFlags.hasTemplateSaved.value,
onClick: l[2] ||= (t) => e.panelState.testEmailModalOpen.value = !0
}, [e.testEmail.isSending.value ? (i(), v(h(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(ne), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(h(a).testEmail.button), 1)], 10, dt)) : m("", !0),
x("button", {
class: b(h($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.isSaveDisabled,
onClick: l[3] ||= (e) => c.$emit("save")
}, [e.isSaving ? (i(), v(h(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(q), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(e.isSaving ? h(a).header.saving : h(a).header.save), 1)], 10, ft)
])
]));
}
}), mt = /* @__PURE__ */ E({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {}
},
emits: ["send-test-email"],
setup(e, { expose: t, emit: n }) {
let r = u(() => import("./AiChatSidebar-A1CuWGY0.js")), a = u(() => import("./CommentsSidebar-DHdRiGPX.js")), o = u(() => import("./DesignReferenceSidebar-Dre99DTH.js")), s = u(() => import("./TemplateScoringPanel-CTk8WwxU.js")), l = u(() => import("./TestEmailModal-BJTDxFHh.js")), d = u(async () => {
try {
return (await import("./src-D6F_3XkE.js")).MediaLibraryModal;
} catch {
throw Error("[Templatical] Cloud media library requires the optional peer dependency '@templatical/media-library'. Please install it.");
}
}), f = n;
function m(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
let g = c(null);
function _(e) {
g.value?.filterByBlock(e);
}
return t({ filterCommentsByBlock: _ }), (t, n) => (i(), p(w, null, [
D(h(r), {
visible: e.panelState.aiChatOpen.value,
"on-apply": (t) => m(t, e.core, e.editor),
onClose: n[0] ||= (t) => e.panelState.aiChatOpen.value = !1
}, null, 8, ["visible", "on-apply"]),
D(h(s), {
visible: e.panelState.scoringPanelOpen.value,
onClose: n[1] ||= (t) => e.panelState.scoringPanelOpen.value = !1
}, null, 8, ["visible"]),
D(h(o), {
visible: e.panelState.designReferenceOpen.value,
"has-existing-blocks": e.editor.content.value.blocks.length > 0,
onClose: n[2] ||= (t) => e.panelState.designReferenceOpen.value = !1,
onApply: n[3] ||= (t) => m(t, e.core, e.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
D(h(a), {
ref_key: "commentsSidebar",
ref: g,
visible: e.panelState.commentsOpen.value,
onClose: n[4] ||= (t) => e.panelState.commentsOpen.value = !1
}, null, 8, ["visible"]),
D(h(l), {
visible: e.panelState.testEmailModalOpen.value,
"allowed-emails": e.testEmail.allowedEmails.value,
"is-sending": e.testEmail.isSending.value,
error: e.testEmail.error.value,
onSend: n[5] ||= (e) => f("send-test-email", e),
onClose: n[6] ||= (t) => e.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
D(h(d), {
visible: e.panelState.mediaLibraryOpen.value,
accept: e.panelState.mediaLibraryAccept.value,
"popover-target": e.core.popoverRoot.value,
onSelect: e.mediaLib.handleMediaSelect,
onClose: e.mediaLib.handleMediaLibraryClose
}, null, 8, [
"visible",
"accept",
"popover-target",
"onSelect",
"onClose"
])
], 64));
}
}), ht = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, gt = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, _t = { class: "tpl:flex tpl:w-12 tpl:shrink-0 tpl:flex-col tpl:items-center tpl:gap-4 tpl:py-5 tpl:border-r tpl:border-[var(--tpl-border)]" }, vt = /* @__PURE__ */ E({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(e) {
return (t, n) => e.visible ? (i(), p("div", ht, [n[1] ||= l("<div class=\"tpl:flex tpl:h-14 tpl:shrink-0 tpl:items-center tpl:justify-between tpl:px-4 tpl:border-b tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-5 tpl:w-28 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl:flex tpl:gap-3\"><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div></div>", 1), x("div", gt, [x("div", _t, [(i(), p(w, null, o(5, (e) => x("div", {
key: e,
class: "tpl-shimmer tpl:size-7 tpl:rounded-[var(--tpl-radius-sm)]"
})), 64))]), n[0] ||= l("<div class=\"tpl:flex tpl:flex-1 tpl:items-start tpl:justify-center tpl:overflow-auto tpl:p-8 tpl:bg-[var(--tpl-canvas-bg)]\"><div class=\"tpl:w-full tpl:max-w-[600px] tpl:rounded-[var(--tpl-radius)] tpl:p-6 tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)]\"><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-3/4 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-5/6 tpl:rounded\"></div></div><div class=\"tpl:py-4\"><div class=\"tpl-shimmer tpl:h-44 tpl:w-full tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-2/3 tpl:rounded\"></div></div><div class=\"tpl:flex tpl:justify-center tpl:py-4\"><div class=\"tpl-shimmer tpl:h-10 tpl:w-36 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/2 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/3 tpl:rounded\"></div></div></div></div><div class=\"tpl:flex tpl:w-[320px] tpl:shrink-0 tpl:flex-col tpl:gap-4 tpl:p-4 tpl:border-l tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-8 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div></div>", 2)])])) : m("", !0);
}
}), yt = {
key: 0,
role: "alert",
class: "tpl-error tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-6 tpl:px-8 tpl:bg-[var(--tpl-bg)]"
}, bt = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, xt = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, St = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, Ct = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, wt = /* @__PURE__ */ E({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(e, { emit: t }) {
let n = t, { t: r } = X();
function a(e) {
return "isUnauthorized" in e && e.isUnauthorized ? r.error.authFailed : "isNotFound" in e && e.isNotFound ? r.error.templateNotFound : r.error.defaultMessage;
}
function o(e) {
return "isNotFound" in e && !!e.isNotFound;
}
return (t, s) => e.visible && e.error ? (i(), p("div", yt, [
x("div", bt, [D(h(W), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
x("div", xt, [x("h2", St, d(h(r).error.title), 1), x("p", Ct, d(a(e.error)), 1)]),
o(e.error) ? m("", !0) : (i(), p("button", {
key: 0,
class: "tpl-btn tpl-btn-primary tpl:inline-flex tpl:items-center tpl:gap-2 tpl:rounded-md tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: s[0] ||= (e) => n("retry")
}, d(h(r).error.retry), 1))
])) : m("", !0);
}
}), Tt = {
key: 0,
class: "tpl-preview-banner tpl:absolute tpl:top-14 tpl:right-0 tpl:left-0 tpl:z-40 tpl:flex tpl:items-center tpl:justify-center tpl:gap-4 tpl:px-4 tpl:py-3 tpl:bg-[var(--tpl-primary-light)] tpl:border-b tpl:border-[var(--tpl-primary)]"
}, Et = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, Dt = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Ot = /* @__PURE__ */ E({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = X();
return (t, a) => e.visible ? (i(), p("div", Tt, [x("div", Et, [D(h(G), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), x("span", null, d(h(r).snapshotPreview.message), 1)]), x("div", Dt, [x("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:text-[var(--tpl-text-muted)] tpl:border tpl:border-[var(--tpl-border)]",
style: { "background-color": "transparent" },
onClick: a[0] ||= (e) => n("cancel")
}, d(h(r).snapshotPreview.cancel), 1), x("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: a[1] ||= (e) => n("confirm")
}, d(h(r).snapshotPreview.restore), 1)])])) : m("", !0);
}
}), kt = {
key: 0,
role: "status",
"aria-live": "polite",
class: "tpl:absolute tpl:top-16 tpl:left-1/2 tpl:z-toast tpl:-translate-x-1/2 tpl:rounded-[var(--tpl-radius)] tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:shadow-lg",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-text)",
border: "1px solid var(--tpl-warning)"
}
}, At = /* @__PURE__ */ E({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(e) {
let { t } = U();
return (n, r) => e.visible ? (i(), p("div", kt, d(h(t).history.collabWarning), 1)) : m("", !0);
}
}), jt = ["data-tpl-theme"], Mt = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, Nt = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, Pt = ["aria-label"], Ft = /*#__PURE__*/ ae(/* @__PURE__ */ E({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(e, { expose: r, emit: o }) {
let l = u(() => import("./SavedBlocksPanels-D-pA_wfk.js")), f = e;
a(z, f.cloudTranslations);
let w = o, E = c(null), O = c(null), k = ze({
config: f.config,
translations: f.translations,
fontsManager: f.fontsManager,
emit: w,
getCommentsSidebar: () => E.value ? { filterByBlock: E.value.filterCommentsByBlock } : null,
editorRoot: f.shadowRoot,
containerEl: O
}), { isInitializing: A, isAuthReady: j, initError: N, planConfigInstance: P, websocket: F, collaboration: I, isCollaborationEnabled: L, editor: R, core: B, featureFlags: V, mediaLib: H, exporter: ee, testEmail: U, commentsInstance: W, savedBlocks: G, panelState: K, snapshotPreview: q, collabWarning: J, setThemeOverrides: ne, setUiTheme: Y } = k, { showNotice: re } = M(() => f.config.smallScreenNotice);
async function ie(e) {
try {
await U.sendTestEmail(e), K.testEmailModalOpen.value = !1;
} catch {}
}
async function ae() {
try {
await q.confirmRestoreSnapshot();
} catch {}
}
let X = Ve({
config: f.config,
editor: R,
websocket: F,
planConfigInstance: P,
snapshotPreview: q,
core: B,
exporter: ee,
featureFlags: V,
isDestroyed: k.isDestroyed
}), Z = He({
issues: B.templateLint ? B.templateLint.issues : c([]),
planConfig: P.config
});
async function Q() {
await Z.tryRunSave(() => X.saveTemplate().catch((e) => f.config.onError?.(e)));
}
return k.onSaveHook.value = Q, t(() => {
k.initialize();
}), g(() => {
k.destroy();
}), r({
getContent: () => R.content.value,
setContent: (e) => R.setContent(e),
setTheme: Y,
setThemeOverrides: ne,
create: X.createTemplate,
load: X.loadTemplate,
save: X.saveTemplate,
sendTestEmail: U.sendTestEmail
}), (t, r) => (i(), p("div", {
ref_key: "rootEl",
ref: O,
class: b(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": h(R).state.darkMode }]),
"data-tpl-theme": h(B).resolvedTheme.value,
style: C(h(B).themeStyles.value),
onDragover: r[6] ||= _(() => {}, ["prevent"]),
onDrop: r[7] ||= _(() => {}, ["prevent"])
}, [
D(ge),
D(y, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-100",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: s(() => [D(vt, { visible: h(A) || h(R).state.isLoading }, null, 8, ["visible"])]),
_: 1
}),
D(y, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-0",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: s(() => [D(wt, {
error: h(N),
visible: !!h(N) && !h(A),
onRetry: h(k).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
D(pt, {
editor: h(R),
core: h(B),
"feature-flags": h(V),
"panel-state": h(K),
"snapshot-preview": h(q),
"comments-instance": h(W),
"test-email": h(U),
websocket: h(F),
collaboration: h(I),
"is-collaboration-enabled": h(L),
"is-saving": h(R).state.isSaving || h(V).isSaveExporting.value,
"is-save-disabled": h(R).state.isSaving || h(V).isSaveExporting.value || !h(R).state.isDirty,
onSave: Q
}, null, 8, [
"editor",
"core",
"feature-flags",
"panel-state",
"snapshot-preview",
"comments-instance",
"test-email",
"websocket",
"collaboration",
"is-collaboration-enabled",
"is-saving",
"is-save-disabled"
]),
D(Qe, {
open: h(Z).modalOpen.value,
issues: h(Z).blockingIssues.value,
onCancel: h(Z).cancel,
onConfirm: h(Z).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
D(Ot, {
visible: h(q).isPreviewingSnapshot.value,
onCancel: h(q).cancelPreview,
onConfirm: ae
}, null, 8, ["visible", "onCancel"]),
D(y, {
"enter-active-class": "tpl:transition-all tpl:duration-200 tpl:ease-out",
"enter-from-class": "tpl:translate-y-[-8px] tpl:opacity-0",
"enter-to-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-300 tpl:ease-in",
"leave-from-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-to-class": "tpl:translate-y-[-8px] tpl:opacity-0"
}, {
default: s(() => [D(At, { visible: h(J).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
n(D(le, null, null, 512), [[S, !h(R).state.previewMode]]),
x("div", {
class: b(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [h(R).state.previewMode ? "tpl:left-0 tpl:right-0" : h(K).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", h(q).isPreviewingSnapshot.value ? "tpl:top-[104px]" : "tpl:top-14"]]),
style: {
transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
"background-color": "var(--tpl-canvas-bg)"
}
}, [x("div", Mt, [D(y, { name: "tpl-restore-btn" }, {
default: s(() => [h(B).conditionPreview.hasHiddenBlocks.value ? (i(), p("button", {
key: 0,
class: "tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-warning)",
"border-color": "var(--tpl-warning)",
"backdrop-filter": "blur(8px)"
},
onClick: r[0] ||= (e) => h(B).conditionPreview.reset()
}, [D(h(te), {
size: 13,
"stroke-width": 2
}), T(" " + d(h(B).t.blockSettings.restoreHiddenBlocks), 1)])) : m("", !0)]),
_: 1
})]), x("main", Nt, [D(se, {
viewport: h(R).state.viewport,
content: h(R).content.value,
"selected-block-id": h(R).state.selectedBlockId,
"dark-mode": h(R).state.darkMode,
"preview-mode": h(R).state.previewMode,
"locked-blocks": h(I)?.lockedBlocks.value ?? void 0,
onSelectBlock: h(R).selectBlock,
onOpenAiChat: r[1] ||= (e) => h(K).aiChatOpen.value = !0,
onOpenDesignReference: r[2] ||= (e) => h(K).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
e.config.branding !== !1 && !h(V).isWhiteLabeled.value ? (i(), v(pe, {
key: 0,
"position-class": [h(R).state.previewMode ? "tpl:left-0 tpl:right-0" : h(K).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]"]
}, null, 8, ["position-class"])) : m("", !0),
x("div", {
class: "tpl-sr-only",
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
"aria-label": h(B).t.landmarks.reorderAnnouncements
}, d(h(B).keyboardReorder.announcement.value), 9, Pt),
n(D(oe, {
"selected-block": h(R).selectedBlock.value,
settings: h(R).content.value.settings,
"shifted-left": h(K).rightPanelOpen.value,
onUpdateBlock: r[3] ||= (e) => h(R).updateBlock(h(R).selectedBlock.value.id, e),
onDeleteBlock: r[4] ||= (e) => h(B).blockActions.deleteBlock(h(R).selectedBlock.value.id),
onDuplicateBlock: r[5] ||= (e) => h(B).blockActions.duplicateBlock(h(R).selectedBlock.value),
onUpdateSettings: h(R).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[S, !h(R).state.previewMode]]),
!h(A) && h(j) ? (i(), v(mt, {
key: 1,
ref_key: "cloudPanelsRef",
ref: E,
config: f.config,
editor: h(R),
core: h(B),
"panel-state": h(K),
"plan-config-instance": h(P),
"test-email": h(U),
"media-lib": h(H),
onSendTestEmail: ie
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib"
])) : m("", !0),
h(G).isAvailable.value ? (i(), v(h(l), {
key: 2,
feature: h(G)
}, null, 8, ["feature"])) : m("", !0),
x("div", {
ref: (e) => h(B).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
D(ue),
D(he),
h(re) ? (i(), v(me, { key: 3 })) : m("", !0)
], 46, jt));
}
}), [["__scopeId", "data-v-04940787"]]);
//#endregion
export { Ft as default };
//# sourceMappingURL=CloudEditor-C0Y4RD4c.js.map

Sorry, the diff of this file is too big to display

import { B as e, F as t, G as n, H as r, I as i, J as a, K as o, L as s, P as c, R as l, U as u, V as d, W as f, z as p } from "./src-BKI1x1k7.js";
//#endregion
//#region ../renderer/src/render-context.ts
var m = `https://cdn.jsdelivr.net/npm/@templatical/renderer@${{
name: "@templatical/renderer",
description: "Render Templatical email templates to MJML",
version: "0.21.2",
bugs: "https://github.com/templatical/sdk/issues",
dependencies: { "@templatical/types": "workspace:*" },
devDependencies: {
"@resvg/resvg-js": "^2.6.2",
mjml: "^5.4.0",
typescript: "^6.0.3",
vitest: "^4.1.10"
},
exports: { ".": {
types: "./dist/index.d.ts",
import: "./dist/index.js"
} },
files: ["dist", "assets"],
homepage: "https://templatical.com",
keywords: [
"email",
"email-template",
"html-email",
"mjml",
"renderer",
"templatical"
],
license: "MIT",
module: "./dist/index.js",
publishConfig: { access: "public" },
repository: {
type: "git",
url: "git+https://github.com/templatical/sdk.git",
directory: "packages/renderer"
},
scripts: {
build: "tsdown && node scripts/rasterize-social.mjs",
test: "vitest run --config vitest.config.ts",
typecheck: "tsc --noEmit"
},
type: "module",
types: "./dist/index.d.ts"
}.version}/assets/social`, h = {
arial: "Arial, sans-serif",
helvetica: "Helvetica, sans-serif",
georgia: "Georgia, serif",
"times new roman": "'Times New Roman', serif",
verdana: "Verdana, sans-serif",
"trebuchet ms": "'Trebuchet MS', sans-serif",
"courier new": "'Courier New', monospace",
tahoma: "Tahoma, sans-serif"
}, g = class e {
containerWidth;
customFonts;
defaultFallbackFont;
allowHtmlBlocks;
customBlockHtml;
socialIconsBaseUrl;
constructor(e, t, n, r, i = /* @__PURE__ */ new Map(), a = m) {
this.containerWidth = e, this.customFonts = t, this.defaultFallbackFont = n, this.allowHtmlBlocks = r, this.customBlockHtml = i, this.socialIconsBaseUrl = a;
}
withContainerWidth(t) {
return new e(t, this.customFonts, this.defaultFallbackFont, this.allowHtmlBlocks, this.customBlockHtml, this.socialIconsBaseUrl);
}
resolveFontFamily(e) {
for (let t of this.customFonts) if (t.name.toLowerCase() === e.toLowerCase()) {
let e = t.fallback ?? this.defaultFallbackFont;
return `'${t.name}', ${e}`;
}
return h[e.toLowerCase()] || e;
}
}, _ = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
"\"": "&quot;",
"'": "&#039;"
}, v = /[&<>"']/g;
function y(e) {
return e === "" ? "" : e.replace(v, (e) => _[e] ?? e);
}
function b(e) {
return e === "" ? "" : e.replace(v, (e) => _[e] ?? e);
}
function x(e) {
return e === "" ? "" : b(e).replace(/[;{}\r\n]/g, "");
}
function S(e) {
return e === "" ? "" : C(e, (e) => w(e, "data-merge-tag") ?? w(e, "data-logic-merge-tag"));
}
function C(e, t) {
let n = "", r = 0;
for (; r < e.length;) {
let i = e.indexOf("<span", r);
if (i === -1) {
n += e.substring(r);
break;
}
let a = e[i + 5];
if (a !== ">" && a !== " " && a !== " " && a !== "\n" && a !== "\r" && a !== "/") {
n += e.substring(r, i + 5), r = i + 5;
continue;
}
let o = e.indexOf(">", i + 5);
if (o === -1) {
n += e.substring(r);
break;
}
let s = e.indexOf("</span>", o + 1);
if (s === -1) {
n += e.substring(r);
break;
}
let c = t(e.substring(i + 5, o));
if (c === null) {
n += e.substring(r, i + 5), r = i + 5;
continue;
}
n += e.substring(r, i), n += c, r = s + 7;
}
return n;
}
function w(e, t) {
let n = RegExp(`(?:^|\\s)${t}="([^"<>]*)"`).exec(e);
return n ? n[1] : null;
}
//#endregion
//#region ../renderer/src/padding.ts
function T(e) {
return `${e.top}px ${e.right}px ${e.bottom}px ${e.left}px`;
}
//#endregion
//#region ../renderer/src/utils.ts
function E(e, t) {
return e ? ` ${t === "native" ? "background-color" : "container-background-color"}="${e}"` : "";
}
//#endregion
//#region ../renderer/src/visibility.ts
function D(e) {
let t = e.visibility;
return t ? !t.desktop && !t.mobile : !1;
}
function O(e) {
let t = k(e);
return t === "" ? "" : ` css-class="${t}"`;
}
function k(e) {
let t = e.visibility;
if (!t) return "";
let n = [];
return t.desktop || n.push("tpl-hide-desktop"), t.mobile || n.push("tpl-hide-mobile"), n.join(" ");
}
//#endregion
//#region ../renderer/src/renderers/title.ts
function A(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = j(S(e.content)), o = a[e.level] ?? a[2], s = e.color ? `\n color="${b(e.color)}"` : "", c = e.textAlign, l = ee(e.fontFamily, t), u = O(e), d = `h${a[e.level] ? e.level : 2}`;
return `<mj-text
font-size="${o}px"${s}
align="${c}"
line-height="1.3"
padding="${n}"${r}${l}${u}
><${d} style="margin:0;font-size:inherit;color:inherit;line-height:inherit">${i}</${d}></mj-text>`;
}
function j(e) {
let t = e.match(/^\s*<p\b[^>]*>([\s\S]*)<\/p>\s*$/);
return !t || /<\/p>\s*<p\b/i.test(t[1]) ? e : t[1];
}
function ee(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/paragraph.ts
function te(e, t) {
if (D(e) || e.content.replace(/<\/?p\b[^<>]*>/gi, "").trim() === "") return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = S(e.content);
return `<mj-text
line-height="1.5"
padding="${n}"${r}${O(e)}
>${i}</mj-text>`;
}
//#endregion
//#region ../renderer/src/renderers/image.ts
function ne(e, t) {
if (D(e) || e.src === "") return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = e.width === "full" ? t.containerWidth + "px" : e.width + "px", a = O(e), o = "";
e.linkUrl && (o = ` href="${b(e.linkUrl)}"`, e.linkOpenInNewTab && (o += " target=\"_blank\" rel=\"noopener\""));
let s = b(e.src), c = e.decorative === !0;
return `<mj-image
src="${s}"
alt="${c ? "" : b(e.alt)}"
width="${i}"
align="${e.align}"
padding="${n}"${r}${o}${a}${c ? " role=\"presentation\"" : ""}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/button.ts
function M(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = T(e.buttonPadding), a = e.url === "" ? "" : b(e.url), o = a === "" ? "" : ` href="${a}"`, s = b(e.backgroundColor), c = b(e.textColor), l = e.fontSize, u = e.borderRadius, d = y(e.text);
return `<mj-button${o}${e.openInNewTab ? " target=\"_blank\" rel=\"noopener\"" : ""}
background-color="${s}"
color="${c}"
font-size="${l}px"
font-weight="bold"
border-radius="${u}px"
inner-padding="${i}"
padding="${n}"${r}${N(e.fontFamily, t)}${P(e.width)}${O(e)}
>${d}</mj-button>`;
}
function N(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
function P(e) {
return e === void 0 ? "" : ` width="${e === "full" ? "100%" : `${e}px`}"`;
}
//#endregion
//#region ../renderer/src/renderers/divider.ts
function F(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = e.styles.backgroundColor ? ` container-background-color="${b(e.styles.backgroundColor)}"` : "", i = e.width === "full" ? "100%" : e.width + "px";
return `<mj-divider
border-width="${e.thickness}px"
border-style="${e.lineStyle}"
border-color="${b(e.color)}"
width="${i}"
padding="${n}"${r}${O(e)}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/spacer.ts
function I(e, t) {
return D(e) ? "" : `<mj-spacer height="${e.height}px" padding="0"${e.styles.backgroundColor ? ` container-background-color="${b(e.styles.backgroundColor)}"` : ""}${O(e)} />`;
}
//#endregion
//#region ../renderer/src/renderers/html.ts
function L(e, t) {
if (D(e) || !t.allowHtmlBlocks) return "";
let n = e.content;
if (n === "") return "";
let r = O(e);
return `<mj-text padding="${T(e.styles.padding)}"${E(e.styles.backgroundColor, "container")}${r}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/renderers/social.ts
function R(e, t) {
if (D(e)) return "";
let n = e.icons;
if (n.length === 0) return "";
let r = T(e.styles.padding), i = e.styles.backgroundColor ? ` container-background-color="${b(e.styles.backgroundColor)}"` : "", a = O(e), o = e.align, s = e.iconSize, c = e.iconStyle, l = e.spacing, u;
switch (s) {
case "small":
u = 24;
break;
case "large":
u = 48;
break;
default:
u = 32;
break;
}
let d;
switch (c) {
case "circle":
d = "50%";
break;
case "rounded":
d = "8px";
break;
case "square":
d = "0";
break;
default:
d = "4px";
break;
}
let f = n.length;
return `<mj-social
mode="horizontal"
align="${o}"
icon-padding="0"
padding="${r}"${i}${a}
>
${n.map((e, n) => {
let r = e.platform, i = b(e.url), a = `${t.socialIconsBaseUrl}/${c}/${r}.png`, o = n === f - 1 ? 0 : l;
return `<mj-social-element src="${a}" href="${i}" icon-size="${u}px" padding="0 ${o}px 0 0" border-radius="${d}" background-color="transparent"></mj-social-element>`;
}).join("\n")}
</mj-social>`;
}
//#endregion
//#region ../renderer/src/renderers/menu.ts
function z(e, t) {
if (D(e) || e.items.length === 0) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = O(e), a = H(e.fontFamily, t), o = e.textAlign;
return `<mj-text
font-size="${e.fontSize}px"${e.color ? `\n color="${b(e.color)}"` : ""}
align="${o}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${B(e)}</mj-text>`;
}
function B(e) {
let t = e.items, n = y(e.separator), r = x(e.separatorColor), i = e.spacing, a = e.linkColor ?? e.color, o = [], s = t.length;
for (let e = 0; e < s; e++) o.push(V(t[e], a)), e < s - 1 && o.push(`<span style="color: ${r}; padding: 0 ${i}px;">${n}</span>`);
return o.join("");
}
function V(e, t) {
let n = y(e.text), r = b(e.url), i = e.color ?? t, a = e.openInNewTab ? " target=\"_blank\" rel=\"noopener\"" : "", o = ["text-decoration: none"];
return i && o.unshift(`color: ${x(i)}`), e.bold && o.push("font-weight: bold"), e.underline && o.push("text-decoration: underline"), `<a href="${r}" style="${o.join("; ")}"${a}>${n}</a>`;
}
function H(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/table.ts
function U(e, t) {
if (D(e) || e.rows.length === 0) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = O(e), a = q(e.fontFamily, t);
return `<mj-text
font-size="${e.fontSize}px"${e.color ? `\n color="${b(e.color)}"` : ""}
align="${e.textAlign}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${W(e)}</mj-text>`;
}
function W(e) {
let t = x(e.borderColor), n = e.borderWidth, r = "";
for (let i = 0; i < e.rows.length; i++) {
let a = e.rows[i];
r += G(a, e, e.hasHeaderRow && i === 0, t, n);
}
return `<table style="width: 100%; border-collapse: collapse;">${r}</table>`;
}
function G(e, t, n, r, i) {
let a = "";
for (let o of e.cells) a += K(o, t, n, r, i);
return `<tr>${a}</tr>`;
}
function K(e, t, n, r, i) {
let a = t.cellPadding, o = [`border: ${i}px solid ${r}`, `padding: ${a}px`];
n && (o.push("font-weight: bold"), t.headerBackgroundColor && o.push(`background-color: ${x(t.headerBackgroundColor)}`));
let s = o.join("; "), c = y(S(e.content)), l = n ? "th" : "td";
return `<${l} style="${s}">${c}</${l}>`;
}
function q(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/custom.ts
function re(e, t) {
if (D(e)) return "";
let n = t.customBlockHtml.get(e.id) ?? e.renderedHtml;
if (!n || n === "") return "";
let r = O(e);
return `<mj-text padding="${T(e.styles.padding)}"${E(e.styles.backgroundColor, "container")}${r}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/columns.ts
function J(e) {
switch (e) {
case "2": return ["50%", "50%"];
case "3": return [
"33.33%",
"33.33%",
"33.34%"
];
case "1-2": return ["33.33%", "66.67%"];
case "2-1": return ["66.67%", "33.33%"];
default: return ["100%"];
}
}
function Y(e, t) {
switch (e) {
case "2": return [t * .5, t * .5];
case "3": return [
t / 3,
t / 3,
t / 3
];
case "1-2": return [t / 3, t * 2 / 3];
case "2-1": return [t * 2 / 3, t / 3];
default: return [t];
}
}
//#endregion
//#region ../renderer/src/display-condition.ts
function X(e, t) {
if (t === "") return "";
let n = e.displayCondition;
return n ? `<mj-raw>${n.before}</mj-raw>
` + t + `
<mj-raw>${n.after}</mj-raw>` : t;
}
//#endregion
//#region ../renderer/src/renderers/section.ts
function ie(e, t, n) {
if (D(e)) return "";
let r = e.columns, i = J(r), a = Y(r, t.containerWidth), o = T(e.styles.padding), s = E(e.styles.backgroundColor, "native"), c = O(e), l = e.borderRadius && e.borderRadius > 0 ? ` border-radius="${e.borderRadius}px"` : "", u = e.children, f = [];
for (let e = 0; e < u.length; e++) {
let r = u[e], o = i[e] ?? "100%", s = Math.floor(a[e] ?? t.containerWidth), c = ae(r, t.allowHtmlBlocks).filter((e) => !d(e)), l = t.withContainerWidth(s), p = c.map((e) => X(e, n(e, l))).filter((e) => e !== "").join("\n");
f.push(`<mj-column width="${o}">
${p === "" ? "<mj-text>&nbsp;</mj-text>" : p}
</mj-column>`);
}
let p = f.join("\n");
return `<mj-section${s} padding="${o}"${l}${c}>
${e.stackOnMobile === !1 && f.length > 1 ? `<mj-group>
${p}
</mj-group>` : p}
</mj-section>`;
}
function ae(e, t) {
return t ? e : e.filter((e) => e.type !== "html");
}
//#endregion
//#region ../renderer/src/renderers/video.ts
function oe(e, t) {
if (t) return t;
if (!e) return null;
for (let t of [/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/, /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/]) {
let n = e.match(t);
if (n) return `https://img.youtube.com/vi/${n[1]}/maxresdefault.jpg`;
}
let n = e.match(/vimeo\.com\/(?:video\/)?(\d+)/);
return n ? `https://vumbnail.com/${n[1]}.jpg` : null;
}
function se(e, t) {
if (D(e)) return "";
let n = oe(e.url, e.thumbnailUrl);
if (!n) return "";
let r = T(e.styles.padding), i = E(e.styles.backgroundColor, "container"), a = e.width === "full" ? t.containerWidth + "px" : e.width + "px", o = O(e);
return `<mj-image
src="${b(n)}"
alt="${b(e.alt)}"
width="${a}"
align="${e.align}"
padding="${r}"
href="${b(e.url)}"
target="_blank"
rel="noopener"${i}${o}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/index.ts
function Z(a, m) {
return d(a) ? ie(a, m, Z) : n(a) ? A(a, m) : e(a) ? te(a, m) : l(a) ? ne(a, m) : c(a) ? M(a, m) : i(a) ? F(a, m) : u(a) ? I(a, m) : s(a) ? L(a, m) : r(a) ? R(a, m) : p(a) ? z(a, m) : f(a) ? U(a, m) : o(a) ? se(a, m) : t(a) ? re(a, m) : "";
}
//#endregion
//#region ../renderer/src/index.ts
async function ce(e, t) {
let n = t?.customFonts ?? [], r = t?.defaultFallbackFont ?? "Arial, sans-serif", i = t?.allowHtmlBlocks ?? !0, a = fe(t?.socialIconsBaseUrl ?? m), o = await he(e, t?.renderCustomBlock), s = ge(e, t?.getCustomBlockStylesheet), c = new g(e.settings.width, n, r, i, o, a), l = Q(e.blocks, i), u = c.resolveFontFamily(e.settings.fontFamily), d = e.settings.backgroundColor, f = e.settings.textColor ? ` color="${b(e.settings.textColor)}"` : "", p = e.settings.linkColor ? x(e.settings.linkColor) : "inherit", h = e.settings.linkUnderline ? "underline" : "none", _ = l.map((e) => le(e, c)).filter((e) => e !== "").join("\n"), v = me(n), y = pe(e.settings.preheaderText);
return `<mjml lang="${b(e.settings.locale)}">
<mj-head>${y}
<mj-attributes>
<mj-all font-family="${u}" />
<mj-text font-size="14px"${f} />
<mj-section padding="0" />
<mj-column padding="0" />
<mj-image fluid-on-mobile="true" />
</mj-attributes>${v}
<mj-style>
a { color: ${p}; text-decoration: ${h}; }
@media only screen and (max-width: 480px) {
.tpl-hide-mobile { display: none !important; mso-hide: all !important; }
}
@media only screen and (min-width: 481px) {
.tpl-hide-desktop { display: none !important; mso-hide: all !important; }
}
</mj-style>${_e(s)}
</mj-head>
<mj-body width="${c.containerWidth}px" background-color="${d}">
${_}
</mj-body>
</mjml>`;
}
function le(e, t) {
if (d(e)) {
let n = Z(e, t);
return X(e, e.wrapper && n !== "" ? ue(n, e.wrapper) : n);
}
return X(e, de(Z(e, t)));
}
function ue(e, t) {
return `<mj-wrapper${E(t.backgroundColor, "native")}${` padding="${t.padding ? T(t.padding) : "0"}"`}${t.borderRadius && t.borderRadius > 0 ? ` border-radius="${t.borderRadius}px"` : ""}>
${e}
</mj-wrapper>`;
}
function de(e) {
return e === "" ? "" : `<mj-section>
<mj-column>
${e}
</mj-column>
</mj-section>`;
}
function fe(e) {
return e.endsWith("/") ? e.slice(0, -1) : e;
}
function pe(e) {
if (!e) return "";
let t = e.trim();
return t === "" ? "" : `\n <mj-preview>${y(t)}</mj-preview>`;
}
function me(e) {
return e.length === 0 ? "" : e.map((e) => `\n <mj-font name="${b(e.name)}" href="${b(e.url)}" />`).join("");
}
function Q(e, t) {
return t ? e : e.filter((e) => e.type !== "html");
}
async function he(e, t) {
let n = /* @__PURE__ */ new Map();
if (!t) return n;
let r = [];
if ($(e.blocks, r), r.length === 0) return n;
let i = await Promise.all(r.map((e) => t(e)));
for (let e = 0; e < r.length; e++) n.set(r[e].id, i[e]);
return n;
}
function $(e, n) {
for (let r of e) {
if (t(r)) {
n.push(r);
continue;
}
if (d(r)) for (let e of r.children) $(e, n);
}
}
function ge(e, t) {
if (!t) return [];
let n = [];
if ($(e.blocks, n), n.length === 0) return [];
let r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = [];
for (let e of n) {
if (r.has(e.customType)) continue;
r.add(e.customType);
let n = t(e.customType);
if (!n) continue;
let o = n.trim();
o === "" || i.has(o) || (i.add(o), a.push(o));
}
return a;
}
function _e(e) {
return e.length === 0 ? "" : e.map((e) => `\n <mj-style>\n${e}\n </mj-style>`).join("");
}
//#endregion
export { m as DEFAULT_SOCIAL_ICONS_BASE_URL, g as RenderContext, S as convertMergeTagsToValues, b as escapeAttr, y as escapeHtml, O as getCssClassAttr, k as getCssClasses, J as getWidthPercentages, Y as getWidthPixels, D as isHiddenOnAll, Z as renderBlock, ce as renderToMjml, T as toPaddingString };
//# sourceMappingURL=src-BuC_IHzN.js.map

Sorry, the diff of this file is too big to display

import { A as e, D as t, Dt as n, E as r, Et as i, I as a, K as o, O as s, Ot as c, R as l, Y as u, Z as d, _ as f, c as p, d as m, g as h, h as g, k as _, l as v, m as y, nt as b, p as x, r as S, s as C, u as w, z as T } from "./vue.runtime.esm-bundler-B0xoGkDv.js";
import { c as E, o as D, t as O } from "./runtime-dom.esm-bundler-GdMI8WqG.js";
import { n as k } from "./upload-BwwE0U6G.js";
import { A } from "./dist-BJbqgyPn.js";
import { E as j, V as M, t as N, x as P } from "./useEditorCore-CT1slufs.js";
import { m as F } from "./dist-DYv_Pttj.js";
import { s as I } from "./usePopoverPosition-BO2LNy5n.js";
import { A as L, F as R, c as z, r as B, s as V, t as H, u as ee } from "./keys-CHPcp-Nz.js";
import { t as U } from "./useI18n-D2L9Mkik.js";
import { t as W } from "./createLucideIcon-JWHwTI6N.js";
import { t as G } from "./check-BpQDKiPz.js";
import { t as K } from "./circle-alert-CgtE46ND.js";
import { a as q, c as te, d as ne, f as re, i as ie, l as ae, m as oe, n as se, o as ce, p as le, r as ue, s as de, t as fe, u as pe } from "./styles-PcOPXvLO.js";
import { t as me } from "./clock-BzKLLW5L.js";
import { t as J } from "./loader-circle-C-Z6kgI6.js";
import { t as Y } from "./message-circle-CEm5qckV.js";
import { t as X } from "./send-B70aQDrA.js";
import { t as Z } from "./sparkles-DVlm1Ipp.js";
import { t as he } from "./triangle-alert-Djg6IG8N.js";
import { t as ge } from "./_plugin-vue_export-helper-B3ysoDQm.js";
import { n as Q } from "./useCloudI18n-BmiygEM4.js";
import { d as $ } from "./ColorPicker-s9GHXjZs.js";
import { _ as _e, c as ve, f as ye, g as be, h as xe, i as Se, l as Ce, m as we, n as Te, o as Ee, p as De, r as Oe, s as ke, t as Ae, u as je, v as Me, y as Ne } from "./cloud-Du7mnkz2.js";
var Pe = W("save", [
["path", {
d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",
key: "1c8476"
}],
["path", {
d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",
key: "1ydtos"
}],
["path", {
d: "M7 3v4a1 1 0 0 0 1 1h7",
key: "t51u73"
}]
]);
//#endregion
//#region src/cloud/composables/useSnapshotPreview.ts
function Fe(e) {
let { authManager: t, editor: n, history: r, conditionPreview: i, autoSave: a, onError: s } = e, c = d(null), l = u(null), f = u(null), p = !1;
o(() => {
p = !0;
});
let m = C(() => l.value !== null), h = C(() => c.value?.snapshots.value ?? []), g = C(() => c.value?.isLoading.value ?? !1), _ = C(() => c.value?.isRestoring.value ?? !1);
function v() {
n.state.template?.id && !c.value && (c.value = be({
authManager: t,
templateId: n.state.template.id,
onRestore: y,
onError: s
}), c.value.loadSnapshots());
}
function y(e) {
n.setContent(e.content, !1), r.clear(), i.reset();
}
async function b(e) {
if (!p) {
if (l.value) {
l.value = e, n.setContent(e.content, !1);
return;
}
n.state.isDirty && n.hasTemplate() && (await n.createSnapshot(), p) || (f.value = structuredClone(n.content.value), a?.pause(), l.value = e, n.setContent(e.content, !1));
}
}
async function x() {
if (!(!l.value || !c.value)) try {
if (await c.value.restoreSnapshot(l.value.id), p || (await c.value.loadSnapshots(), p)) return;
} catch (e) {
throw !p && f.value && n.setContent(f.value, !1), e;
} finally {
p || (l.value = null, f.value = null, a?.resume());
}
}
function S() {
!l.value || !f.value || (n.setContent(f.value, !1), l.value = null, f.value = null, a?.resume());
}
async function w() {
p || c.value && await c.value.loadSnapshots();
}
return {
snapshotHistoryInstance: c,
previewingSnapshot: l,
contentBeforePreview: f,
isPreviewingSnapshot: m,
snapshotHistorySnapshots: h,
snapshotHistoryIsLoading: g,
snapshotHistoryIsRestoring: _,
initSnapshotHistory: v,
handleRestore: y,
handleSnapshotNavigate: b,
confirmRestoreSnapshot: x,
cancelPreview: S,
loadSnapshotHistory: w
};
}
//#endregion
//#region src/cloud/composables/useCloudPanelState.ts
function Ie() {
let e = u(null), t = C({
get: () => e.value === "ai-chat",
set: (t) => e.value = t ? "ai-chat" : null
}), n = C({
get: () => e.value === "scoring",
set: (t) => e.value = t ? "scoring" : null
}), r = C({
get: () => e.value === "design-reference",
set: (t) => e.value = t ? "design-reference" : null
}), i = C({
get: () => e.value === "comments",
set: (t) => e.value = t ? "comments" : null
}), a = u(!1), o = u(!1), s = u(void 0), c = u(!1), l = u(null), d = C(() => e.value !== null), f = C(() => {
let t = e.value;
return t === "ai-chat" || t === "design-reference" || t === "scoring" ? t : null;
}), p = C(() => c.value || e.value === "ai-chat" || e.value === "design-reference" || e.value === "scoring");
function m() {
c.value = !c.value;
}
function h(t) {
c.value = !1, e.value = e.value === t ? null : t;
}
return I(l, () => {
c.value = !1;
}), {
activePanel: e,
aiChatOpen: t,
scoringPanelOpen: n,
designReferenceOpen: r,
commentsOpen: i,
testEmailModalOpen: a,
mediaLibraryOpen: o,
mediaLibraryAccept: s,
aiMenuOpen: c,
aiMenuRef: l,
rightPanelOpen: d,
activeAiFeature: f,
aiButtonActive: p,
toggleAiMenu: m,
handleAiFeatureSelect: h
};
}
//#endregion
//#region src/cloud/composables/useCollabUndoWarning.ts
function Le(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = u(!1), a = u(!1), { start: o } = F(() => {
a.value = !1;
}, k, { immediate: !1 });
function s() {
i.value || !t.value || n() === 0 || !r.value || (i.value = !0, a.value = !0, o());
}
return {
collabUndoWarningVisible: a,
showCollabUndoWarning: s
};
}
//#endregion
//#region src/cloud/composables/useCloudFeatureFlags.ts
function Re(e) {
let { planConfigInstance: t, aiConfig: n, editor: r } = e, i = C(() => t.hasFeature("ai_generation") && n.hasAnyMenuFeature.value), a = C(() => t.hasFeature("test_email")), o = C(() => !!r.state.template?.id), s = C(() => t.hasFeature("white_label")), c = C(() => t.config.value?.limits.max_templates ?? null), l = C(() => t.config.value?.template_count ?? 0), d = u(!1), f = u("idle"), p = u(""), { start: m } = F(() => {
f.value = "idle";
}, 3e3, { immediate: !1 });
return {
canUseAiGeneration: i,
canSendTestEmail: a,
hasTemplateSaved: o,
isWhiteLabeled: s,
templateLimit: c,
templateCount: l,
isSaveExporting: d,
saveStatus: f,
saveErrorMessage: p,
startSaveStatusClear: m
};
}
//#endregion
//#region src/cloud/composables/useCloudMediaLibrary.ts
function ze(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: r, authManager: i, getMediaConfig: a, onError: s } = e, c = null;
function l(e) {
return {
url: e.url,
alt: e.alt_text || void 0
};
}
async function u(e) {
let i = e?.accept ?? ["images"];
if (e?.files?.length) {
if (t) {
let n = await t({
accept: i,
files: e.files
});
return n ? l(n) : null;
}
return d(e.files[0]);
}
if (t) {
let e = await t({ accept: i });
return e ? l(e) : null;
}
return c &&= (c(null), null), r.value = i, n.value = !0, new Promise((e) => {
c = (t) => {
e(t);
};
});
}
async function d(e) {
let t = f(e);
if (t) return s?.(t), null;
try {
let { MediaApiClient: t } = await import("@templatical/media-library");
return l(await new t(i).uploadMedia(e));
} catch (e) {
return s?.(e), null;
}
}
function f(e) {
let t = a?.() ?? null;
if (!t) return null;
let n = t.categories?.images?.mime_types ?? [];
return n.length > 0 && !n.includes(e.type) ? /* @__PURE__ */ Error(`Unsupported image type: ${e.type || "unknown"}. Accepted: ${n.join(", ")}.`) : t.max_file_size > 0 && e.size > t.max_file_size ? /* @__PURE__ */ Error(`Image is too large (${e.size} bytes). Maximum allowed is ${t.max_file_size} bytes.`) : null;
}
function p(e) {
n.value = !1, c?.(l(e)), c = null;
}
function m() {
n.value = !1, c?.(null), c = null;
}
return o(() => {
c &&= (c(null), null);
}), {
handleRequestMedia: u,
handleMediaSelect: p,
handleMediaLibraryClose: m
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function Be(e) {
let { config: t, translations: n, fontsManager: r, emit: i, getCommentsSidebar: o } = e, s = u(!0), c = u(!1), l = u(null), d = !1, f = { value: null }, p = null, m = null, h = new Ae({
...t.auth,
onError: t.onError
}), g = xe({
authManager: h,
onError: t.onError
}), v = u(/* @__PURE__ */ new Map()), y = ye({
authManager: h,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: v
}), b = Ne({
authManager: h,
onError: t.onError
});
t.mcp?.enabled && we({
editor: y,
channel: b.channel,
onOperation: t.mcp.onOperation
});
let x = null;
t.collaboration?.enabled && (x = ke({
authManager: h,
editor: y,
channel: b.channel,
onError: t.onError,
onCollaboratorJoined: t.collaboration.onCollaboratorJoined,
onCollaboratorLeft: t.collaboration.onCollaboratorLeft,
onBlockLocked: t.collaboration.onBlockLocked,
onBlockUnlocked: t.collaboration.onBlockUnlocked
}), a(() => x.lockedBlocks.value, (e) => {
v.value = e;
}, { immediate: !0 }), ve(y, x));
let S = C(() => !!t.collaboration?.enabled && g.hasFeature("collaboration")), w = N({
editor: y,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
templateDefaults: t.templateDefaults,
customBlocks: [],
paletteBlocks: t.paletteBlocks,
htmlBlockPreview: t.htmlBlockPreview,
colors: t.colors,
mergeTags: t.mergeTags,
logicTags: t.logicTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: re(t),
onSave: () => {
f.value?.().catch((e) => {
t.onError?.(e);
});
}
},
translations: n,
fontsManager: r,
historyOptions: x ? { isRemoteOperation: () => x._isProcessingRemoteOperation() } : void 0,
autoSaveOptions: {
onChange: async () => {
y.hasTemplate() && (await y.createSnapshot(), p?.snapshotHistoryInstance.value?.loadSnapshots());
},
debounce: t.autoSaveDebounce ?? 5e3,
enabled: () => t.autoSave !== !1 && g.hasFeature("auto_save")
},
themeExtraStyles: () => ({ "--tpl-drop-text": `"${n.canvas.dropHere}"` }),
keyboardOptions: { onBeforeUndo: () => m?.showCollabUndoWarning() },
editorRoot: e.editorRoot,
containerEl: e.containerEl
}), T = Le({
isCollaborationEnabled: S,
getCollaboratorCount: () => x?.collaborators.value.length ?? 0,
canUndo: w.history.canUndo
});
m = T;
let E = Fe({
authManager: h,
editor: y,
history: w.history,
conditionPreview: w.conditionPreview,
autoSave: w.autoSave,
onError: t.onError
});
p = E;
let D = Ie(), O = Ee(t.ai), k = Re({
planConfigInstance: g,
aiConfig: O,
editor: y
}), A = ze({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: D.mediaLibraryOpen,
mediaLibraryAccept: D.mediaLibraryAccept,
authManager: h,
getMediaConfig: () => g.config.value?.media ?? null,
onError: t.onError
});
j({
onBlockMove: y.moveBlock,
onBlockAdd: y.addBlock
});
let P = De({
authManager: h,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => g.hasFeature("custom_fonts")
}), F = Me({
authManager: h,
getTemplateId: () => y.state.template?.id ?? null,
save: () => y.save(),
exportHtml: (e) => P.exportHtml(e),
onError: t.onError,
isAuthReady: c,
onBeforeTestEmail: t.onBeforeTestEmail
}), I = je({
authManager: h,
getTemplateId: () => y.state.template?.id ?? null,
getSocketId: () => b.getSocketId(),
onComment: t.onComment,
onError: t.onError,
isAuthReady: c,
hasCommentingFeature: () => t.commenting !== !1 && g.hasFeature("commenting")
});
Ce({
comments: I,
channel: b.channel
});
let z = typeof t.savedBlocks == "object" && t.savedBlocks !== null ? t.savedBlocks : null, U = le({
provider: z ?? Te(h),
editor: y,
onError: t.onError,
isAvailable: z ? () => !0 : () => t.savedBlocks !== !1 && g.hasFeature("saved_modules")
}), W = _e({
authManager: h,
getTemplateId: () => y.state.template?.id ?? null
});
function G(e) {
D.commentsOpen.value = !0, queueMicrotask(() => {
o()?.filterByBlock(e);
});
}
_(L, A.handleRequestMedia), _(B, h), _(H, O), _(ee, I), _(R, W), _(V, {
plan: g,
ai: O,
comments: {
getBlockCount: (e) => I.commentCountByBlock.value.get(e) ?? 0,
openForBlock: G
},
savedBlocks: U.capability
});
function K(e) {
g.hasFeature("theme_customization") && (w.themeOverrides.value = e);
}
function q(e) {
y.setUiTheme(e);
}
async function te() {
s.value = !0, l.value = null;
try {
if (await h.initialize(), d) return;
c.value = !0;
let e = await Oe({ authManager: h });
if (d) return;
if (!e.api.ok) throw Error("Health check failed: API is not reachable");
if (!e.auth.ok) throw Error(`Health check failed: authentication error${e.auth.error ? ` - ${e.auth.error}` : ""}`);
if (e.websocket.ok || M.warn("WebSocket health check failed:", e.websocket.error ?? "unknown error", "-- real-time features will be disabled."), await g.fetchConfig(), d) return;
r.setCustomFontsEnabled(g.hasFeature("custom_fonts")), t.customBlocks?.length && g.hasFeature("custom_blocks") && w.registerCustomBlocks(t.customBlocks), t.theme && g.hasFeature("theme_customization") && (w.themeOverrides.value = t.theme), i("ready");
} catch (e) {
if (d) return;
let n = e instanceof Error ? e : Error("Initialization failed", { cause: e });
l.value = n, t.onError?.(n);
} finally {
d || (s.value = !1);
}
}
function ne() {
d = !0, r.cleanupFontLinks(), b.disconnect(), w.destroy(), t.onUnmount?.();
}
return {
isInitializing: s,
isAuthReady: c,
initError: l,
isDestroyed: () => d,
authManager: h,
planConfigInstance: g,
websocket: b,
collaboration: x,
isCollaborationEnabled: S,
editor: y,
core: w,
aiConfig: O,
featureFlags: k,
mediaLib: A,
exporter: P,
testEmail: F,
commentsInstance: I,
savedBlocks: U,
scoringInstance: W,
panelState: D,
snapshotPreview: E,
collabWarning: T,
onSaveHook: f,
initialize: te,
destroy: ne,
setThemeOverrides: K,
setUiTheme: q,
openCommentsForBlock: G
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Ve(e, t) {
let n = async (e) => {
if (A(e)) {
let n = e;
try {
n.renderedHtml = await t.renderCustomBlock(n);
} catch {
n.renderedHtml = `<!-- Custom block render error: ${n.customType} -->`;
}
}
if (e.type === "section" && "children" in e) {
let t = e;
for (let e of t.children) for (let t of e) await n(t);
}
};
for (let t of e.blocks) await n(t);
}
//#endregion
//#region src/cloud/composables/useCloudLifecycle.ts
function He(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return Se(i.config.value.websocket);
}
async function d(e) {
let i = await n.create(e);
return l() ? i : (t.onCreate?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function f(e) {
let i = await n.load(e);
return l() ? i : (t.onLoad?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function p() {
c.isSaveExporting.value = !0, c.saveStatus.value = "idle";
try {
if (await Ve(n.content.value, o.registry), l()) throw Error("Component unmounted during save");
let e = await n.save();
if (l()) throw Error("Component unmounted during save");
a.initSnapshotHistory(), a.snapshotHistoryInstance.value?.loadSnapshots();
let r = await s.exportHtml(e.id);
if (l()) throw Error("Component unmounted during save");
let i = {
templateId: e.id,
html: r.html,
mjml: r.mjml,
content: e.content
};
return t.onSave?.(i), c.saveStatus.value = "saved", c.startSaveStatusClear(), i;
} catch (e) {
throw l() || (c.saveStatus.value = "error", c.saveErrorMessage.value = e instanceof Error ? e.message : "Save failed"), e;
} finally {
l() || (c.isSaveExporting.value = !1);
}
}
return {
createTemplate: d,
loadTemplate: f,
saveTemplate: p
};
}
//#endregion
//#region src/cloud/composables/useCloudSaveGate.ts
function Ue(e) {
let t = u(!1), n = null, r = C(() => e.planConfig.value?.accessibility?.blockOnError === !0), i = C(() => r.value ? e.issues.value.filter((e) => e.severity === "error") : []), a = C(() => i.value.length > 0);
async function o(e) {
return a.value ? (n = e, t.value = !0, !1) : (await e(), !0);
}
async function s() {
let e = n;
n = null, t.value = !1, e && await e();
}
function c() {
n = null, t.value = !1;
}
return {
shouldBlock: a,
blockingIssues: i,
modalOpen: t,
tryRunSave: o,
confirmAndSave: s,
cancel: c
};
}
//#endregion
//#region src/cloud/components/CloudSaveGateModal.vue?vue&type=script&setup=true&lang.ts
var We = ["aria-label"], Ge = { class: "tpl:flex tpl:max-h-[80vh] tpl:w-full tpl:max-w-md tpl:flex-col tpl:gap-4 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:p-5 tpl:shadow-[var(--tpl-shadow-md)]" }, Ke = { class: "tpl:flex tpl:items-center tpl:gap-2" }, qe = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, Je = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Ye = { class: "tpl:m-0 tpl:flex tpl:max-h-64 tpl:list-none tpl:flex-col tpl:gap-1.5 tpl:overflow-y-auto tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2" }, Xe = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, Ze = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Qe = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, $e = /* @__PURE__ */ f({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(t, { emit: n }) {
let r = n, { t: i } = Q();
return (n, a) => (s(), v(O, {
"enter-active-class": "tpl:transition-opacity tpl:duration-150",
"leave-active-class": "tpl:transition-opacity tpl:duration-150",
"enter-from-class": "tpl:opacity-0",
"leave-to-class": "tpl:opacity-0"
}, {
default: l(() => [t.open ? (s(), m("div", {
key: 0,
role: "dialog",
"aria-modal": "true",
"aria-label": b(i).saveGate.title,
class: "tpl:fixed tpl:inset-0 tpl:z-50 tpl:flex tpl:items-center tpl:justify-center tpl:bg-black/40 tpl:p-6",
onClick: a[2] ||= E((e) => r("cancel"), ["self"])
}, [p("div", Ge, [
p("header", Ke, [g(b(he), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), p("h2", qe, c(b(i).saveGate.title), 1)]),
p("p", Je, c(b(i).saveGate.body), 1),
p("ul", Ye, [(s(!0), m(S, null, e(t.issues, (e) => (s(), m("li", {
key: `${e.ruleId}-${e.blockId ?? "template"}`,
class: "tpl:flex tpl:flex-col tpl:gap-0.5 tpl:rounded tpl:px-2 tpl:py-1.5"
}, [p("span", Xe, c(e.message), 1), p("span", Ze, c(e.ruleId), 1)]))), 128))]),
p("footer", Qe, [p("button", {
type: "button",
class: "tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]",
onClick: a[0] ||= (e) => r("cancel")
}, c(b(i).saveGate.cancel), 1), p("button", {
type: "button",
class: "tpl:rounded-md tpl:bg-[var(--tpl-danger)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-white",
onClick: a[1] ||= (e) => r("confirm")
}, c(b(i).saveGate.confirm), 1)])
])], 8, We)) : w("", !0)]),
_: 1
}));
}
}), et = {
class: "tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4",
style: {
"background-color": "color-mix(in srgb, var(--tpl-bg) 80%, transparent)",
"backdrop-filter": "blur(12px)",
"-webkit-backdrop-filter": "blur(12px)",
"box-shadow": "var(--tpl-shadow-md)",
"border-bottom": "1px solid var(--tpl-border)"
}
}, tt = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, nt = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, rt = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, it = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, at = ["data-tooltip"], ot = {
key: 1,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-success)]"
}, st = {
key: 2,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-text-muted)]"
}, ct = ["aria-label", "aria-expanded"], lt = {
key: 0,
class: "tpl:inline-flex tpl:size-4.5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:text-[10px] tpl:font-semibold tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]"
}, ut = ["aria-expanded"], dt = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, ft = ["disabled"], pt = ["disabled"], mt = /* @__PURE__ */ f({
__name: "CloudHeader",
props: {
editor: {},
core: {},
featureFlags: {},
panelState: {},
snapshotPreview: {},
commentsInstance: {},
testEmail: {},
websocket: {},
collaboration: {},
isCollaborationEnabled: { type: Boolean },
isSaveDisabled: { type: Boolean },
isSaving: { type: Boolean }
},
emits: ["save"],
setup(e) {
let t = h(() => import("./CollaboratorBar-Bj4NZiie.js")), r = h(() => import("./SnapshotHistory-FtzDq8f0.js")), a = h(() => import("./AiFeatureMenu-CcqQDHzJ.js")), { t: o, format: u } = Q();
return (d, f) => (s(), m("header", et, [
p("div", tt, [e.featureFlags.templateLimit.value === null ? w("", !0) : (s(), m("span", nt, c(b(u)(b(o).header.templatesUsed, {
used: e.featureFlags.templateCount.value,
max: e.featureFlags.templateLimit.value
})), 1))]),
p("div", rt, [
g(ce, {
viewport: e.editor.state.viewport,
onChange: e.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
g(ie, {
"dark-mode": e.editor.state.darkMode,
onChange: e.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
g(q, {
"preview-mode": e.editor.state.previewMode,
onChange: e.editor.setPreviewMode
}, null, 8, ["preview-mode", "onChange"]),
e.collaboration && e.isCollaborationEnabled ? (s(), v(b(t), {
key: 0,
collaborators: e.collaboration.collaborators.value,
"is-connected": e.websocket.isConnected.value
}, null, 8, ["collaborators", "is-connected"])) : w("", !0),
e.snapshotPreview.snapshotHistoryInstance.value ? (s(), v(b(r), {
key: 1,
snapshots: e.snapshotPreview.snapshotHistorySnapshots.value,
"is-loading": e.snapshotPreview.snapshotHistoryIsLoading.value,
"is-restoring": e.snapshotPreview.snapshotHistoryIsRestoring.value,
onLoad: e.snapshotPreview.loadSnapshotHistory,
onNavigate: e.snapshotPreview.handleSnapshotNavigate
}, null, 8, [
"snapshots",
"is-loading",
"is-restoring",
"onLoad",
"onNavigate"
])) : w("", !0)
]),
p("div", it, [
e.featureFlags.saveStatus.value === "error" ? (s(), m("div", {
key: 0,
"aria-live": "assertive",
class: "tpl-tooltip tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-danger)]",
"data-tooltip": e.featureFlags.saveErrorMessage.value
}, [g(b(K), {
size: 12,
"stroke-width": 2.5
}), y(" " + c(b(o).header.saveFailed), 1)], 8, at)) : e.featureFlags.saveStatus.value === "saved" ? (s(), m("div", ot, [g(b(G), {
size: 12,
"stroke-width": 2.5
}), y(" " + c(b(o).header.saved), 1)])) : e.editor.state.isDirty ? (s(), m("div", st, [f[4] ||= p("span", { class: "tpl-pulse tpl:size-1.5 tpl:rounded-full tpl:bg-[var(--tpl-primary)]" }, null, -1), y(" " + c(b(o).header.unsaved), 1)])) : w("", !0),
e.commentsInstance.isEnabled.value && e.featureFlags.hasTemplateSaved.value ? (s(), m("button", {
key: 3,
"aria-label": e.commentsInstance.unresolvedCount.value > 0 ? `${b(o).comments.button} (${e.commentsInstance.unresolvedCount.value})` : b(o).comments.button,
"aria-expanded": e.panelState.commentsOpen.value,
class: i(b($)),
style: n({
backgroundColor: e.panelState.commentsOpen.value ? "var(--tpl-primary)" : "transparent",
color: e.panelState.commentsOpen.value ? "var(--tpl-bg)" : "var(--tpl-primary)",
borderColor: "var(--tpl-primary)"
}),
onClick: f[0] ||= (t) => e.panelState.commentsOpen.value = !e.panelState.commentsOpen.value
}, [
g(b(Y), {
size: 16,
"stroke-width": 2
}),
y(" " + c(b(o).comments.button) + " ", 1),
e.commentsInstance.unresolvedCount.value > 0 && !e.panelState.commentsOpen.value ? (s(), m("span", lt, c(e.commentsInstance.unresolvedCount.value), 1)) : w("", !0)
], 14, ct)) : w("", !0),
e.featureFlags.canUseAiGeneration.value && e.featureFlags.hasTemplateSaved.value ? (s(), m("div", {
key: 4,
ref: (t) => e.panelState.aiMenuRef.value = t,
class: "tpl:relative"
}, [p("button", {
"aria-expanded": e.panelState.aiMenuOpen.value,
class: i(["tpl-ai-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-4 tpl:py-2 tpl:text-sm tpl:font-semibold tpl:whitespace-nowrap tpl:transition-all tpl:duration-200", e.panelState.aiButtonActive.value ? "tpl-ai-btn--active" : "tpl-ai-btn--idle"]),
onClick: f[1] ||= E((...t) => e.panelState.toggleAiMenu && e.panelState.toggleAiMenu(...t), ["stop"])
}, [g(b(Z), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), y(" " + c(b(o).aiChat.button), 1)], 10, ut), g(O, {
"enter-active-class": "tpl:transition-all tpl:duration-150 tpl:ease-out",
"enter-from-class": "tpl:scale-95 tpl:opacity-0",
"enter-to-class": "tpl:scale-100 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-100 tpl:ease-in",
"leave-from-class": "tpl:scale-100 tpl:opacity-100",
"leave-to-class": "tpl:scale-95 tpl:opacity-0"
}, {
default: l(() => [e.panelState.aiMenuOpen.value ? (s(), m("div", dt, [g(b(a), {
"active-feature": e.panelState.activeAiFeature.value,
onSelect: e.panelState.handleAiFeatureSelect
}, null, 8, ["active-feature", "onSelect"])])) : w("", !0)]),
_: 1
})], 512)) : w("", !0),
e.testEmail.isEnabled.value && e.featureFlags.canSendTestEmail.value ? (s(), m("button", {
key: 5,
class: i(b($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.testEmail.isSending.value || !e.featureFlags.hasTemplateSaved.value,
onClick: f[2] ||= (t) => e.panelState.testEmailModalOpen.value = !0
}, [e.testEmail.isSending.value ? (s(), v(b(J), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (s(), v(b(X), {
key: 0,
size: 16,
"stroke-width": 2
})), y(" " + c(b(o).testEmail.button), 1)], 10, ft)) : w("", !0),
p("button", {
class: i(b($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.isSaveDisabled,
onClick: f[3] ||= (e) => d.$emit("save")
}, [e.isSaving ? (s(), v(b(J), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (s(), v(b(Pe), {
key: 0,
size: 16,
"stroke-width": 2
})), y(" " + c(e.isSaving ? b(o).header.saving : b(o).header.save), 1)], 10, pt)
])
]));
}
}), ht = /* @__PURE__ */ f({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {}
},
emits: ["send-test-email"],
setup(e, { expose: t, emit: n }) {
let r = h(() => import("./AiChatSidebar-K_AehWc-.js")), i = h(() => import("./CommentsSidebar-DvNEdugN.js")), a = h(() => import("./DesignReferenceSidebar-DNmK3dxp.js")), o = h(() => import("./TemplateScoringPanel-ifGGGWs5.js")), c = h(() => import("./TestEmailModal-DL2O1H8M.js")), l = h(async () => {
try {
return (await import("@templatical/media-library")).MediaLibraryModal;
} catch {
throw Error("[Templatical] Cloud media library requires the optional peer dependency '@templatical/media-library'. Please install it.");
}
}), d = n;
function f(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
let p = u(null);
function _(e) {
p.value?.filterByBlock(e);
}
return t({ filterCommentsByBlock: _ }), (t, n) => (s(), m(S, null, [
g(b(r), {
visible: e.panelState.aiChatOpen.value,
"on-apply": (t) => f(t, e.core, e.editor),
onClose: n[0] ||= (t) => e.panelState.aiChatOpen.value = !1
}, null, 8, ["visible", "on-apply"]),
g(b(o), {
visible: e.panelState.scoringPanelOpen.value,
onClose: n[1] ||= (t) => e.panelState.scoringPanelOpen.value = !1
}, null, 8, ["visible"]),
g(b(a), {
visible: e.panelState.designReferenceOpen.value,
"has-existing-blocks": e.editor.content.value.blocks.length > 0,
onClose: n[2] ||= (t) => e.panelState.designReferenceOpen.value = !1,
onApply: n[3] ||= (t) => f(t, e.core, e.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
g(b(i), {
ref_key: "commentsSidebar",
ref: p,
visible: e.panelState.commentsOpen.value,
onClose: n[4] ||= (t) => e.panelState.commentsOpen.value = !1
}, null, 8, ["visible"]),
g(b(c), {
visible: e.panelState.testEmailModalOpen.value,
"allowed-emails": e.testEmail.allowedEmails.value,
"is-sending": e.testEmail.isSending.value,
error: e.testEmail.error.value,
onSend: n[5] ||= (e) => d("send-test-email", e),
onClose: n[6] ||= (t) => e.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
g(b(l), {
visible: e.panelState.mediaLibraryOpen.value,
accept: e.panelState.mediaLibraryAccept.value,
"popover-target": e.core.popoverRoot.value,
onSelect: e.mediaLib.handleMediaSelect,
onClose: e.mediaLib.handleMediaLibraryClose
}, null, 8, [
"visible",
"accept",
"popover-target",
"onSelect",
"onClose"
])
], 64));
}
}), gt = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, _t = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, vt = { class: "tpl:flex tpl:w-12 tpl:shrink-0 tpl:flex-col tpl:items-center tpl:gap-4 tpl:py-5 tpl:border-r tpl:border-[var(--tpl-border)]" }, yt = /* @__PURE__ */ f({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(t) {
return (n, r) => t.visible ? (s(), m("div", gt, [r[1] ||= x("<div class=\"tpl:flex tpl:h-14 tpl:shrink-0 tpl:items-center tpl:justify-between tpl:px-4 tpl:border-b tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-5 tpl:w-28 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl:flex tpl:gap-3\"><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div></div>", 1), p("div", _t, [p("div", vt, [(s(), m(S, null, e(5, (e) => p("div", {
key: e,
class: "tpl-shimmer tpl:size-7 tpl:rounded-[var(--tpl-radius-sm)]"
})), 64))]), r[0] ||= x("<div class=\"tpl:flex tpl:flex-1 tpl:items-start tpl:justify-center tpl:overflow-auto tpl:p-8 tpl:bg-[var(--tpl-canvas-bg)]\"><div class=\"tpl:w-full tpl:max-w-[600px] tpl:rounded-[var(--tpl-radius)] tpl:p-6 tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)]\"><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-3/4 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-5/6 tpl:rounded\"></div></div><div class=\"tpl:py-4\"><div class=\"tpl-shimmer tpl:h-44 tpl:w-full tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-2/3 tpl:rounded\"></div></div><div class=\"tpl:flex tpl:justify-center tpl:py-4\"><div class=\"tpl-shimmer tpl:h-10 tpl:w-36 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/2 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/3 tpl:rounded\"></div></div></div></div><div class=\"tpl:flex tpl:w-[320px] tpl:shrink-0 tpl:flex-col tpl:gap-4 tpl:p-4 tpl:border-l tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-8 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div></div>", 2)])])) : w("", !0);
}
}), bt = {
key: 0,
role: "alert",
class: "tpl-error tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-6 tpl:px-8 tpl:bg-[var(--tpl-bg)]"
}, xt = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, St = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, Ct = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, wt = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Tt = /* @__PURE__ */ f({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
function i(e) {
return "isUnauthorized" in e && e.isUnauthorized ? r.error.authFailed : "isNotFound" in e && e.isNotFound ? r.error.templateNotFound : r.error.defaultMessage;
}
function a(e) {
return "isNotFound" in e && !!e.isNotFound;
}
return (t, o) => e.visible && e.error ? (s(), m("div", bt, [
p("div", xt, [g(b(K), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
p("div", St, [p("h2", Ct, c(b(r).error.title), 1), p("p", wt, c(i(e.error)), 1)]),
a(e.error) ? w("", !0) : (s(), m("button", {
key: 0,
class: "tpl-btn tpl-btn-primary tpl:inline-flex tpl:items-center tpl:gap-2 tpl:rounded-md tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: o[0] ||= (e) => n("retry")
}, c(b(r).error.retry), 1))
])) : w("", !0);
}
}), Et = {
key: 0,
class: "tpl-preview-banner tpl:absolute tpl:top-14 tpl:right-0 tpl:left-0 tpl:z-40 tpl:flex tpl:items-center tpl:justify-center tpl:gap-4 tpl:px-4 tpl:py-3 tpl:bg-[var(--tpl-primary-light)] tpl:border-b tpl:border-[var(--tpl-primary)]"
}, Dt = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, Ot = { class: "tpl:flex tpl:items-center tpl:gap-2" }, kt = /* @__PURE__ */ f({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
return (t, i) => e.visible ? (s(), m("div", Et, [p("div", Dt, [g(b(me), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), p("span", null, c(b(r).snapshotPreview.message), 1)]), p("div", Ot, [p("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:text-[var(--tpl-text-muted)] tpl:border tpl:border-[var(--tpl-border)]",
style: { "background-color": "transparent" },
onClick: i[0] ||= (e) => n("cancel")
}, c(b(r).snapshotPreview.cancel), 1), p("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: i[1] ||= (e) => n("confirm")
}, c(b(r).snapshotPreview.restore), 1)])])) : w("", !0);
}
}), At = {
key: 0,
role: "status",
"aria-live": "polite",
class: "tpl:absolute tpl:top-16 tpl:left-1/2 tpl:z-toast tpl:-translate-x-1/2 tpl:rounded-[var(--tpl-radius)] tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:shadow-lg",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-text)",
border: "1px solid var(--tpl-warning)"
}
}, jt = /* @__PURE__ */ f({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(e) {
let { t } = U();
return (n, r) => e.visible ? (s(), m("div", At, c(b(t).history.collabWarning), 1)) : w("", !0);
}
}), Mt = ["data-tpl-theme"], Nt = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, Pt = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, Ft = ["aria-label"], It = /*#__PURE__*/ ge(/* @__PURE__ */ f({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(e, { expose: a, emit: o }) {
let d = h(() => import("./SavedBlocksPanels-Dff38YXu.js")), f = e;
_(z, f.cloudTranslations);
let x = o, S = u(null), C = u(null), k = Be({
config: f.config,
translations: f.translations,
fontsManager: f.fontsManager,
emit: x,
getCommentsSidebar: () => S.value ? { filterByBlock: S.value.filterCommentsByBlock } : null,
editorRoot: f.shadowRoot,
containerEl: C
}), { isInitializing: A, isAuthReady: j, initError: M, planConfigInstance: N, websocket: F, collaboration: I, isCollaborationEnabled: L, editor: R, core: B, featureFlags: V, mediaLib: H, exporter: ee, testEmail: U, commentsInstance: W, savedBlocks: G, panelState: K, snapshotPreview: q, collabWarning: re, setThemeOverrides: ie, setUiTheme: ce } = k, { showNotice: le } = P(() => f.config.smallScreenNotice);
async function me(e) {
try {
await U.sendTestEmail(e), K.testEmailModalOpen.value = !1;
} catch {}
}
async function J() {
try {
await q.confirmRestoreSnapshot();
} catch {}
}
let Y = He({
config: f.config,
editor: R,
websocket: F,
planConfigInstance: N,
snapshotPreview: q,
core: B,
exporter: ee,
featureFlags: V,
isDestroyed: k.isDestroyed
}), X = Ue({
issues: B.templateLint ? B.templateLint.issues : u([]),
planConfig: N.config
});
async function Z() {
await X.tryRunSave(() => Y.saveTemplate().catch((e) => f.config.onError?.(e)));
}
return k.onSaveHook.value = Z, r(() => {
k.initialize();
}), t(() => {
k.destroy();
}), a({
getContent: () => R.content.value,
setContent: (e) => R.setContent(e),
setTheme: ce,
setThemeOverrides: ie,
create: Y.createTemplate,
load: Y.loadTemplate,
save: Y.saveTemplate,
sendTestEmail: U.sendTestEmail
}), (t, r) => (s(), m("div", {
ref_key: "rootEl",
ref: C,
class: i(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": b(R).state.darkMode }]),
"data-tpl-theme": b(B).resolvedTheme.value,
style: n(b(B).themeStyles.value),
onDragover: r[6] ||= E(() => {}, ["prevent"]),
onDrop: r[7] ||= E(() => {}, ["prevent"])
}, [
g(pe),
g(O, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-100",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: l(() => [g(yt, { visible: b(A) || b(R).state.isLoading }, null, 8, ["visible"])]),
_: 1
}),
g(O, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-0",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: l(() => [g(Tt, {
error: b(M),
visible: !!b(M) && !b(A),
onRetry: b(k).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
g(mt, {
editor: b(R),
core: b(B),
"feature-flags": b(V),
"panel-state": b(K),
"snapshot-preview": b(q),
"comments-instance": b(W),
"test-email": b(U),
websocket: b(F),
collaboration: b(I),
"is-collaboration-enabled": b(L),
"is-saving": b(R).state.isSaving || b(V).isSaveExporting.value,
"is-save-disabled": b(R).state.isSaving || b(V).isSaveExporting.value || !b(R).state.isDirty,
onSave: Z
}, null, 8, [
"editor",
"core",
"feature-flags",
"panel-state",
"snapshot-preview",
"comments-instance",
"test-email",
"websocket",
"collaboration",
"is-collaboration-enabled",
"is-saving",
"is-save-disabled"
]),
g($e, {
open: b(X).modalOpen.value,
issues: b(X).blockingIssues.value,
onCancel: b(X).cancel,
onConfirm: b(X).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
g(kt, {
visible: b(q).isPreviewingSnapshot.value,
onCancel: b(q).cancelPreview,
onConfirm: J
}, null, 8, ["visible", "onCancel"]),
g(O, {
"enter-active-class": "tpl:transition-all tpl:duration-200 tpl:ease-out",
"enter-from-class": "tpl:translate-y-[-8px] tpl:opacity-0",
"enter-to-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-300 tpl:ease-in",
"leave-from-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-to-class": "tpl:translate-y-[-8px] tpl:opacity-0"
}, {
default: l(() => [g(jt, { visible: b(re).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
T(g(ae, null, null, 512), [[D, !b(R).state.previewMode]]),
p("div", {
class: i(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [b(R).state.previewMode ? "tpl:left-0 tpl:right-0" : b(K).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", b(q).isPreviewingSnapshot.value ? "tpl:top-[104px]" : "tpl:top-14"]]),
style: {
transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
"background-color": "var(--tpl-canvas-bg)"
}
}, [p("div", Nt, [g(O, { name: "tpl-restore-btn" }, {
default: l(() => [b(B).conditionPreview.hasHiddenBlocks.value ? (s(), m("button", {
key: 0,
class: "tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-warning)",
"border-color": "var(--tpl-warning)",
"backdrop-filter": "blur(8px)"
},
onClick: r[0] ||= (e) => b(B).conditionPreview.reset()
}, [g(b(oe), {
size: 13,
"stroke-width": 2
}), y(" " + c(b(B).t.blockSettings.restoreHiddenBlocks), 1)])) : w("", !0)]),
_: 1
})]), p("main", Pt, [g(ne, {
viewport: b(R).state.viewport,
content: b(R).content.value,
"selected-block-id": b(R).state.selectedBlockId,
"dark-mode": b(R).state.darkMode,
"preview-mode": b(R).state.previewMode,
"locked-blocks": b(I)?.lockedBlocks.value ?? void 0,
onSelectBlock: b(R).selectBlock,
onOpenAiChat: r[1] ||= (e) => b(K).aiChatOpen.value = !0,
onOpenDesignReference: r[2] ||= (e) => b(K).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
e.config.branding !== !1 && !b(V).isWhiteLabeled.value ? (s(), v(ue, {
key: 0,
"position-class": [b(R).state.previewMode ? "tpl:left-0 tpl:right-0" : b(K).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]"]
}, null, 8, ["position-class"])) : w("", !0),
p("div", {
class: "tpl-sr-only",
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
"aria-label": b(B).t.landmarks.reorderAnnouncements
}, c(b(B).keyboardReorder.announcement.value), 9, Ft),
T(g(te, {
"selected-block": b(R).selectedBlock.value,
settings: b(R).content.value.settings,
"shifted-left": b(K).rightPanelOpen.value,
onUpdateBlock: r[3] ||= (e) => b(R).updateBlock(b(R).selectedBlock.value.id, e),
onDeleteBlock: r[4] ||= (e) => b(B).blockActions.deleteBlock(b(R).selectedBlock.value.id),
onDuplicateBlock: r[5] ||= (e) => b(B).blockActions.duplicateBlock(b(R).selectedBlock.value),
onUpdateSettings: b(R).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[D, !b(R).state.previewMode]]),
!b(A) && b(j) ? (s(), v(ht, {
key: 1,
ref_key: "cloudPanelsRef",
ref: S,
config: f.config,
editor: b(R),
core: b(B),
"panel-state": b(K),
"plan-config-instance": b(N),
"test-email": b(U),
"media-lib": b(H),
onSendTestEmail: me
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib"
])) : w("", !0),
b(G).isAvailable.value ? (s(), v(b(d), {
key: 2,
feature: b(G)
}, null, 8, ["feature"])) : w("", !0),
p("div", {
ref: (e) => b(B).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
g(se),
g(fe),
b(le) ? (s(), v(de, { key: 3 })) : w("", !0)
], 46, Mt));
}
}), [["__scopeId", "data-v-04940787"]]);
//#endregion
export { It as default };
+5
-5
{
"version": "0.21.1",
"initialGzipBytes": 286973,
"version": "0.21.2",
"initialGzipBytes": 286975,
"initialRawBytes": 1033853,
"initialFileCount": 38,
"lazyGzipBytes": 190248,
"lazyRawBytes": 624400,
"lazyGzipBytes": 190290,
"lazyRawBytes": 624509,
"lazyFileCount": 52,
"generatedAt": "2026-07-29T19:31:48.705Z"
"generatedAt": "2026-07-30T09:39:43.642Z"
}

@@ -261,3 +261,17 @@ import type { AiConfig } from '@templatical/types';

templateDefaults?: TemplateDefaults;
savedBlocks?: boolean;
/**
* Reusable saved blocks.
*
* - **omitted / `true`** — backed by Templatical Cloud, gated on the
* `saved_modules` plan feature.
* - **`false`** — off entirely; no UI renders.
* - **a {@link SavedBlocksProvider}** — backed by *your* store instead of
* Cloud's, and **not plan-gated**, because the plan feature licenses Cloud's
* storage rather than the editor's UI.
*
* The provider form is the same type `init()` takes, so moving an OSS
* integration to Cloud means deleting this key (to adopt Cloud's store) or
* leaving it exactly as-is (to keep your own) — never rewriting it.
*/
savedBlocks?: boolean | SavedBlocksProvider;
autoSave?: boolean;

@@ -264,0 +278,0 @@ autoSaveDebounce?: number;

{
"name": "@templatical/editor",
"description": "Vue 3 visual drag-and-drop email editor powered by Templatical",
"version": "0.21.1",
"version": "0.21.2",
"bugs": "https://github.com/templatical/sdk/issues",

@@ -35,5 +35,5 @@ "devDependencies": {

"vue-tsc": "^3.3.8",
"@templatical/core": "0.21.1",
"@templatical/quality": "0.21.1",
"@templatical/types": "0.21.1"
"@templatical/core": "0.21.2",
"@templatical/quality": "0.21.2",
"@templatical/types": "0.21.2"
},

@@ -66,5 +66,5 @@ "exports": {

"peerDependencies": {
"@templatical/media-library": "0.21.1",
"@templatical/quality": "0.21.1",
"@templatical/renderer": "0.21.1"
"@templatical/media-library": "0.21.2",
"@templatical/quality": "0.21.2",
"@templatical/renderer": "0.21.2"
},

@@ -71,0 +71,0 @@ "peerDependenciesMeta": {

import { $ as e, A as t, H as n, J as r, M as i, N as a, P as o, V as s, Z as c, _ as l, b as u, ct as d, f, g as p, h as m, it as h, j as g, l as _, m as v, n as y, ot as b, p as x, s as S, st as C, u as w, v as T, x as E, y as D, z as O } from "./draggable-D840DIZB.js";
import { t as k } from "./timeouts-Bmi_yePw.js";
import { F as A } from "./src-BKI1x1k7.js";
import { T as j, b as M, j as N, t as P } from "./useEditorCore-BA6mspzD.js";
import { _ as F } from "./dist-CiBEt0VR.js";
import { t as I } from "./dist-CxTt8FRE.js";
import { A as L, F as R, c as z, r as B, s as V, t as H, u as U } from "./keys-D7kUmfpE.js";
import { t as W } from "./useI18n-8Wd7G-cq.js";
import { At as G, Dt as K, F as ee, Ft as q, P as J, et as te, j as ne, rt as Y, u as re, w as ie } from "./icons-CYWw8Xfp.js";
import { t as ae } from "./_plugin-vue_export-helper-B3ysoDQm.js";
import { n as X } from "./useCloudI18n-BjNENqkM.js";
import { a as Z, c as oe, d as se, f as Q, i as ce, l as le, n as ue, o as de, p as fe, r as pe, s as me, t as he, u as ge } from "./styles-DMOEiSX9.js";
import { d as $ } from "./ColorPicker-DZSzZ5ZP.js";
import { S as _e, _ as ve, a as ye, c as be, d as xe, f as Se, h as Ce, i as we, l as Te, m as Ee, n as De, o as Oe, r as ke, s as Ae, t as je, u as Me, v as Ne } from "./cloud-BJlbXGTJ.js";
//#region src/cloud/composables/useSnapshotPreview.ts
function Pe(t) {
let { authManager: n, editor: i, history: a, conditionPreview: o, autoSave: s, onError: l } = t, u = e(null), d = c(null), p = c(null), m = !1;
r(() => {
m = !0;
});
let h = f(() => d.value !== null), g = f(() => u.value?.snapshots.value ?? []), _ = f(() => u.value?.isLoading.value ?? !1), v = f(() => u.value?.isRestoring.value ?? !1);
function y() {
i.state.template?.id && !u.value && (u.value = Oe({
authManager: n,
templateId: i.state.template.id,
onRestore: b,
onError: l
}), u.value.loadSnapshots());
}
function b(e) {
i.setContent(e.content, !1), a.clear(), o.reset();
}
async function x(e) {
if (!m) {
if (d.value) {
d.value = e, i.setContent(e.content, !1);
return;
}
i.state.isDirty && i.hasTemplate() && (await i.createSnapshot(), m) || (p.value = structuredClone(i.content.value), s?.pause(), d.value = e, i.setContent(e.content, !1));
}
}
async function S() {
if (!(!d.value || !u.value)) try {
if (await u.value.restoreSnapshot(d.value.id), m || (await u.value.loadSnapshots(), m)) return;
} catch (e) {
throw !m && p.value && i.setContent(p.value, !1), e;
} finally {
m || (d.value = null, p.value = null, s?.resume());
}
}
function C() {
!d.value || !p.value || (i.setContent(p.value, !1), d.value = null, p.value = null, s?.resume());
}
async function w() {
m || u.value && await u.value.loadSnapshots();
}
return {
snapshotHistoryInstance: u,
previewingSnapshot: d,
contentBeforePreview: p,
isPreviewingSnapshot: h,
snapshotHistorySnapshots: g,
snapshotHistoryIsLoading: _,
snapshotHistoryIsRestoring: v,
initSnapshotHistory: y,
handleRestore: b,
handleSnapshotNavigate: x,
confirmRestoreSnapshot: S,
cancelPreview: C,
loadSnapshotHistory: w
};
}
//#endregion
//#region src/cloud/composables/useCloudPanelState.ts
function Fe() {
let e = c(null), t = f({
get: () => e.value === "ai-chat",
set: (t) => e.value = t ? "ai-chat" : null
}), n = f({
get: () => e.value === "scoring",
set: (t) => e.value = t ? "scoring" : null
}), r = f({
get: () => e.value === "design-reference",
set: (t) => e.value = t ? "design-reference" : null
}), i = f({
get: () => e.value === "comments",
set: (t) => e.value = t ? "comments" : null
}), a = c(!1), o = c(!1), s = c(void 0), l = c(!1), u = c(null), d = f(() => e.value !== null), p = f(() => {
let t = e.value;
return t === "ai-chat" || t === "design-reference" || t === "scoring" ? t : null;
}), m = f(() => l.value || e.value === "ai-chat" || e.value === "design-reference" || e.value === "scoring");
function h() {
l.value = !l.value;
}
function g(t) {
l.value = !1, e.value = e.value === t ? null : t;
}
return I(u, () => {
l.value = !1;
}), {
activePanel: e,
aiChatOpen: t,
scoringPanelOpen: n,
designReferenceOpen: r,
commentsOpen: i,
testEmailModalOpen: a,
mediaLibraryOpen: o,
mediaLibraryAccept: s,
aiMenuOpen: l,
aiMenuRef: u,
rightPanelOpen: d,
activeAiFeature: p,
aiButtonActive: m,
toggleAiMenu: h,
handleAiFeatureSelect: g
};
}
//#endregion
//#region src/cloud/composables/useCollabUndoWarning.ts
function Ie(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = c(!1), a = c(!1), { start: o } = F(() => {
a.value = !1;
}, k, { immediate: !1 });
function s() {
i.value || !t.value || n() === 0 || !r.value || (i.value = !0, a.value = !0, o());
}
return {
collabUndoWarningVisible: a,
showCollabUndoWarning: s
};
}
//#endregion
//#region src/cloud/composables/useCloudFeatureFlags.ts
function Le(e) {
let { planConfigInstance: t, aiConfig: n, editor: r } = e, i = f(() => t.hasFeature("ai_generation") && n.hasAnyMenuFeature.value), a = f(() => t.hasFeature("test_email")), o = f(() => !!r.state.template?.id), s = f(() => t.hasFeature("white_label")), l = f(() => t.config.value?.limits.max_templates ?? null), u = f(() => t.config.value?.template_count ?? 0), d = c(!1), p = c("idle"), m = c(""), { start: h } = F(() => {
p.value = "idle";
}, 3e3, { immediate: !1 });
return {
canUseAiGeneration: i,
canSendTestEmail: a,
hasTemplateSaved: o,
isWhiteLabeled: s,
templateLimit: l,
templateCount: u,
isSaveExporting: d,
saveStatus: p,
saveErrorMessage: m,
startSaveStatusClear: h
};
}
//#endregion
//#region src/cloud/composables/useCloudMediaLibrary.ts
function Re(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: i, authManager: a, getMediaConfig: o, onError: s } = e, c = null;
function l(e) {
return {
url: e.url,
alt: e.alt_text || void 0
};
}
async function u(e) {
let r = e?.accept ?? ["images"];
if (e?.files?.length) {
if (t) {
let n = await t({
accept: r,
files: e.files
});
return n ? l(n) : null;
}
return d(e.files[0]);
}
if (t) {
let e = await t({ accept: r });
return e ? l(e) : null;
}
return c &&= (c(null), null), i.value = r, n.value = !0, new Promise((e) => {
c = (t) => {
e(t);
};
});
}
async function d(e) {
let t = f(e);
if (t) return s?.(t), null;
try {
let { MediaApiClient: t } = await import("./src-D6F_3XkE.js");
return l(await new t(a).uploadMedia(e));
} catch (e) {
return s?.(e), null;
}
}
function f(e) {
let t = o?.() ?? null;
if (!t) return null;
let n = t.categories?.images?.mime_types ?? [];
return n.length > 0 && !n.includes(e.type) ? /* @__PURE__ */ Error(`Unsupported image type: ${e.type || "unknown"}. Accepted: ${n.join(", ")}.`) : t.max_file_size > 0 && e.size > t.max_file_size ? /* @__PURE__ */ Error(`Image is too large (${e.size} bytes). Maximum allowed is ${t.max_file_size} bytes.`) : null;
}
function p(e) {
n.value = !1, c?.(l(e)), c = null;
}
function m() {
n.value = !1, c?.(null), c = null;
}
return r(() => {
c &&= (c(null), null);
}), {
handleRequestMedia: u,
handleMediaSelect: p,
handleMediaLibraryClose: m
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function ze(e) {
let { config: t, translations: n, fontsManager: r, emit: i, getCommentsSidebar: o } = e, s = c(!0), l = c(!1), u = c(null), d = !1, p = { value: null }, m = null, h = null, g = new _e({
...t.auth,
onError: t.onError
}), _ = ke({
authManager: g,
onError: t.onError
}), v = c(/* @__PURE__ */ new Map()), y = ve({
authManager: g,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: v
}), b = be({
authManager: g,
onError: t.onError
});
t.mcp?.enabled && je({
editor: y,
channel: b.channel,
onOperation: t.mcp.onOperation
});
let x = null;
t.collaboration?.enabled && (x = Me({
authManager: g,
editor: y,
channel: b.channel,
onError: t.onError,
onCollaboratorJoined: t.collaboration.onCollaboratorJoined,
onCollaboratorLeft: t.collaboration.onCollaboratorLeft,
onBlockLocked: t.collaboration.onBlockLocked,
onBlockUnlocked: t.collaboration.onBlockUnlocked
}), O(() => x.lockedBlocks.value, (e) => {
v.value = e;
}, { immediate: !0 }), Te(y, x));
let S = f(() => !!t.collaboration?.enabled && _.hasFeature("collaboration")), C = P({
editor: y,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
templateDefaults: t.templateDefaults,
customBlocks: [],
paletteBlocks: t.paletteBlocks,
htmlBlockPreview: t.htmlBlockPreview,
colors: t.colors,
mergeTags: t.mergeTags,
logicTags: t.logicTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: Q(t),
onSave: () => {
p.value?.().catch((e) => {
t.onError?.(e);
});
}
},
translations: n,
fontsManager: r,
historyOptions: x ? { isRemoteOperation: () => x._isProcessingRemoteOperation() } : void 0,
autoSaveOptions: {
onChange: async () => {
y.hasTemplate() && (await y.createSnapshot(), m?.snapshotHistoryInstance.value?.loadSnapshots());
},
debounce: t.autoSaveDebounce ?? 5e3,
enabled: () => t.autoSave !== !1 && _.hasFeature("auto_save")
},
themeExtraStyles: () => ({ "--tpl-drop-text": `"${n.canvas.dropHere}"` }),
keyboardOptions: { onBeforeUndo: () => h?.showCollabUndoWarning() },
editorRoot: e.editorRoot,
containerEl: e.containerEl
}), w = Ie({
isCollaborationEnabled: S,
getCollaboratorCount: () => x?.collaborators.value.length ?? 0,
canUndo: C.history.canUndo
});
h = w;
let T = Pe({
authManager: g,
editor: y,
history: C.history,
conditionPreview: C.conditionPreview,
autoSave: C.autoSave,
onError: t.onError
});
m = T;
let E = Fe(), D = Ce(t.ai), k = Le({
planConfigInstance: _,
aiConfig: D,
editor: y
}), A = Re({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: E.mediaLibraryOpen,
mediaLibraryAccept: E.mediaLibraryAccept,
authManager: g,
getMediaConfig: () => _.config.value?.media ?? null,
onError: t.onError
});
j({
onBlockMove: y.moveBlock,
onBlockAdd: y.addBlock
});
let M = we({
authManager: g,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => _.hasFeature("custom_fonts")
}), F = ye({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null,
save: () => y.save(),
exportHtml: (e) => M.exportHtml(e),
onError: t.onError,
isAuthReady: l,
onBeforeTestEmail: t.onBeforeTestEmail
}), I = Se({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null,
getSocketId: () => b.getSocketId(),
onComment: t.onComment,
onError: t.onError,
isAuthReady: l,
hasCommentingFeature: () => t.commenting !== !1 && _.hasFeature("commenting")
});
xe({
comments: I,
channel: b.channel
});
let z = fe({
provider: Ae(g),
editor: y,
onError: t.onError,
isAvailable: () => t.savedBlocks !== !1 && _.hasFeature("saved_modules")
}), W = Ee({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null
});
function G(e) {
E.commentsOpen.value = !0, queueMicrotask(() => {
o()?.filterByBlock(e);
});
}
a(L, A.handleRequestMedia), a(B, g), a(H, D), a(U, I), a(R, W), a(V, {
plan: _,
ai: D,
comments: {
getBlockCount: (e) => I.commentCountByBlock.value.get(e) ?? 0,
openForBlock: G
},
savedBlocks: z.capability
});
function K(e) {
_.hasFeature("theme_customization") && (C.themeOverrides.value = e);
}
function ee(e) {
y.setUiTheme(e);
}
async function q() {
s.value = !0, u.value = null;
try {
if (await g.initialize(), d) return;
l.value = !0;
let e = await De({ authManager: g });
if (d) return;
if (!e.api.ok) throw Error("Health check failed: API is not reachable");
if (!e.auth.ok) throw Error(`Health check failed: authentication error${e.auth.error ? ` - ${e.auth.error}` : ""}`);
if (e.websocket.ok || N.warn("WebSocket health check failed:", e.websocket.error ?? "unknown error", "-- real-time features will be disabled."), await _.fetchConfig(), d) return;
r.setCustomFontsEnabled(_.hasFeature("custom_fonts")), t.customBlocks?.length && _.hasFeature("custom_blocks") && C.registerCustomBlocks(t.customBlocks), t.theme && _.hasFeature("theme_customization") && (C.themeOverrides.value = t.theme), i("ready");
} catch (e) {
if (d) return;
let n = e instanceof Error ? e : Error("Initialization failed", { cause: e });
u.value = n, t.onError?.(n);
} finally {
d || (s.value = !1);
}
}
function J() {
d = !0, r.cleanupFontLinks(), b.disconnect(), C.destroy(), t.onUnmount?.();
}
return {
isInitializing: s,
isAuthReady: l,
initError: u,
isDestroyed: () => d,
authManager: g,
planConfigInstance: _,
websocket: b,
collaboration: x,
isCollaborationEnabled: S,
editor: y,
core: C,
aiConfig: D,
featureFlags: k,
mediaLib: A,
exporter: M,
testEmail: F,
commentsInstance: I,
savedBlocks: z,
scoringInstance: W,
panelState: E,
snapshotPreview: T,
collabWarning: w,
onSaveHook: p,
initialize: q,
destroy: J,
setThemeOverrides: K,
setUiTheme: ee,
openCommentsForBlock: G
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Be(e, t) {
let n = async (e) => {
if (A(e)) {
let n = e;
try {
n.renderedHtml = await t.renderCustomBlock(n);
} catch {
n.renderedHtml = `<!-- Custom block render error: ${n.customType} -->`;
}
}
if (e.type === "section" && "children" in e) {
let t = e;
for (let e of t.children) for (let t of e) await n(t);
}
};
for (let t of e.blocks) await n(t);
}
//#endregion
//#region src/cloud/composables/useCloudLifecycle.ts
function Ve(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return Ne(i.config.value.websocket);
}
async function d(e) {
let i = await n.create(e);
return l() ? i : (t.onCreate?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function f(e) {
let i = await n.load(e);
return l() ? i : (t.onLoad?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function p() {
c.isSaveExporting.value = !0, c.saveStatus.value = "idle";
try {
if (await Be(n.content.value, o.registry), l()) throw Error("Component unmounted during save");
let e = await n.save();
if (l()) throw Error("Component unmounted during save");
a.initSnapshotHistory(), a.snapshotHistoryInstance.value?.loadSnapshots();
let r = await s.exportHtml(e.id);
if (l()) throw Error("Component unmounted during save");
let i = {
templateId: e.id,
html: r.html,
mjml: r.mjml,
content: e.content
};
return t.onSave?.(i), c.saveStatus.value = "saved", c.startSaveStatusClear(), i;
} catch (e) {
throw l() || (c.saveStatus.value = "error", c.saveErrorMessage.value = e instanceof Error ? e.message : "Save failed"), e;
} finally {
l() || (c.isSaveExporting.value = !1);
}
}
return {
createTemplate: d,
loadTemplate: f,
saveTemplate: p
};
}
//#endregion
//#region src/cloud/composables/useCloudSaveGate.ts
function He(e) {
let t = c(!1), n = null, r = f(() => e.planConfig.value?.accessibility?.blockOnError === !0), i = f(() => r.value ? e.issues.value.filter((e) => e.severity === "error") : []), a = f(() => i.value.length > 0);
async function o(e) {
return a.value ? (n = e, t.value = !0, !1) : (await e(), !0);
}
async function s() {
let e = n;
n = null, t.value = !1, e && await e();
}
function l() {
n = null, t.value = !1;
}
return {
shouldBlock: a,
blockingIssues: i,
modalOpen: t,
tryRunSave: o,
confirmAndSave: s,
cancel: l
};
}
//#endregion
//#region src/cloud/components/CloudSaveGateModal.vue?vue&type=script&setup=true&lang.ts
var Ue = ["aria-label"], We = { class: "tpl:flex tpl:max-h-[80vh] tpl:w-full tpl:max-w-md tpl:flex-col tpl:gap-4 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:p-5 tpl:shadow-[var(--tpl-shadow-md)]" }, Ge = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Ke = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, qe = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Je = { class: "tpl:m-0 tpl:flex tpl:max-h-64 tpl:list-none tpl:flex-col tpl:gap-1.5 tpl:overflow-y-auto tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2" }, Ye = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, Xe = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Ze = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, Qe = /* @__PURE__ */ E({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = X();
return (t, a) => (i(), v(y, {
"enter-active-class": "tpl:transition-opacity tpl:duration-150",
"leave-active-class": "tpl:transition-opacity tpl:duration-150",
"enter-from-class": "tpl:opacity-0",
"leave-to-class": "tpl:opacity-0"
}, {
default: s(() => [e.open ? (i(), p("div", {
key: 0,
role: "dialog",
"aria-modal": "true",
"aria-label": h(r).saveGate.title,
class: "tpl:fixed tpl:inset-0 tpl:z-50 tpl:flex tpl:items-center tpl:justify-center tpl:bg-black/40 tpl:p-6",
onClick: a[2] ||= _((e) => n("cancel"), ["self"])
}, [x("div", We, [
x("header", Ge, [D(h(re), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), x("h2", Ke, d(h(r).saveGate.title), 1)]),
x("p", qe, d(h(r).saveGate.body), 1),
x("ul", Je, [(i(!0), p(w, null, o(e.issues, (e) => (i(), p("li", {
key: `${e.ruleId}-${e.blockId ?? "template"}`,
class: "tpl:flex tpl:flex-col tpl:gap-0.5 tpl:rounded tpl:px-2 tpl:py-1.5"
}, [x("span", Ye, d(e.message), 1), x("span", Xe, d(e.ruleId), 1)]))), 128))]),
x("footer", Ze, [x("button", {
type: "button",
class: "tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]",
onClick: a[0] ||= (e) => n("cancel")
}, d(h(r).saveGate.cancel), 1), x("button", {
type: "button",
class: "tpl:rounded-md tpl:bg-[var(--tpl-danger)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-white",
onClick: a[1] ||= (e) => n("confirm")
}, d(h(r).saveGate.confirm), 1)])
])], 8, Ue)) : m("", !0)]),
_: 1
}));
}
}), $e = {
class: "tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4",
style: {
"background-color": "color-mix(in srgb, var(--tpl-bg) 80%, transparent)",
"backdrop-filter": "blur(12px)",
"-webkit-backdrop-filter": "blur(12px)",
"box-shadow": "var(--tpl-shadow-md)",
"border-bottom": "1px solid var(--tpl-border)"
}
}, et = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, tt = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, nt = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, rt = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, it = ["data-tooltip"], at = {
key: 1,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-success)]"
}, ot = {
key: 2,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-text-muted)]"
}, st = ["aria-label", "aria-expanded"], ct = {
key: 0,
class: "tpl:inline-flex tpl:size-4.5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:text-[10px] tpl:font-semibold tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]"
}, lt = ["aria-expanded"], ut = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, dt = ["disabled"], ft = ["disabled"], pt = /* @__PURE__ */ E({
__name: "CloudHeader",
props: {
editor: {},
core: {},
featureFlags: {},
panelState: {},
snapshotPreview: {},
commentsInstance: {},
testEmail: {},
websocket: {},
collaboration: {},
isCollaborationEnabled: { type: Boolean },
isSaveDisabled: { type: Boolean },
isSaving: { type: Boolean }
},
emits: ["save"],
setup(e) {
let t = u(() => import("./CollaboratorBar-BS3rJy6-.js")), n = u(() => import("./SnapshotHistory-Bf1uovti.js")), r = u(() => import("./AiFeatureMenu-Duwg413F.js")), { t: a, format: o } = X();
return (c, l) => (i(), p("header", $e, [
x("div", et, [e.featureFlags.templateLimit.value === null ? m("", !0) : (i(), p("span", tt, d(h(o)(h(a).header.templatesUsed, {
used: e.featureFlags.templateCount.value,
max: e.featureFlags.templateLimit.value
})), 1))]),
x("div", nt, [
D(de, {
viewport: e.editor.state.viewport,
onChange: e.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
D(ce, {
"dark-mode": e.editor.state.darkMode,
onChange: e.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
D(Z, {
"preview-mode": e.editor.state.previewMode,
onChange: e.editor.setPreviewMode
}, null, 8, ["preview-mode", "onChange"]),
e.collaboration && e.isCollaborationEnabled ? (i(), v(h(t), {
key: 0,
collaborators: e.collaboration.collaborators.value,
"is-connected": e.websocket.isConnected.value
}, null, 8, ["collaborators", "is-connected"])) : m("", !0),
e.snapshotPreview.snapshotHistoryInstance.value ? (i(), v(h(n), {
key: 1,
snapshots: e.snapshotPreview.snapshotHistorySnapshots.value,
"is-loading": e.snapshotPreview.snapshotHistoryIsLoading.value,
"is-restoring": e.snapshotPreview.snapshotHistoryIsRestoring.value,
onLoad: e.snapshotPreview.loadSnapshotHistory,
onNavigate: e.snapshotPreview.handleSnapshotNavigate
}, null, 8, [
"snapshots",
"is-loading",
"is-restoring",
"onLoad",
"onNavigate"
])) : m("", !0)
]),
x("div", rt, [
e.featureFlags.saveStatus.value === "error" ? (i(), p("div", {
key: 0,
"aria-live": "assertive",
class: "tpl-tooltip tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-danger)]",
"data-tooltip": e.featureFlags.saveErrorMessage.value
}, [D(h(G), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saveFailed), 1)], 8, it)) : e.featureFlags.saveStatus.value === "saved" ? (i(), p("div", at, [D(h(q), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saved), 1)])) : e.editor.state.isDirty ? (i(), p("div", ot, [l[4] ||= x("span", { class: "tpl-pulse tpl:size-1.5 tpl:rounded-full tpl:bg-[var(--tpl-primary)]" }, null, -1), T(" " + d(h(a).header.unsaved), 1)])) : m("", !0),
e.commentsInstance.isEnabled.value && e.featureFlags.hasTemplateSaved.value ? (i(), p("button", {
key: 3,
"aria-label": e.commentsInstance.unresolvedCount.value > 0 ? `${h(a).comments.button} (${e.commentsInstance.unresolvedCount.value})` : h(a).comments.button,
"aria-expanded": e.panelState.commentsOpen.value,
class: b(h($)),
style: C({
backgroundColor: e.panelState.commentsOpen.value ? "var(--tpl-primary)" : "transparent",
color: e.panelState.commentsOpen.value ? "var(--tpl-bg)" : "var(--tpl-primary)",
borderColor: "var(--tpl-primary)"
}),
onClick: l[0] ||= (t) => e.panelState.commentsOpen.value = !e.panelState.commentsOpen.value
}, [
D(h(te), {
size: 16,
"stroke-width": 2
}),
T(" " + d(h(a).comments.button) + " ", 1),
e.commentsInstance.unresolvedCount.value > 0 && !e.panelState.commentsOpen.value ? (i(), p("span", ct, d(e.commentsInstance.unresolvedCount.value), 1)) : m("", !0)
], 14, st)) : m("", !0),
e.featureFlags.canUseAiGeneration.value && e.featureFlags.hasTemplateSaved.value ? (i(), p("div", {
key: 4,
ref: (t) => e.panelState.aiMenuRef.value = t,
class: "tpl:relative"
}, [x("button", {
"aria-expanded": e.panelState.aiMenuOpen.value,
class: b(["tpl-ai-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-4 tpl:py-2 tpl:text-sm tpl:font-semibold tpl:whitespace-nowrap tpl:transition-all tpl:duration-200", e.panelState.aiButtonActive.value ? "tpl-ai-btn--active" : "tpl-ai-btn--idle"]),
onClick: l[1] ||= _((...t) => e.panelState.toggleAiMenu && e.panelState.toggleAiMenu(...t), ["stop"])
}, [D(h(ie), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), T(" " + d(h(a).aiChat.button), 1)], 10, lt), D(y, {
"enter-active-class": "tpl:transition-all tpl:duration-150 tpl:ease-out",
"enter-from-class": "tpl:scale-95 tpl:opacity-0",
"enter-to-class": "tpl:scale-100 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-100 tpl:ease-in",
"leave-from-class": "tpl:scale-100 tpl:opacity-100",
"leave-to-class": "tpl:scale-95 tpl:opacity-0"
}, {
default: s(() => [e.panelState.aiMenuOpen.value ? (i(), p("div", ut, [D(h(r), {
"active-feature": e.panelState.activeAiFeature.value,
onSelect: e.panelState.handleAiFeatureSelect
}, null, 8, ["active-feature", "onSelect"])])) : m("", !0)]),
_: 1
})], 512)) : m("", !0),
e.testEmail.isEnabled.value && e.featureFlags.canSendTestEmail.value ? (i(), p("button", {
key: 5,
class: b(h($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.testEmail.isSending.value || !e.featureFlags.hasTemplateSaved.value,
onClick: l[2] ||= (t) => e.panelState.testEmailModalOpen.value = !0
}, [e.testEmail.isSending.value ? (i(), v(h(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(ne), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(h(a).testEmail.button), 1)], 10, dt)) : m("", !0),
x("button", {
class: b(h($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.isSaveDisabled,
onClick: l[3] ||= (e) => c.$emit("save")
}, [e.isSaving ? (i(), v(h(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(J), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(e.isSaving ? h(a).header.saving : h(a).header.save), 1)], 10, ft)
])
]));
}
}), mt = /* @__PURE__ */ E({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {}
},
emits: ["send-test-email"],
setup(e, { expose: t, emit: n }) {
let r = u(() => import("./AiChatSidebar-A1CuWGY0.js")), a = u(() => import("./CommentsSidebar-DHdRiGPX.js")), o = u(() => import("./DesignReferenceSidebar-Dre99DTH.js")), s = u(() => import("./TemplateScoringPanel-CTk8WwxU.js")), l = u(() => import("./TestEmailModal-BJTDxFHh.js")), d = u(async () => {
try {
return (await import("./src-D6F_3XkE.js")).MediaLibraryModal;
} catch {
throw Error("[Templatical] Cloud media library requires the optional peer dependency '@templatical/media-library'. Please install it.");
}
}), f = n;
function m(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
let g = c(null);
function _(e) {
g.value?.filterByBlock(e);
}
return t({ filterCommentsByBlock: _ }), (t, n) => (i(), p(w, null, [
D(h(r), {
visible: e.panelState.aiChatOpen.value,
"on-apply": (t) => m(t, e.core, e.editor),
onClose: n[0] ||= (t) => e.panelState.aiChatOpen.value = !1
}, null, 8, ["visible", "on-apply"]),
D(h(s), {
visible: e.panelState.scoringPanelOpen.value,
onClose: n[1] ||= (t) => e.panelState.scoringPanelOpen.value = !1
}, null, 8, ["visible"]),
D(h(o), {
visible: e.panelState.designReferenceOpen.value,
"has-existing-blocks": e.editor.content.value.blocks.length > 0,
onClose: n[2] ||= (t) => e.panelState.designReferenceOpen.value = !1,
onApply: n[3] ||= (t) => m(t, e.core, e.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
D(h(a), {
ref_key: "commentsSidebar",
ref: g,
visible: e.panelState.commentsOpen.value,
onClose: n[4] ||= (t) => e.panelState.commentsOpen.value = !1
}, null, 8, ["visible"]),
D(h(l), {
visible: e.panelState.testEmailModalOpen.value,
"allowed-emails": e.testEmail.allowedEmails.value,
"is-sending": e.testEmail.isSending.value,
error: e.testEmail.error.value,
onSend: n[5] ||= (e) => f("send-test-email", e),
onClose: n[6] ||= (t) => e.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
D(h(d), {
visible: e.panelState.mediaLibraryOpen.value,
accept: e.panelState.mediaLibraryAccept.value,
"popover-target": e.core.popoverRoot.value,
onSelect: e.mediaLib.handleMediaSelect,
onClose: e.mediaLib.handleMediaLibraryClose
}, null, 8, [
"visible",
"accept",
"popover-target",
"onSelect",
"onClose"
])
], 64));
}
}), ht = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, gt = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, _t = { class: "tpl:flex tpl:w-12 tpl:shrink-0 tpl:flex-col tpl:items-center tpl:gap-4 tpl:py-5 tpl:border-r tpl:border-[var(--tpl-border)]" }, vt = /* @__PURE__ */ E({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(e) {
return (t, n) => e.visible ? (i(), p("div", ht, [n[1] ||= l("<div class=\"tpl:flex tpl:h-14 tpl:shrink-0 tpl:items-center tpl:justify-between tpl:px-4 tpl:border-b tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-5 tpl:w-28 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl:flex tpl:gap-3\"><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div></div>", 1), x("div", gt, [x("div", _t, [(i(), p(w, null, o(5, (e) => x("div", {
key: e,
class: "tpl-shimmer tpl:size-7 tpl:rounded-[var(--tpl-radius-sm)]"
})), 64))]), n[0] ||= l("<div class=\"tpl:flex tpl:flex-1 tpl:items-start tpl:justify-center tpl:overflow-auto tpl:p-8 tpl:bg-[var(--tpl-canvas-bg)]\"><div class=\"tpl:w-full tpl:max-w-[600px] tpl:rounded-[var(--tpl-radius)] tpl:p-6 tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)]\"><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-3/4 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-5/6 tpl:rounded\"></div></div><div class=\"tpl:py-4\"><div class=\"tpl-shimmer tpl:h-44 tpl:w-full tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-2/3 tpl:rounded\"></div></div><div class=\"tpl:flex tpl:justify-center tpl:py-4\"><div class=\"tpl-shimmer tpl:h-10 tpl:w-36 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/2 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/3 tpl:rounded\"></div></div></div></div><div class=\"tpl:flex tpl:w-[320px] tpl:shrink-0 tpl:flex-col tpl:gap-4 tpl:p-4 tpl:border-l tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-8 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div></div>", 2)])])) : m("", !0);
}
}), yt = {
key: 0,
role: "alert",
class: "tpl-error tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-6 tpl:px-8 tpl:bg-[var(--tpl-bg)]"
}, bt = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, xt = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, St = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, Ct = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, wt = /* @__PURE__ */ E({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(e, { emit: t }) {
let n = t, { t: r } = X();
function a(e) {
return "isUnauthorized" in e && e.isUnauthorized ? r.error.authFailed : "isNotFound" in e && e.isNotFound ? r.error.templateNotFound : r.error.defaultMessage;
}
function o(e) {
return "isNotFound" in e && !!e.isNotFound;
}
return (t, s) => e.visible && e.error ? (i(), p("div", yt, [
x("div", bt, [D(h(G), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
x("div", xt, [x("h2", St, d(h(r).error.title), 1), x("p", Ct, d(a(e.error)), 1)]),
o(e.error) ? m("", !0) : (i(), p("button", {
key: 0,
class: "tpl-btn tpl-btn-primary tpl:inline-flex tpl:items-center tpl:gap-2 tpl:rounded-md tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: s[0] ||= (e) => n("retry")
}, d(h(r).error.retry), 1))
])) : m("", !0);
}
}), Tt = {
key: 0,
class: "tpl-preview-banner tpl:absolute tpl:top-14 tpl:right-0 tpl:left-0 tpl:z-40 tpl:flex tpl:items-center tpl:justify-center tpl:gap-4 tpl:px-4 tpl:py-3 tpl:bg-[var(--tpl-primary-light)] tpl:border-b tpl:border-[var(--tpl-primary)]"
}, Et = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, Dt = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Ot = /* @__PURE__ */ E({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = X();
return (t, a) => e.visible ? (i(), p("div", Tt, [x("div", Et, [D(h(K), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), x("span", null, d(h(r).snapshotPreview.message), 1)]), x("div", Dt, [x("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:text-[var(--tpl-text-muted)] tpl:border tpl:border-[var(--tpl-border)]",
style: { "background-color": "transparent" },
onClick: a[0] ||= (e) => n("cancel")
}, d(h(r).snapshotPreview.cancel), 1), x("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: a[1] ||= (e) => n("confirm")
}, d(h(r).snapshotPreview.restore), 1)])])) : m("", !0);
}
}), kt = {
key: 0,
role: "status",
"aria-live": "polite",
class: "tpl:absolute tpl:top-16 tpl:left-1/2 tpl:z-toast tpl:-translate-x-1/2 tpl:rounded-[var(--tpl-radius)] tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:shadow-lg",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-text)",
border: "1px solid var(--tpl-warning)"
}
}, At = /* @__PURE__ */ E({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(e) {
let { t } = W();
return (n, r) => e.visible ? (i(), p("div", kt, d(h(t).history.collabWarning), 1)) : m("", !0);
}
}), jt = ["data-tpl-theme"], Mt = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, Nt = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, Pt = ["aria-label"], Ft = /*#__PURE__*/ ae(/* @__PURE__ */ E({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(e, { expose: r, emit: o }) {
let l = u(() => import("./SavedBlocksPanels-D-pA_wfk.js")), f = e;
a(z, f.cloudTranslations);
let w = o, E = c(null), O = c(null), k = ze({
config: f.config,
translations: f.translations,
fontsManager: f.fontsManager,
emit: w,
getCommentsSidebar: () => E.value ? { filterByBlock: E.value.filterCommentsByBlock } : null,
editorRoot: f.shadowRoot,
containerEl: O
}), { isInitializing: A, isAuthReady: j, initError: N, planConfigInstance: P, websocket: F, collaboration: I, isCollaborationEnabled: L, editor: R, core: B, featureFlags: V, mediaLib: H, exporter: U, testEmail: W, commentsInstance: G, savedBlocks: K, panelState: q, snapshotPreview: J, collabWarning: te, setThemeOverrides: ne, setUiTheme: Y } = k, { showNotice: re } = M(() => f.config.smallScreenNotice);
async function ie(e) {
try {
await W.sendTestEmail(e), q.testEmailModalOpen.value = !1;
} catch {}
}
async function ae() {
try {
await J.confirmRestoreSnapshot();
} catch {}
}
let X = Ve({
config: f.config,
editor: R,
websocket: F,
planConfigInstance: P,
snapshotPreview: J,
core: B,
exporter: U,
featureFlags: V,
isDestroyed: k.isDestroyed
}), Z = He({
issues: B.templateLint ? B.templateLint.issues : c([]),
planConfig: P.config
});
async function Q() {
await Z.tryRunSave(() => X.saveTemplate().catch((e) => f.config.onError?.(e)));
}
return k.onSaveHook.value = Q, t(() => {
k.initialize();
}), g(() => {
k.destroy();
}), r({
getContent: () => R.content.value,
setContent: (e) => R.setContent(e),
setTheme: Y,
setThemeOverrides: ne,
create: X.createTemplate,
load: X.loadTemplate,
save: X.saveTemplate,
sendTestEmail: W.sendTestEmail
}), (t, r) => (i(), p("div", {
ref_key: "rootEl",
ref: O,
class: b(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": h(R).state.darkMode }]),
"data-tpl-theme": h(B).resolvedTheme.value,
style: C(h(B).themeStyles.value),
onDragover: r[6] ||= _(() => {}, ["prevent"]),
onDrop: r[7] ||= _(() => {}, ["prevent"])
}, [
D(ge),
D(y, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-100",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: s(() => [D(vt, { visible: h(A) || h(R).state.isLoading }, null, 8, ["visible"])]),
_: 1
}),
D(y, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-0",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: s(() => [D(wt, {
error: h(N),
visible: !!h(N) && !h(A),
onRetry: h(k).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
D(pt, {
editor: h(R),
core: h(B),
"feature-flags": h(V),
"panel-state": h(q),
"snapshot-preview": h(J),
"comments-instance": h(G),
"test-email": h(W),
websocket: h(F),
collaboration: h(I),
"is-collaboration-enabled": h(L),
"is-saving": h(R).state.isSaving || h(V).isSaveExporting.value,
"is-save-disabled": h(R).state.isSaving || h(V).isSaveExporting.value || !h(R).state.isDirty,
onSave: Q
}, null, 8, [
"editor",
"core",
"feature-flags",
"panel-state",
"snapshot-preview",
"comments-instance",
"test-email",
"websocket",
"collaboration",
"is-collaboration-enabled",
"is-saving",
"is-save-disabled"
]),
D(Qe, {
open: h(Z).modalOpen.value,
issues: h(Z).blockingIssues.value,
onCancel: h(Z).cancel,
onConfirm: h(Z).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
D(Ot, {
visible: h(J).isPreviewingSnapshot.value,
onCancel: h(J).cancelPreview,
onConfirm: ae
}, null, 8, ["visible", "onCancel"]),
D(y, {
"enter-active-class": "tpl:transition-all tpl:duration-200 tpl:ease-out",
"enter-from-class": "tpl:translate-y-[-8px] tpl:opacity-0",
"enter-to-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-300 tpl:ease-in",
"leave-from-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-to-class": "tpl:translate-y-[-8px] tpl:opacity-0"
}, {
default: s(() => [D(At, { visible: h(te).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
n(D(le, null, null, 512), [[S, !h(R).state.previewMode]]),
x("div", {
class: b(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [h(R).state.previewMode ? "tpl:left-0 tpl:right-0" : h(q).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", h(J).isPreviewingSnapshot.value ? "tpl:top-[104px]" : "tpl:top-14"]]),
style: {
transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
"background-color": "var(--tpl-canvas-bg)"
}
}, [x("div", Mt, [D(y, { name: "tpl-restore-btn" }, {
default: s(() => [h(B).conditionPreview.hasHiddenBlocks.value ? (i(), p("button", {
key: 0,
class: "tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-warning)",
"border-color": "var(--tpl-warning)",
"backdrop-filter": "blur(8px)"
},
onClick: r[0] ||= (e) => h(B).conditionPreview.reset()
}, [D(h(ee), {
size: 13,
"stroke-width": 2
}), T(" " + d(h(B).t.blockSettings.restoreHiddenBlocks), 1)])) : m("", !0)]),
_: 1
})]), x("main", Nt, [D(se, {
viewport: h(R).state.viewport,
content: h(R).content.value,
"selected-block-id": h(R).state.selectedBlockId,
"dark-mode": h(R).state.darkMode,
"preview-mode": h(R).state.previewMode,
"locked-blocks": h(I)?.lockedBlocks.value ?? void 0,
onSelectBlock: h(R).selectBlock,
onOpenAiChat: r[1] ||= (e) => h(q).aiChatOpen.value = !0,
onOpenDesignReference: r[2] ||= (e) => h(q).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
e.config.branding !== !1 && !h(V).isWhiteLabeled.value ? (i(), v(pe, {
key: 0,
"position-class": [h(R).state.previewMode ? "tpl:left-0 tpl:right-0" : h(q).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]"]
}, null, 8, ["position-class"])) : m("", !0),
x("div", {
class: "tpl-sr-only",
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
"aria-label": h(B).t.landmarks.reorderAnnouncements
}, d(h(B).keyboardReorder.announcement.value), 9, Pt),
n(D(oe, {
"selected-block": h(R).selectedBlock.value,
settings: h(R).content.value.settings,
"shifted-left": h(q).rightPanelOpen.value,
onUpdateBlock: r[3] ||= (e) => h(R).updateBlock(h(R).selectedBlock.value.id, e),
onDeleteBlock: r[4] ||= (e) => h(B).blockActions.deleteBlock(h(R).selectedBlock.value.id),
onDuplicateBlock: r[5] ||= (e) => h(B).blockActions.duplicateBlock(h(R).selectedBlock.value),
onUpdateSettings: h(R).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[S, !h(R).state.previewMode]]),
!h(A) && h(j) ? (i(), v(mt, {
key: 1,
ref_key: "cloudPanelsRef",
ref: E,
config: f.config,
editor: h(R),
core: h(B),
"panel-state": h(q),
"plan-config-instance": h(P),
"test-email": h(W),
"media-lib": h(H),
onSendTestEmail: ie
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib"
])) : m("", !0),
h(K).isAvailable.value ? (i(), v(h(l), {
key: 2,
feature: h(K)
}, null, 8, ["feature"])) : m("", !0),
x("div", {
ref: (e) => h(B).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
D(ue),
D(he),
h(re) ? (i(), v(me, { key: 3 })) : m("", !0)
], 46, jt));
}
}), [["__scopeId", "data-v-04940787"]]);
//#endregion
export { Ft as default };
//# sourceMappingURL=CloudEditor-B3hqbwfP.js.map

Sorry, the diff of this file is too big to display

import { B as e, F as t, G as n, H as r, I as i, J as a, K as o, L as s, P as c, R as l, U as u, V as d, W as f, z as p } from "./src-BKI1x1k7.js";
//#endregion
//#region ../renderer/src/render-context.ts
var m = `https://cdn.jsdelivr.net/npm/@templatical/renderer@${{
name: "@templatical/renderer",
description: "Render Templatical email templates to MJML",
version: "0.21.1",
bugs: "https://github.com/templatical/sdk/issues",
dependencies: { "@templatical/types": "workspace:*" },
devDependencies: {
"@resvg/resvg-js": "^2.6.2",
mjml: "^5.4.0",
typescript: "^6.0.3",
vitest: "^4.1.10"
},
exports: { ".": {
types: "./dist/index.d.ts",
import: "./dist/index.js"
} },
files: ["dist", "assets"],
homepage: "https://templatical.com",
keywords: [
"email",
"email-template",
"html-email",
"mjml",
"renderer",
"templatical"
],
license: "MIT",
module: "./dist/index.js",
publishConfig: { access: "public" },
repository: {
type: "git",
url: "git+https://github.com/templatical/sdk.git",
directory: "packages/renderer"
},
scripts: {
build: "tsdown && node scripts/rasterize-social.mjs",
test: "vitest run --config vitest.config.ts",
typecheck: "tsc --noEmit"
},
type: "module",
types: "./dist/index.d.ts"
}.version}/assets/social`, h = {
arial: "Arial, sans-serif",
helvetica: "Helvetica, sans-serif",
georgia: "Georgia, serif",
"times new roman": "'Times New Roman', serif",
verdana: "Verdana, sans-serif",
"trebuchet ms": "'Trebuchet MS', sans-serif",
"courier new": "'Courier New', monospace",
tahoma: "Tahoma, sans-serif"
}, g = class e {
containerWidth;
customFonts;
defaultFallbackFont;
allowHtmlBlocks;
customBlockHtml;
socialIconsBaseUrl;
constructor(e, t, n, r, i = /* @__PURE__ */ new Map(), a = m) {
this.containerWidth = e, this.customFonts = t, this.defaultFallbackFont = n, this.allowHtmlBlocks = r, this.customBlockHtml = i, this.socialIconsBaseUrl = a;
}
withContainerWidth(t) {
return new e(t, this.customFonts, this.defaultFallbackFont, this.allowHtmlBlocks, this.customBlockHtml, this.socialIconsBaseUrl);
}
resolveFontFamily(e) {
for (let t of this.customFonts) if (t.name.toLowerCase() === e.toLowerCase()) {
let e = t.fallback ?? this.defaultFallbackFont;
return `'${t.name}', ${e}`;
}
return h[e.toLowerCase()] || e;
}
}, _ = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
"\"": "&quot;",
"'": "&#039;"
}, v = /[&<>"']/g;
function y(e) {
return e === "" ? "" : e.replace(v, (e) => _[e] ?? e);
}
function b(e) {
return e === "" ? "" : e.replace(v, (e) => _[e] ?? e);
}
function x(e) {
return e === "" ? "" : b(e).replace(/[;{}\r\n]/g, "");
}
function S(e) {
return e === "" ? "" : C(e, (e) => w(e, "data-merge-tag") ?? w(e, "data-logic-merge-tag"));
}
function C(e, t) {
let n = "", r = 0;
for (; r < e.length;) {
let i = e.indexOf("<span", r);
if (i === -1) {
n += e.substring(r);
break;
}
let a = e[i + 5];
if (a !== ">" && a !== " " && a !== " " && a !== "\n" && a !== "\r" && a !== "/") {
n += e.substring(r, i + 5), r = i + 5;
continue;
}
let o = e.indexOf(">", i + 5);
if (o === -1) {
n += e.substring(r);
break;
}
let s = e.indexOf("</span>", o + 1);
if (s === -1) {
n += e.substring(r);
break;
}
let c = t(e.substring(i + 5, o));
if (c === null) {
n += e.substring(r, i + 5), r = i + 5;
continue;
}
n += e.substring(r, i), n += c, r = s + 7;
}
return n;
}
function w(e, t) {
let n = RegExp(`(?:^|\\s)${t}="([^"<>]*)"`).exec(e);
return n ? n[1] : null;
}
//#endregion
//#region ../renderer/src/padding.ts
function T(e) {
return `${e.top}px ${e.right}px ${e.bottom}px ${e.left}px`;
}
//#endregion
//#region ../renderer/src/utils.ts
function E(e, t) {
return e ? ` ${t === "native" ? "background-color" : "container-background-color"}="${e}"` : "";
}
//#endregion
//#region ../renderer/src/visibility.ts
function D(e) {
let t = e.visibility;
return t ? !t.desktop && !t.mobile : !1;
}
function O(e) {
let t = k(e);
return t === "" ? "" : ` css-class="${t}"`;
}
function k(e) {
let t = e.visibility;
if (!t) return "";
let n = [];
return t.desktop || n.push("tpl-hide-desktop"), t.mobile || n.push("tpl-hide-mobile"), n.join(" ");
}
//#endregion
//#region ../renderer/src/renderers/title.ts
function A(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = j(S(e.content)), o = a[e.level] ?? a[2], s = e.color ? `\n color="${b(e.color)}"` : "", c = e.textAlign, l = ee(e.fontFamily, t), u = O(e), d = `h${a[e.level] ? e.level : 2}`;
return `<mj-text
font-size="${o}px"${s}
align="${c}"
line-height="1.3"
padding="${n}"${r}${l}${u}
><${d} style="margin:0;font-size:inherit;color:inherit;line-height:inherit">${i}</${d}></mj-text>`;
}
function j(e) {
let t = e.match(/^\s*<p\b[^>]*>([\s\S]*)<\/p>\s*$/);
return !t || /<\/p>\s*<p\b/i.test(t[1]) ? e : t[1];
}
function ee(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/paragraph.ts
function te(e, t) {
if (D(e) || e.content.replace(/<\/?p\b[^<>]*>/gi, "").trim() === "") return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = S(e.content);
return `<mj-text
line-height="1.5"
padding="${n}"${r}${O(e)}
>${i}</mj-text>`;
}
//#endregion
//#region ../renderer/src/renderers/image.ts
function ne(e, t) {
if (D(e) || e.src === "") return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = e.width === "full" ? t.containerWidth + "px" : e.width + "px", a = O(e), o = "";
e.linkUrl && (o = ` href="${b(e.linkUrl)}"`, e.linkOpenInNewTab && (o += " target=\"_blank\" rel=\"noopener\""));
let s = b(e.src), c = e.decorative === !0;
return `<mj-image
src="${s}"
alt="${c ? "" : b(e.alt)}"
width="${i}"
align="${e.align}"
padding="${n}"${r}${o}${a}${c ? " role=\"presentation\"" : ""}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/button.ts
function M(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = T(e.buttonPadding), a = e.url === "" ? "" : b(e.url), o = a === "" ? "" : ` href="${a}"`, s = b(e.backgroundColor), c = b(e.textColor), l = e.fontSize, u = e.borderRadius, d = y(e.text);
return `<mj-button${o}${e.openInNewTab ? " target=\"_blank\" rel=\"noopener\"" : ""}
background-color="${s}"
color="${c}"
font-size="${l}px"
font-weight="bold"
border-radius="${u}px"
inner-padding="${i}"
padding="${n}"${r}${N(e.fontFamily, t)}${P(e.width)}${O(e)}
>${d}</mj-button>`;
}
function N(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
function P(e) {
return e === void 0 ? "" : ` width="${e === "full" ? "100%" : `${e}px`}"`;
}
//#endregion
//#region ../renderer/src/renderers/divider.ts
function F(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = e.styles.backgroundColor ? ` container-background-color="${b(e.styles.backgroundColor)}"` : "", i = e.width === "full" ? "100%" : e.width + "px";
return `<mj-divider
border-width="${e.thickness}px"
border-style="${e.lineStyle}"
border-color="${b(e.color)}"
width="${i}"
padding="${n}"${r}${O(e)}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/spacer.ts
function I(e, t) {
return D(e) ? "" : `<mj-spacer height="${e.height}px" padding="0"${e.styles.backgroundColor ? ` container-background-color="${b(e.styles.backgroundColor)}"` : ""}${O(e)} />`;
}
//#endregion
//#region ../renderer/src/renderers/html.ts
function L(e, t) {
if (D(e) || !t.allowHtmlBlocks) return "";
let n = e.content;
if (n === "") return "";
let r = O(e);
return `<mj-text padding="${T(e.styles.padding)}"${E(e.styles.backgroundColor, "container")}${r}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/renderers/social.ts
function R(e, t) {
if (D(e)) return "";
let n = e.icons;
if (n.length === 0) return "";
let r = T(e.styles.padding), i = e.styles.backgroundColor ? ` container-background-color="${b(e.styles.backgroundColor)}"` : "", a = O(e), o = e.align, s = e.iconSize, c = e.iconStyle, l = e.spacing, u;
switch (s) {
case "small":
u = 24;
break;
case "large":
u = 48;
break;
default:
u = 32;
break;
}
let d;
switch (c) {
case "circle":
d = "50%";
break;
case "rounded":
d = "8px";
break;
case "square":
d = "0";
break;
default:
d = "4px";
break;
}
let f = n.length;
return `<mj-social
mode="horizontal"
align="${o}"
icon-padding="0"
padding="${r}"${i}${a}
>
${n.map((e, n) => {
let r = e.platform, i = b(e.url), a = `${t.socialIconsBaseUrl}/${c}/${r}.png`, o = n === f - 1 ? 0 : l;
return `<mj-social-element src="${a}" href="${i}" icon-size="${u}px" padding="0 ${o}px 0 0" border-radius="${d}" background-color="transparent"></mj-social-element>`;
}).join("\n")}
</mj-social>`;
}
//#endregion
//#region ../renderer/src/renderers/menu.ts
function z(e, t) {
if (D(e) || e.items.length === 0) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = O(e), a = H(e.fontFamily, t), o = e.textAlign;
return `<mj-text
font-size="${e.fontSize}px"${e.color ? `\n color="${b(e.color)}"` : ""}
align="${o}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${B(e)}</mj-text>`;
}
function B(e) {
let t = e.items, n = y(e.separator), r = x(e.separatorColor), i = e.spacing, a = e.linkColor ?? e.color, o = [], s = t.length;
for (let e = 0; e < s; e++) o.push(V(t[e], a)), e < s - 1 && o.push(`<span style="color: ${r}; padding: 0 ${i}px;">${n}</span>`);
return o.join("");
}
function V(e, t) {
let n = y(e.text), r = b(e.url), i = e.color ?? t, a = e.openInNewTab ? " target=\"_blank\" rel=\"noopener\"" : "", o = ["text-decoration: none"];
return i && o.unshift(`color: ${x(i)}`), e.bold && o.push("font-weight: bold"), e.underline && o.push("text-decoration: underline"), `<a href="${r}" style="${o.join("; ")}"${a}>${n}</a>`;
}
function H(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/table.ts
function U(e, t) {
if (D(e) || e.rows.length === 0) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = O(e), a = q(e.fontFamily, t);
return `<mj-text
font-size="${e.fontSize}px"${e.color ? `\n color="${b(e.color)}"` : ""}
align="${e.textAlign}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${W(e)}</mj-text>`;
}
function W(e) {
let t = x(e.borderColor), n = e.borderWidth, r = "";
for (let i = 0; i < e.rows.length; i++) {
let a = e.rows[i];
r += G(a, e, e.hasHeaderRow && i === 0, t, n);
}
return `<table style="width: 100%; border-collapse: collapse;">${r}</table>`;
}
function G(e, t, n, r, i) {
let a = "";
for (let o of e.cells) a += K(o, t, n, r, i);
return `<tr>${a}</tr>`;
}
function K(e, t, n, r, i) {
let a = t.cellPadding, o = [`border: ${i}px solid ${r}`, `padding: ${a}px`];
n && (o.push("font-weight: bold"), t.headerBackgroundColor && o.push(`background-color: ${x(t.headerBackgroundColor)}`));
let s = o.join("; "), c = y(S(e.content)), l = n ? "th" : "td";
return `<${l} style="${s}">${c}</${l}>`;
}
function q(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/custom.ts
function re(e, t) {
if (D(e)) return "";
let n = t.customBlockHtml.get(e.id) ?? e.renderedHtml;
if (!n || n === "") return "";
let r = O(e);
return `<mj-text padding="${T(e.styles.padding)}"${E(e.styles.backgroundColor, "container")}${r}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/columns.ts
function J(e) {
switch (e) {
case "2": return ["50%", "50%"];
case "3": return [
"33.33%",
"33.33%",
"33.34%"
];
case "1-2": return ["33.33%", "66.67%"];
case "2-1": return ["66.67%", "33.33%"];
default: return ["100%"];
}
}
function Y(e, t) {
switch (e) {
case "2": return [t * .5, t * .5];
case "3": return [
t / 3,
t / 3,
t / 3
];
case "1-2": return [t / 3, t * 2 / 3];
case "2-1": return [t * 2 / 3, t / 3];
default: return [t];
}
}
//#endregion
//#region ../renderer/src/display-condition.ts
function X(e, t) {
if (t === "") return "";
let n = e.displayCondition;
return n ? `<mj-raw>${n.before}</mj-raw>
` + t + `
<mj-raw>${n.after}</mj-raw>` : t;
}
//#endregion
//#region ../renderer/src/renderers/section.ts
function ie(e, t, n) {
if (D(e)) return "";
let r = e.columns, i = J(r), a = Y(r, t.containerWidth), o = T(e.styles.padding), s = E(e.styles.backgroundColor, "native"), c = O(e), l = e.borderRadius && e.borderRadius > 0 ? ` border-radius="${e.borderRadius}px"` : "", u = e.children, f = [];
for (let e = 0; e < u.length; e++) {
let r = u[e], o = i[e] ?? "100%", s = Math.floor(a[e] ?? t.containerWidth), c = ae(r, t.allowHtmlBlocks).filter((e) => !d(e)), l = t.withContainerWidth(s), p = c.map((e) => X(e, n(e, l))).filter((e) => e !== "").join("\n");
f.push(`<mj-column width="${o}">
${p === "" ? "<mj-text>&nbsp;</mj-text>" : p}
</mj-column>`);
}
let p = f.join("\n");
return `<mj-section${s} padding="${o}"${l}${c}>
${e.stackOnMobile === !1 && f.length > 1 ? `<mj-group>
${p}
</mj-group>` : p}
</mj-section>`;
}
function ae(e, t) {
return t ? e : e.filter((e) => e.type !== "html");
}
//#endregion
//#region ../renderer/src/renderers/video.ts
function oe(e, t) {
if (t) return t;
if (!e) return null;
for (let t of [/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/, /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/]) {
let n = e.match(t);
if (n) return `https://img.youtube.com/vi/${n[1]}/maxresdefault.jpg`;
}
let n = e.match(/vimeo\.com\/(?:video\/)?(\d+)/);
return n ? `https://vumbnail.com/${n[1]}.jpg` : null;
}
function se(e, t) {
if (D(e)) return "";
let n = oe(e.url, e.thumbnailUrl);
if (!n) return "";
let r = T(e.styles.padding), i = E(e.styles.backgroundColor, "container"), a = e.width === "full" ? t.containerWidth + "px" : e.width + "px", o = O(e);
return `<mj-image
src="${b(n)}"
alt="${b(e.alt)}"
width="${a}"
align="${e.align}"
padding="${r}"
href="${b(e.url)}"
target="_blank"
rel="noopener"${i}${o}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/index.ts
function Z(a, m) {
return d(a) ? ie(a, m, Z) : n(a) ? A(a, m) : e(a) ? te(a, m) : l(a) ? ne(a, m) : c(a) ? M(a, m) : i(a) ? F(a, m) : u(a) ? I(a, m) : s(a) ? L(a, m) : r(a) ? R(a, m) : p(a) ? z(a, m) : f(a) ? U(a, m) : o(a) ? se(a, m) : t(a) ? re(a, m) : "";
}
//#endregion
//#region ../renderer/src/index.ts
async function ce(e, t) {
let n = t?.customFonts ?? [], r = t?.defaultFallbackFont ?? "Arial, sans-serif", i = t?.allowHtmlBlocks ?? !0, a = fe(t?.socialIconsBaseUrl ?? m), o = await he(e, t?.renderCustomBlock), s = ge(e, t?.getCustomBlockStylesheet), c = new g(e.settings.width, n, r, i, o, a), l = Q(e.blocks, i), u = c.resolveFontFamily(e.settings.fontFamily), d = e.settings.backgroundColor, f = e.settings.textColor ? ` color="${b(e.settings.textColor)}"` : "", p = e.settings.linkColor ? x(e.settings.linkColor) : "inherit", h = e.settings.linkUnderline ? "underline" : "none", _ = l.map((e) => le(e, c)).filter((e) => e !== "").join("\n"), v = me(n), y = pe(e.settings.preheaderText);
return `<mjml lang="${b(e.settings.locale)}">
<mj-head>${y}
<mj-attributes>
<mj-all font-family="${u}" />
<mj-text font-size="14px"${f} />
<mj-section padding="0" />
<mj-column padding="0" />
<mj-image fluid-on-mobile="true" />
</mj-attributes>${v}
<mj-style>
a { color: ${p}; text-decoration: ${h}; }
@media only screen and (max-width: 480px) {
.tpl-hide-mobile { display: none !important; mso-hide: all !important; }
}
@media only screen and (min-width: 481px) {
.tpl-hide-desktop { display: none !important; mso-hide: all !important; }
}
</mj-style>${_e(s)}
</mj-head>
<mj-body width="${c.containerWidth}px" background-color="${d}">
${_}
</mj-body>
</mjml>`;
}
function le(e, t) {
if (d(e)) {
let n = Z(e, t);
return X(e, e.wrapper && n !== "" ? ue(n, e.wrapper) : n);
}
return X(e, de(Z(e, t)));
}
function ue(e, t) {
return `<mj-wrapper${E(t.backgroundColor, "native")}${` padding="${t.padding ? T(t.padding) : "0"}"`}${t.borderRadius && t.borderRadius > 0 ? ` border-radius="${t.borderRadius}px"` : ""}>
${e}
</mj-wrapper>`;
}
function de(e) {
return e === "" ? "" : `<mj-section>
<mj-column>
${e}
</mj-column>
</mj-section>`;
}
function fe(e) {
return e.endsWith("/") ? e.slice(0, -1) : e;
}
function pe(e) {
if (!e) return "";
let t = e.trim();
return t === "" ? "" : `\n <mj-preview>${y(t)}</mj-preview>`;
}
function me(e) {
return e.length === 0 ? "" : e.map((e) => `\n <mj-font name="${b(e.name)}" href="${b(e.url)}" />`).join("");
}
function Q(e, t) {
return t ? e : e.filter((e) => e.type !== "html");
}
async function he(e, t) {
let n = /* @__PURE__ */ new Map();
if (!t) return n;
let r = [];
if ($(e.blocks, r), r.length === 0) return n;
let i = await Promise.all(r.map((e) => t(e)));
for (let e = 0; e < r.length; e++) n.set(r[e].id, i[e]);
return n;
}
function $(e, n) {
for (let r of e) {
if (t(r)) {
n.push(r);
continue;
}
if (d(r)) for (let e of r.children) $(e, n);
}
}
function ge(e, t) {
if (!t) return [];
let n = [];
if ($(e.blocks, n), n.length === 0) return [];
let r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = [];
for (let e of n) {
if (r.has(e.customType)) continue;
r.add(e.customType);
let n = t(e.customType);
if (!n) continue;
let o = n.trim();
o === "" || i.has(o) || (i.add(o), a.push(o));
}
return a;
}
function _e(e) {
return e.length === 0 ? "" : e.map((e) => `\n <mj-style>\n${e}\n </mj-style>`).join("");
}
//#endregion
export { m as DEFAULT_SOCIAL_ICONS_BASE_URL, g as RenderContext, S as convertMergeTagsToValues, b as escapeAttr, y as escapeHtml, O as getCssClassAttr, k as getCssClasses, J as getWidthPercentages, Y as getWidthPixels, D as isHiddenOnAll, Z as renderBlock, ce as renderToMjml, T as toPaddingString };
//# sourceMappingURL=src-DYji-wXB.js.map

Sorry, the diff of this file is too big to display

import { A as e, D as t, Dt as n, E as r, Et as i, I as a, K as o, O as s, Ot as c, R as l, Y as u, Z as d, _ as f, c as p, d as m, g as h, h as g, k as _, l as v, m as y, nt as b, p as x, r as S, s as C, u as w, z as T } from "./vue.runtime.esm-bundler-B0xoGkDv.js";
import { c as E, o as D, t as O } from "./runtime-dom.esm-bundler-GdMI8WqG.js";
import { n as k } from "./upload-BwwE0U6G.js";
import { A } from "./dist-BJbqgyPn.js";
import { E as j, V as M, t as N, x as P } from "./useEditorCore-CT1slufs.js";
import { m as F } from "./dist-DYv_Pttj.js";
import { s as I } from "./usePopoverPosition-BO2LNy5n.js";
import { A as L, F as R, c as z, r as B, s as V, t as H, u as ee } from "./keys-CHPcp-Nz.js";
import { t as U } from "./useI18n-D2L9Mkik.js";
import { t as W } from "./createLucideIcon-JWHwTI6N.js";
import { t as G } from "./check-BpQDKiPz.js";
import { t as K } from "./circle-alert-CgtE46ND.js";
import { a as q, c as te, d as ne, f as re, i as ie, l as ae, m as oe, n as se, o as ce, p as le, r as ue, s as de, t as fe, u as pe } from "./styles-PcOPXvLO.js";
import { t as me } from "./clock-BzKLLW5L.js";
import { t as J } from "./loader-circle-C-Z6kgI6.js";
import { t as Y } from "./message-circle-CEm5qckV.js";
import { t as X } from "./send-B70aQDrA.js";
import { t as Z } from "./sparkles-DVlm1Ipp.js";
import { t as he } from "./triangle-alert-Djg6IG8N.js";
import { t as ge } from "./_plugin-vue_export-helper-B3ysoDQm.js";
import { n as Q } from "./useCloudI18n-BmiygEM4.js";
import { d as $ } from "./ColorPicker-s9GHXjZs.js";
import { _ as _e, c as ve, f as ye, g as be, h as xe, i as Se, l as Ce, m as we, n as Te, o as Ee, p as De, r as Oe, s as ke, t as Ae, u as je, v as Me, y as Ne } from "./cloud-Du7mnkz2.js";
var Pe = W("save", [
["path", {
d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",
key: "1c8476"
}],
["path", {
d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",
key: "1ydtos"
}],
["path", {
d: "M7 3v4a1 1 0 0 0 1 1h7",
key: "t51u73"
}]
]);
//#endregion
//#region src/cloud/composables/useSnapshotPreview.ts
function Fe(e) {
let { authManager: t, editor: n, history: r, conditionPreview: i, autoSave: a, onError: s } = e, c = d(null), l = u(null), f = u(null), p = !1;
o(() => {
p = !0;
});
let m = C(() => l.value !== null), h = C(() => c.value?.snapshots.value ?? []), g = C(() => c.value?.isLoading.value ?? !1), _ = C(() => c.value?.isRestoring.value ?? !1);
function v() {
n.state.template?.id && !c.value && (c.value = be({
authManager: t,
templateId: n.state.template.id,
onRestore: y,
onError: s
}), c.value.loadSnapshots());
}
function y(e) {
n.setContent(e.content, !1), r.clear(), i.reset();
}
async function b(e) {
if (!p) {
if (l.value) {
l.value = e, n.setContent(e.content, !1);
return;
}
n.state.isDirty && n.hasTemplate() && (await n.createSnapshot(), p) || (f.value = structuredClone(n.content.value), a?.pause(), l.value = e, n.setContent(e.content, !1));
}
}
async function x() {
if (!(!l.value || !c.value)) try {
if (await c.value.restoreSnapshot(l.value.id), p || (await c.value.loadSnapshots(), p)) return;
} catch (e) {
throw !p && f.value && n.setContent(f.value, !1), e;
} finally {
p || (l.value = null, f.value = null, a?.resume());
}
}
function S() {
!l.value || !f.value || (n.setContent(f.value, !1), l.value = null, f.value = null, a?.resume());
}
async function w() {
p || c.value && await c.value.loadSnapshots();
}
return {
snapshotHistoryInstance: c,
previewingSnapshot: l,
contentBeforePreview: f,
isPreviewingSnapshot: m,
snapshotHistorySnapshots: h,
snapshotHistoryIsLoading: g,
snapshotHistoryIsRestoring: _,
initSnapshotHistory: v,
handleRestore: y,
handleSnapshotNavigate: b,
confirmRestoreSnapshot: x,
cancelPreview: S,
loadSnapshotHistory: w
};
}
//#endregion
//#region src/cloud/composables/useCloudPanelState.ts
function Ie() {
let e = u(null), t = C({
get: () => e.value === "ai-chat",
set: (t) => e.value = t ? "ai-chat" : null
}), n = C({
get: () => e.value === "scoring",
set: (t) => e.value = t ? "scoring" : null
}), r = C({
get: () => e.value === "design-reference",
set: (t) => e.value = t ? "design-reference" : null
}), i = C({
get: () => e.value === "comments",
set: (t) => e.value = t ? "comments" : null
}), a = u(!1), o = u(!1), s = u(void 0), c = u(!1), l = u(null), d = C(() => e.value !== null), f = C(() => {
let t = e.value;
return t === "ai-chat" || t === "design-reference" || t === "scoring" ? t : null;
}), p = C(() => c.value || e.value === "ai-chat" || e.value === "design-reference" || e.value === "scoring");
function m() {
c.value = !c.value;
}
function h(t) {
c.value = !1, e.value = e.value === t ? null : t;
}
return I(l, () => {
c.value = !1;
}), {
activePanel: e,
aiChatOpen: t,
scoringPanelOpen: n,
designReferenceOpen: r,
commentsOpen: i,
testEmailModalOpen: a,
mediaLibraryOpen: o,
mediaLibraryAccept: s,
aiMenuOpen: c,
aiMenuRef: l,
rightPanelOpen: d,
activeAiFeature: f,
aiButtonActive: p,
toggleAiMenu: m,
handleAiFeatureSelect: h
};
}
//#endregion
//#region src/cloud/composables/useCollabUndoWarning.ts
function Le(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = u(!1), a = u(!1), { start: o } = F(() => {
a.value = !1;
}, k, { immediate: !1 });
function s() {
i.value || !t.value || n() === 0 || !r.value || (i.value = !0, a.value = !0, o());
}
return {
collabUndoWarningVisible: a,
showCollabUndoWarning: s
};
}
//#endregion
//#region src/cloud/composables/useCloudFeatureFlags.ts
function Re(e) {
let { planConfigInstance: t, aiConfig: n, editor: r } = e, i = C(() => t.hasFeature("ai_generation") && n.hasAnyMenuFeature.value), a = C(() => t.hasFeature("test_email")), o = C(() => !!r.state.template?.id), s = C(() => t.hasFeature("white_label")), c = C(() => t.config.value?.limits.max_templates ?? null), l = C(() => t.config.value?.template_count ?? 0), d = u(!1), f = u("idle"), p = u(""), { start: m } = F(() => {
f.value = "idle";
}, 3e3, { immediate: !1 });
return {
canUseAiGeneration: i,
canSendTestEmail: a,
hasTemplateSaved: o,
isWhiteLabeled: s,
templateLimit: c,
templateCount: l,
isSaveExporting: d,
saveStatus: f,
saveErrorMessage: p,
startSaveStatusClear: m
};
}
//#endregion
//#region src/cloud/composables/useCloudMediaLibrary.ts
function ze(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: r, authManager: i, getMediaConfig: a, onError: s } = e, c = null;
function l(e) {
return {
url: e.url,
alt: e.alt_text || void 0
};
}
async function u(e) {
let i = e?.accept ?? ["images"];
if (e?.files?.length) {
if (t) {
let n = await t({
accept: i,
files: e.files
});
return n ? l(n) : null;
}
return d(e.files[0]);
}
if (t) {
let e = await t({ accept: i });
return e ? l(e) : null;
}
return c &&= (c(null), null), r.value = i, n.value = !0, new Promise((e) => {
c = (t) => {
e(t);
};
});
}
async function d(e) {
let t = f(e);
if (t) return s?.(t), null;
try {
let { MediaApiClient: t } = await import("@templatical/media-library");
return l(await new t(i).uploadMedia(e));
} catch (e) {
return s?.(e), null;
}
}
function f(e) {
let t = a?.() ?? null;
if (!t) return null;
let n = t.categories?.images?.mime_types ?? [];
return n.length > 0 && !n.includes(e.type) ? /* @__PURE__ */ Error(`Unsupported image type: ${e.type || "unknown"}. Accepted: ${n.join(", ")}.`) : t.max_file_size > 0 && e.size > t.max_file_size ? /* @__PURE__ */ Error(`Image is too large (${e.size} bytes). Maximum allowed is ${t.max_file_size} bytes.`) : null;
}
function p(e) {
n.value = !1, c?.(l(e)), c = null;
}
function m() {
n.value = !1, c?.(null), c = null;
}
return o(() => {
c &&= (c(null), null);
}), {
handleRequestMedia: u,
handleMediaSelect: p,
handleMediaLibraryClose: m
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function Be(e) {
let { config: t, translations: n, fontsManager: r, emit: i, getCommentsSidebar: o } = e, s = u(!0), c = u(!1), l = u(null), d = !1, f = { value: null }, p = null, m = null, h = new Ae({
...t.auth,
onError: t.onError
}), g = xe({
authManager: h,
onError: t.onError
}), v = u(/* @__PURE__ */ new Map()), y = ye({
authManager: h,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: v
}), b = Ne({
authManager: h,
onError: t.onError
});
t.mcp?.enabled && we({
editor: y,
channel: b.channel,
onOperation: t.mcp.onOperation
});
let x = null;
t.collaboration?.enabled && (x = ke({
authManager: h,
editor: y,
channel: b.channel,
onError: t.onError,
onCollaboratorJoined: t.collaboration.onCollaboratorJoined,
onCollaboratorLeft: t.collaboration.onCollaboratorLeft,
onBlockLocked: t.collaboration.onBlockLocked,
onBlockUnlocked: t.collaboration.onBlockUnlocked
}), a(() => x.lockedBlocks.value, (e) => {
v.value = e;
}, { immediate: !0 }), ve(y, x));
let S = C(() => !!t.collaboration?.enabled && g.hasFeature("collaboration")), w = N({
editor: y,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
templateDefaults: t.templateDefaults,
customBlocks: [],
paletteBlocks: t.paletteBlocks,
htmlBlockPreview: t.htmlBlockPreview,
colors: t.colors,
mergeTags: t.mergeTags,
logicTags: t.logicTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: re(t),
onSave: () => {
f.value?.().catch((e) => {
t.onError?.(e);
});
}
},
translations: n,
fontsManager: r,
historyOptions: x ? { isRemoteOperation: () => x._isProcessingRemoteOperation() } : void 0,
autoSaveOptions: {
onChange: async () => {
y.hasTemplate() && (await y.createSnapshot(), p?.snapshotHistoryInstance.value?.loadSnapshots());
},
debounce: t.autoSaveDebounce ?? 5e3,
enabled: () => t.autoSave !== !1 && g.hasFeature("auto_save")
},
themeExtraStyles: () => ({ "--tpl-drop-text": `"${n.canvas.dropHere}"` }),
keyboardOptions: { onBeforeUndo: () => m?.showCollabUndoWarning() },
editorRoot: e.editorRoot,
containerEl: e.containerEl
}), T = Le({
isCollaborationEnabled: S,
getCollaboratorCount: () => x?.collaborators.value.length ?? 0,
canUndo: w.history.canUndo
});
m = T;
let E = Fe({
authManager: h,
editor: y,
history: w.history,
conditionPreview: w.conditionPreview,
autoSave: w.autoSave,
onError: t.onError
});
p = E;
let D = Ie(), O = Ee(t.ai), k = Re({
planConfigInstance: g,
aiConfig: O,
editor: y
}), A = ze({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: D.mediaLibraryOpen,
mediaLibraryAccept: D.mediaLibraryAccept,
authManager: h,
getMediaConfig: () => g.config.value?.media ?? null,
onError: t.onError
});
j({
onBlockMove: y.moveBlock,
onBlockAdd: y.addBlock
});
let P = De({
authManager: h,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => g.hasFeature("custom_fonts")
}), F = Me({
authManager: h,
getTemplateId: () => y.state.template?.id ?? null,
save: () => y.save(),
exportHtml: (e) => P.exportHtml(e),
onError: t.onError,
isAuthReady: c,
onBeforeTestEmail: t.onBeforeTestEmail
}), I = je({
authManager: h,
getTemplateId: () => y.state.template?.id ?? null,
getSocketId: () => b.getSocketId(),
onComment: t.onComment,
onError: t.onError,
isAuthReady: c,
hasCommentingFeature: () => t.commenting !== !1 && g.hasFeature("commenting")
});
Ce({
comments: I,
channel: b.channel
});
let z = le({
provider: Te(h),
editor: y,
onError: t.onError,
isAvailable: () => t.savedBlocks !== !1 && g.hasFeature("saved_modules")
}), U = _e({
authManager: h,
getTemplateId: () => y.state.template?.id ?? null
});
function W(e) {
D.commentsOpen.value = !0, queueMicrotask(() => {
o()?.filterByBlock(e);
});
}
_(L, A.handleRequestMedia), _(B, h), _(H, O), _(ee, I), _(R, U), _(V, {
plan: g,
ai: O,
comments: {
getBlockCount: (e) => I.commentCountByBlock.value.get(e) ?? 0,
openForBlock: W
},
savedBlocks: z.capability
});
function G(e) {
g.hasFeature("theme_customization") && (w.themeOverrides.value = e);
}
function K(e) {
y.setUiTheme(e);
}
async function q() {
s.value = !0, l.value = null;
try {
if (await h.initialize(), d) return;
c.value = !0;
let e = await Oe({ authManager: h });
if (d) return;
if (!e.api.ok) throw Error("Health check failed: API is not reachable");
if (!e.auth.ok) throw Error(`Health check failed: authentication error${e.auth.error ? ` - ${e.auth.error}` : ""}`);
if (e.websocket.ok || M.warn("WebSocket health check failed:", e.websocket.error ?? "unknown error", "-- real-time features will be disabled."), await g.fetchConfig(), d) return;
r.setCustomFontsEnabled(g.hasFeature("custom_fonts")), t.customBlocks?.length && g.hasFeature("custom_blocks") && w.registerCustomBlocks(t.customBlocks), t.theme && g.hasFeature("theme_customization") && (w.themeOverrides.value = t.theme), i("ready");
} catch (e) {
if (d) return;
let n = e instanceof Error ? e : Error("Initialization failed", { cause: e });
l.value = n, t.onError?.(n);
} finally {
d || (s.value = !1);
}
}
function te() {
d = !0, r.cleanupFontLinks(), b.disconnect(), w.destroy(), t.onUnmount?.();
}
return {
isInitializing: s,
isAuthReady: c,
initError: l,
isDestroyed: () => d,
authManager: h,
planConfigInstance: g,
websocket: b,
collaboration: x,
isCollaborationEnabled: S,
editor: y,
core: w,
aiConfig: O,
featureFlags: k,
mediaLib: A,
exporter: P,
testEmail: F,
commentsInstance: I,
savedBlocks: z,
scoringInstance: U,
panelState: D,
snapshotPreview: E,
collabWarning: T,
onSaveHook: f,
initialize: q,
destroy: te,
setThemeOverrides: G,
setUiTheme: K,
openCommentsForBlock: W
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Ve(e, t) {
let n = async (e) => {
if (A(e)) {
let n = e;
try {
n.renderedHtml = await t.renderCustomBlock(n);
} catch {
n.renderedHtml = `<!-- Custom block render error: ${n.customType} -->`;
}
}
if (e.type === "section" && "children" in e) {
let t = e;
for (let e of t.children) for (let t of e) await n(t);
}
};
for (let t of e.blocks) await n(t);
}
//#endregion
//#region src/cloud/composables/useCloudLifecycle.ts
function He(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return Se(i.config.value.websocket);
}
async function d(e) {
let i = await n.create(e);
return l() ? i : (t.onCreate?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function f(e) {
let i = await n.load(e);
return l() ? i : (t.onLoad?.(i), a.initSnapshotHistory(), r.connect(i.id, u()), i);
}
async function p() {
c.isSaveExporting.value = !0, c.saveStatus.value = "idle";
try {
if (await Ve(n.content.value, o.registry), l()) throw Error("Component unmounted during save");
let e = await n.save();
if (l()) throw Error("Component unmounted during save");
a.initSnapshotHistory(), a.snapshotHistoryInstance.value?.loadSnapshots();
let r = await s.exportHtml(e.id);
if (l()) throw Error("Component unmounted during save");
let i = {
templateId: e.id,
html: r.html,
mjml: r.mjml,
content: e.content
};
return t.onSave?.(i), c.saveStatus.value = "saved", c.startSaveStatusClear(), i;
} catch (e) {
throw l() || (c.saveStatus.value = "error", c.saveErrorMessage.value = e instanceof Error ? e.message : "Save failed"), e;
} finally {
l() || (c.isSaveExporting.value = !1);
}
}
return {
createTemplate: d,
loadTemplate: f,
saveTemplate: p
};
}
//#endregion
//#region src/cloud/composables/useCloudSaveGate.ts
function Ue(e) {
let t = u(!1), n = null, r = C(() => e.planConfig.value?.accessibility?.blockOnError === !0), i = C(() => r.value ? e.issues.value.filter((e) => e.severity === "error") : []), a = C(() => i.value.length > 0);
async function o(e) {
return a.value ? (n = e, t.value = !0, !1) : (await e(), !0);
}
async function s() {
let e = n;
n = null, t.value = !1, e && await e();
}
function c() {
n = null, t.value = !1;
}
return {
shouldBlock: a,
blockingIssues: i,
modalOpen: t,
tryRunSave: o,
confirmAndSave: s,
cancel: c
};
}
//#endregion
//#region src/cloud/components/CloudSaveGateModal.vue?vue&type=script&setup=true&lang.ts
var We = ["aria-label"], Ge = { class: "tpl:flex tpl:max-h-[80vh] tpl:w-full tpl:max-w-md tpl:flex-col tpl:gap-4 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:p-5 tpl:shadow-[var(--tpl-shadow-md)]" }, Ke = { class: "tpl:flex tpl:items-center tpl:gap-2" }, qe = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, Je = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Ye = { class: "tpl:m-0 tpl:flex tpl:max-h-64 tpl:list-none tpl:flex-col tpl:gap-1.5 tpl:overflow-y-auto tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2" }, Xe = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, Ze = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Qe = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, $e = /* @__PURE__ */ f({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(t, { emit: n }) {
let r = n, { t: i } = Q();
return (n, a) => (s(), v(O, {
"enter-active-class": "tpl:transition-opacity tpl:duration-150",
"leave-active-class": "tpl:transition-opacity tpl:duration-150",
"enter-from-class": "tpl:opacity-0",
"leave-to-class": "tpl:opacity-0"
}, {
default: l(() => [t.open ? (s(), m("div", {
key: 0,
role: "dialog",
"aria-modal": "true",
"aria-label": b(i).saveGate.title,
class: "tpl:fixed tpl:inset-0 tpl:z-50 tpl:flex tpl:items-center tpl:justify-center tpl:bg-black/40 tpl:p-6",
onClick: a[2] ||= E((e) => r("cancel"), ["self"])
}, [p("div", Ge, [
p("header", Ke, [g(b(he), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), p("h2", qe, c(b(i).saveGate.title), 1)]),
p("p", Je, c(b(i).saveGate.body), 1),
p("ul", Ye, [(s(!0), m(S, null, e(t.issues, (e) => (s(), m("li", {
key: `${e.ruleId}-${e.blockId ?? "template"}`,
class: "tpl:flex tpl:flex-col tpl:gap-0.5 tpl:rounded tpl:px-2 tpl:py-1.5"
}, [p("span", Xe, c(e.message), 1), p("span", Ze, c(e.ruleId), 1)]))), 128))]),
p("footer", Qe, [p("button", {
type: "button",
class: "tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]",
onClick: a[0] ||= (e) => r("cancel")
}, c(b(i).saveGate.cancel), 1), p("button", {
type: "button",
class: "tpl:rounded-md tpl:bg-[var(--tpl-danger)] tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:text-white",
onClick: a[1] ||= (e) => r("confirm")
}, c(b(i).saveGate.confirm), 1)])
])], 8, We)) : w("", !0)]),
_: 1
}));
}
}), et = {
class: "tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4",
style: {
"background-color": "color-mix(in srgb, var(--tpl-bg) 80%, transparent)",
"backdrop-filter": "blur(12px)",
"-webkit-backdrop-filter": "blur(12px)",
"box-shadow": "var(--tpl-shadow-md)",
"border-bottom": "1px solid var(--tpl-border)"
}
}, tt = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, nt = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, rt = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, it = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, at = ["data-tooltip"], ot = {
key: 1,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-success)]"
}, st = {
key: 2,
"aria-live": "polite",
class: "tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-text-muted)]"
}, ct = ["aria-label", "aria-expanded"], lt = {
key: 0,
class: "tpl:inline-flex tpl:size-4.5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:text-[10px] tpl:font-semibold tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]"
}, ut = ["aria-expanded"], dt = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, ft = ["disabled"], pt = ["disabled"], mt = /* @__PURE__ */ f({
__name: "CloudHeader",
props: {
editor: {},
core: {},
featureFlags: {},
panelState: {},
snapshotPreview: {},
commentsInstance: {},
testEmail: {},
websocket: {},
collaboration: {},
isCollaborationEnabled: { type: Boolean },
isSaveDisabled: { type: Boolean },
isSaving: { type: Boolean }
},
emits: ["save"],
setup(e) {
let t = h(() => import("./CollaboratorBar-Bj4NZiie.js")), r = h(() => import("./SnapshotHistory-FtzDq8f0.js")), a = h(() => import("./AiFeatureMenu-CcqQDHzJ.js")), { t: o, format: u } = Q();
return (d, f) => (s(), m("header", et, [
p("div", tt, [e.featureFlags.templateLimit.value === null ? w("", !0) : (s(), m("span", nt, c(b(u)(b(o).header.templatesUsed, {
used: e.featureFlags.templateCount.value,
max: e.featureFlags.templateLimit.value
})), 1))]),
p("div", rt, [
g(ce, {
viewport: e.editor.state.viewport,
onChange: e.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
g(ie, {
"dark-mode": e.editor.state.darkMode,
onChange: e.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
g(q, {
"preview-mode": e.editor.state.previewMode,
onChange: e.editor.setPreviewMode
}, null, 8, ["preview-mode", "onChange"]),
e.collaboration && e.isCollaborationEnabled ? (s(), v(b(t), {
key: 0,
collaborators: e.collaboration.collaborators.value,
"is-connected": e.websocket.isConnected.value
}, null, 8, ["collaborators", "is-connected"])) : w("", !0),
e.snapshotPreview.snapshotHistoryInstance.value ? (s(), v(b(r), {
key: 1,
snapshots: e.snapshotPreview.snapshotHistorySnapshots.value,
"is-loading": e.snapshotPreview.snapshotHistoryIsLoading.value,
"is-restoring": e.snapshotPreview.snapshotHistoryIsRestoring.value,
onLoad: e.snapshotPreview.loadSnapshotHistory,
onNavigate: e.snapshotPreview.handleSnapshotNavigate
}, null, 8, [
"snapshots",
"is-loading",
"is-restoring",
"onLoad",
"onNavigate"
])) : w("", !0)
]),
p("div", it, [
e.featureFlags.saveStatus.value === "error" ? (s(), m("div", {
key: 0,
"aria-live": "assertive",
class: "tpl-tooltip tpl-status tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-danger)]",
"data-tooltip": e.featureFlags.saveErrorMessage.value
}, [g(b(K), {
size: 12,
"stroke-width": 2.5
}), y(" " + c(b(o).header.saveFailed), 1)], 8, at)) : e.featureFlags.saveStatus.value === "saved" ? (s(), m("div", ot, [g(b(G), {
size: 12,
"stroke-width": 2.5
}), y(" " + c(b(o).header.saved), 1)])) : e.editor.state.isDirty ? (s(), m("div", st, [f[4] ||= p("span", { class: "tpl-pulse tpl:size-1.5 tpl:rounded-full tpl:bg-[var(--tpl-primary)]" }, null, -1), y(" " + c(b(o).header.unsaved), 1)])) : w("", !0),
e.commentsInstance.isEnabled.value && e.featureFlags.hasTemplateSaved.value ? (s(), m("button", {
key: 3,
"aria-label": e.commentsInstance.unresolvedCount.value > 0 ? `${b(o).comments.button} (${e.commentsInstance.unresolvedCount.value})` : b(o).comments.button,
"aria-expanded": e.panelState.commentsOpen.value,
class: i(b($)),
style: n({
backgroundColor: e.panelState.commentsOpen.value ? "var(--tpl-primary)" : "transparent",
color: e.panelState.commentsOpen.value ? "var(--tpl-bg)" : "var(--tpl-primary)",
borderColor: "var(--tpl-primary)"
}),
onClick: f[0] ||= (t) => e.panelState.commentsOpen.value = !e.panelState.commentsOpen.value
}, [
g(b(Y), {
size: 16,
"stroke-width": 2
}),
y(" " + c(b(o).comments.button) + " ", 1),
e.commentsInstance.unresolvedCount.value > 0 && !e.panelState.commentsOpen.value ? (s(), m("span", lt, c(e.commentsInstance.unresolvedCount.value), 1)) : w("", !0)
], 14, ct)) : w("", !0),
e.featureFlags.canUseAiGeneration.value && e.featureFlags.hasTemplateSaved.value ? (s(), m("div", {
key: 4,
ref: (t) => e.panelState.aiMenuRef.value = t,
class: "tpl:relative"
}, [p("button", {
"aria-expanded": e.panelState.aiMenuOpen.value,
class: i(["tpl-ai-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-4 tpl:py-2 tpl:text-sm tpl:font-semibold tpl:whitespace-nowrap tpl:transition-all tpl:duration-200", e.panelState.aiButtonActive.value ? "tpl-ai-btn--active" : "tpl-ai-btn--idle"]),
onClick: f[1] ||= E((...t) => e.panelState.toggleAiMenu && e.panelState.toggleAiMenu(...t), ["stop"])
}, [g(b(Z), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), y(" " + c(b(o).aiChat.button), 1)], 10, ut), g(O, {
"enter-active-class": "tpl:transition-all tpl:duration-150 tpl:ease-out",
"enter-from-class": "tpl:scale-95 tpl:opacity-0",
"enter-to-class": "tpl:scale-100 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-100 tpl:ease-in",
"leave-from-class": "tpl:scale-100 tpl:opacity-100",
"leave-to-class": "tpl:scale-95 tpl:opacity-0"
}, {
default: l(() => [e.panelState.aiMenuOpen.value ? (s(), m("div", dt, [g(b(a), {
"active-feature": e.panelState.activeAiFeature.value,
onSelect: e.panelState.handleAiFeatureSelect
}, null, 8, ["active-feature", "onSelect"])])) : w("", !0)]),
_: 1
})], 512)) : w("", !0),
e.testEmail.isEnabled.value && e.featureFlags.canSendTestEmail.value ? (s(), m("button", {
key: 5,
class: i(b($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.testEmail.isSending.value || !e.featureFlags.hasTemplateSaved.value,
onClick: f[2] ||= (t) => e.panelState.testEmailModalOpen.value = !0
}, [e.testEmail.isSending.value ? (s(), v(b(J), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (s(), v(b(X), {
key: 0,
size: 16,
"stroke-width": 2
})), y(" " + c(b(o).testEmail.button), 1)], 10, ft)) : w("", !0),
p("button", {
class: i(b($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: e.isSaveDisabled,
onClick: f[3] ||= (e) => d.$emit("save")
}, [e.isSaving ? (s(), v(b(J), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (s(), v(b(Pe), {
key: 0,
size: 16,
"stroke-width": 2
})), y(" " + c(e.isSaving ? b(o).header.saving : b(o).header.save), 1)], 10, pt)
])
]));
}
}), ht = /* @__PURE__ */ f({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {}
},
emits: ["send-test-email"],
setup(e, { expose: t, emit: n }) {
let r = h(() => import("./AiChatSidebar-K_AehWc-.js")), i = h(() => import("./CommentsSidebar-DvNEdugN.js")), a = h(() => import("./DesignReferenceSidebar-DNmK3dxp.js")), o = h(() => import("./TemplateScoringPanel-ifGGGWs5.js")), c = h(() => import("./TestEmailModal-DL2O1H8M.js")), l = h(async () => {
try {
return (await import("@templatical/media-library")).MediaLibraryModal;
} catch {
throw Error("[Templatical] Cloud media library requires the optional peer dependency '@templatical/media-library'. Please install it.");
}
}), d = n;
function f(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
let p = u(null);
function _(e) {
p.value?.filterByBlock(e);
}
return t({ filterCommentsByBlock: _ }), (t, n) => (s(), m(S, null, [
g(b(r), {
visible: e.panelState.aiChatOpen.value,
"on-apply": (t) => f(t, e.core, e.editor),
onClose: n[0] ||= (t) => e.panelState.aiChatOpen.value = !1
}, null, 8, ["visible", "on-apply"]),
g(b(o), {
visible: e.panelState.scoringPanelOpen.value,
onClose: n[1] ||= (t) => e.panelState.scoringPanelOpen.value = !1
}, null, 8, ["visible"]),
g(b(a), {
visible: e.panelState.designReferenceOpen.value,
"has-existing-blocks": e.editor.content.value.blocks.length > 0,
onClose: n[2] ||= (t) => e.panelState.designReferenceOpen.value = !1,
onApply: n[3] ||= (t) => f(t, e.core, e.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
g(b(i), {
ref_key: "commentsSidebar",
ref: p,
visible: e.panelState.commentsOpen.value,
onClose: n[4] ||= (t) => e.panelState.commentsOpen.value = !1
}, null, 8, ["visible"]),
g(b(c), {
visible: e.panelState.testEmailModalOpen.value,
"allowed-emails": e.testEmail.allowedEmails.value,
"is-sending": e.testEmail.isSending.value,
error: e.testEmail.error.value,
onSend: n[5] ||= (e) => d("send-test-email", e),
onClose: n[6] ||= (t) => e.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
g(b(l), {
visible: e.panelState.mediaLibraryOpen.value,
accept: e.panelState.mediaLibraryAccept.value,
"popover-target": e.core.popoverRoot.value,
onSelect: e.mediaLib.handleMediaSelect,
onClose: e.mediaLib.handleMediaLibraryClose
}, null, 8, [
"visible",
"accept",
"popover-target",
"onSelect",
"onClose"
])
], 64));
}
}), gt = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, _t = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, vt = { class: "tpl:flex tpl:w-12 tpl:shrink-0 tpl:flex-col tpl:items-center tpl:gap-4 tpl:py-5 tpl:border-r tpl:border-[var(--tpl-border)]" }, yt = /* @__PURE__ */ f({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(t) {
return (n, r) => t.visible ? (s(), m("div", gt, [r[1] ||= x("<div class=\"tpl:flex tpl:h-14 tpl:shrink-0 tpl:items-center tpl:justify-between tpl:px-4 tpl:border-b tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-5 tpl:w-28 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl:flex tpl:gap-3\"><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-8 tpl:w-20 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div></div>", 1), p("div", _t, [p("div", vt, [(s(), m(S, null, e(5, (e) => p("div", {
key: e,
class: "tpl-shimmer tpl:size-7 tpl:rounded-[var(--tpl-radius-sm)]"
})), 64))]), r[0] ||= x("<div class=\"tpl:flex tpl:flex-1 tpl:items-start tpl:justify-center tpl:overflow-auto tpl:p-8 tpl:bg-[var(--tpl-canvas-bg)]\"><div class=\"tpl:w-full tpl:max-w-[600px] tpl:rounded-[var(--tpl-radius)] tpl:p-6 tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)]\"><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-3/4 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-5/6 tpl:rounded\"></div></div><div class=\"tpl:py-4\"><div class=\"tpl-shimmer tpl:h-44 tpl:w-full tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:h-3 tpl:w-full tpl:rounded\"></div><div class=\"tpl-shimmer tpl:h-3 tpl:w-2/3 tpl:rounded\"></div></div><div class=\"tpl:flex tpl:justify-center tpl:py-4\"><div class=\"tpl-shimmer tpl:h-10 tpl:w-36 tpl:rounded-[var(--tpl-radius-sm)]\"></div></div><div class=\"tpl:space-y-2 tpl:py-4\"><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/2 tpl:rounded\"></div><div class=\"tpl-shimmer tpl:mx-auto tpl:h-2.5 tpl:w-1/3 tpl:rounded\"></div></div></div></div><div class=\"tpl:flex tpl:w-[320px] tpl:shrink-0 tpl:flex-col tpl:gap-4 tpl:p-4 tpl:border-l tpl:border-[var(--tpl-border)]\"><div class=\"tpl-shimmer tpl:h-8 tpl:rounded-[var(--tpl-radius-sm)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div><div class=\"tpl-shimmer tpl:h-32 tpl:rounded-[var(--tpl-radius)]\"></div></div>", 2)])])) : w("", !0);
}
}), bt = {
key: 0,
role: "alert",
class: "tpl-error tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-6 tpl:px-8 tpl:bg-[var(--tpl-bg)]"
}, xt = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, St = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, Ct = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, wt = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Tt = /* @__PURE__ */ f({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
function i(e) {
return "isUnauthorized" in e && e.isUnauthorized ? r.error.authFailed : "isNotFound" in e && e.isNotFound ? r.error.templateNotFound : r.error.defaultMessage;
}
function a(e) {
return "isNotFound" in e && !!e.isNotFound;
}
return (t, o) => e.visible && e.error ? (s(), m("div", bt, [
p("div", xt, [g(b(K), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
p("div", St, [p("h2", Ct, c(b(r).error.title), 1), p("p", wt, c(i(e.error)), 1)]),
a(e.error) ? w("", !0) : (s(), m("button", {
key: 0,
class: "tpl-btn tpl-btn-primary tpl:inline-flex tpl:items-center tpl:gap-2 tpl:rounded-md tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: o[0] ||= (e) => n("retry")
}, c(b(r).error.retry), 1))
])) : w("", !0);
}
}), Et = {
key: 0,
class: "tpl-preview-banner tpl:absolute tpl:top-14 tpl:right-0 tpl:left-0 tpl:z-40 tpl:flex tpl:items-center tpl:justify-center tpl:gap-4 tpl:px-4 tpl:py-3 tpl:bg-[var(--tpl-primary-light)] tpl:border-b tpl:border-[var(--tpl-primary)]"
}, Dt = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, Ot = { class: "tpl:flex tpl:items-center tpl:gap-2" }, kt = /* @__PURE__ */ f({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
return (t, i) => e.visible ? (s(), m("div", Et, [p("div", Dt, [g(b(me), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), p("span", null, c(b(r).snapshotPreview.message), 1)]), p("div", Ot, [p("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:text-[var(--tpl-text-muted)] tpl:border tpl:border-[var(--tpl-border)]",
style: { "background-color": "transparent" },
onClick: i[0] ||= (e) => n("cancel")
}, c(b(r).snapshotPreview.cancel), 1), p("button", {
class: "tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
onClick: i[1] ||= (e) => n("confirm")
}, c(b(r).snapshotPreview.restore), 1)])])) : w("", !0);
}
}), At = {
key: 0,
role: "status",
"aria-live": "polite",
class: "tpl:absolute tpl:top-16 tpl:left-1/2 tpl:z-toast tpl:-translate-x-1/2 tpl:rounded-[var(--tpl-radius)] tpl:px-4 tpl:py-2.5 tpl:text-sm tpl:shadow-lg",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-text)",
border: "1px solid var(--tpl-warning)"
}
}, jt = /* @__PURE__ */ f({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(e) {
let { t } = U();
return (n, r) => e.visible ? (s(), m("div", At, c(b(t).history.collabWarning), 1)) : w("", !0);
}
}), Mt = ["data-tpl-theme"], Nt = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, Pt = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, Ft = ["aria-label"], It = /*#__PURE__*/ ge(/* @__PURE__ */ f({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(e, { expose: a, emit: o }) {
let d = h(() => import("./SavedBlocksPanels-Dff38YXu.js")), f = e;
_(z, f.cloudTranslations);
let x = o, S = u(null), C = u(null), k = Be({
config: f.config,
translations: f.translations,
fontsManager: f.fontsManager,
emit: x,
getCommentsSidebar: () => S.value ? { filterByBlock: S.value.filterCommentsByBlock } : null,
editorRoot: f.shadowRoot,
containerEl: C
}), { isInitializing: A, isAuthReady: j, initError: M, planConfigInstance: N, websocket: F, collaboration: I, isCollaborationEnabled: L, editor: R, core: B, featureFlags: V, mediaLib: H, exporter: ee, testEmail: U, commentsInstance: W, savedBlocks: G, panelState: K, snapshotPreview: q, collabWarning: re, setThemeOverrides: ie, setUiTheme: ce } = k, { showNotice: le } = P(() => f.config.smallScreenNotice);
async function me(e) {
try {
await U.sendTestEmail(e), K.testEmailModalOpen.value = !1;
} catch {}
}
async function J() {
try {
await q.confirmRestoreSnapshot();
} catch {}
}
let Y = He({
config: f.config,
editor: R,
websocket: F,
planConfigInstance: N,
snapshotPreview: q,
core: B,
exporter: ee,
featureFlags: V,
isDestroyed: k.isDestroyed
}), X = Ue({
issues: B.templateLint ? B.templateLint.issues : u([]),
planConfig: N.config
});
async function Z() {
await X.tryRunSave(() => Y.saveTemplate().catch((e) => f.config.onError?.(e)));
}
return k.onSaveHook.value = Z, r(() => {
k.initialize();
}), t(() => {
k.destroy();
}), a({
getContent: () => R.content.value,
setContent: (e) => R.setContent(e),
setTheme: ce,
setThemeOverrides: ie,
create: Y.createTemplate,
load: Y.loadTemplate,
save: Y.saveTemplate,
sendTestEmail: U.sendTestEmail
}), (t, r) => (s(), m("div", {
ref_key: "rootEl",
ref: C,
class: i(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": b(R).state.darkMode }]),
"data-tpl-theme": b(B).resolvedTheme.value,
style: n(b(B).themeStyles.value),
onDragover: r[6] ||= E(() => {}, ["prevent"]),
onDrop: r[7] ||= E(() => {}, ["prevent"])
}, [
g(pe),
g(O, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-100",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: l(() => [g(yt, { visible: b(A) || b(R).state.isLoading }, null, 8, ["visible"])]),
_: 1
}),
g(O, {
"enter-active-class": "tpl:transition-opacity tpl:duration-200",
"enter-from-class": "tpl:opacity-0",
"enter-to-class": "tpl:opacity-100",
"leave-active-class": "tpl:transition-opacity tpl:duration-300",
"leave-from-class": "tpl:opacity-100",
"leave-to-class": "tpl:opacity-0"
}, {
default: l(() => [g(Tt, {
error: b(M),
visible: !!b(M) && !b(A),
onRetry: b(k).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
g(mt, {
editor: b(R),
core: b(B),
"feature-flags": b(V),
"panel-state": b(K),
"snapshot-preview": b(q),
"comments-instance": b(W),
"test-email": b(U),
websocket: b(F),
collaboration: b(I),
"is-collaboration-enabled": b(L),
"is-saving": b(R).state.isSaving || b(V).isSaveExporting.value,
"is-save-disabled": b(R).state.isSaving || b(V).isSaveExporting.value || !b(R).state.isDirty,
onSave: Z
}, null, 8, [
"editor",
"core",
"feature-flags",
"panel-state",
"snapshot-preview",
"comments-instance",
"test-email",
"websocket",
"collaboration",
"is-collaboration-enabled",
"is-saving",
"is-save-disabled"
]),
g($e, {
open: b(X).modalOpen.value,
issues: b(X).blockingIssues.value,
onCancel: b(X).cancel,
onConfirm: b(X).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
g(kt, {
visible: b(q).isPreviewingSnapshot.value,
onCancel: b(q).cancelPreview,
onConfirm: J
}, null, 8, ["visible", "onCancel"]),
g(O, {
"enter-active-class": "tpl:transition-all tpl:duration-200 tpl:ease-out",
"enter-from-class": "tpl:translate-y-[-8px] tpl:opacity-0",
"enter-to-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-active-class": "tpl:transition-all tpl:duration-300 tpl:ease-in",
"leave-from-class": "tpl:translate-y-0 tpl:opacity-100",
"leave-to-class": "tpl:translate-y-[-8px] tpl:opacity-0"
}, {
default: l(() => [g(jt, { visible: b(re).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
T(g(ae, null, null, 512), [[D, !b(R).state.previewMode]]),
p("div", {
class: i(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [b(R).state.previewMode ? "tpl:left-0 tpl:right-0" : b(K).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", b(q).isPreviewingSnapshot.value ? "tpl:top-[104px]" : "tpl:top-14"]]),
style: {
transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
"background-color": "var(--tpl-canvas-bg)"
}
}, [p("div", Nt, [g(O, { name: "tpl-restore-btn" }, {
default: l(() => [b(B).conditionPreview.hasHiddenBlocks.value ? (s(), m("button", {
key: 0,
class: "tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80",
style: {
"background-color": "var(--tpl-warning-light)",
color: "var(--tpl-warning)",
"border-color": "var(--tpl-warning)",
"backdrop-filter": "blur(8px)"
},
onClick: r[0] ||= (e) => b(B).conditionPreview.reset()
}, [g(b(oe), {
size: 13,
"stroke-width": 2
}), y(" " + c(b(B).t.blockSettings.restoreHiddenBlocks), 1)])) : w("", !0)]),
_: 1
})]), p("main", Pt, [g(ne, {
viewport: b(R).state.viewport,
content: b(R).content.value,
"selected-block-id": b(R).state.selectedBlockId,
"dark-mode": b(R).state.darkMode,
"preview-mode": b(R).state.previewMode,
"locked-blocks": b(I)?.lockedBlocks.value ?? void 0,
onSelectBlock: b(R).selectBlock,
onOpenAiChat: r[1] ||= (e) => b(K).aiChatOpen.value = !0,
onOpenDesignReference: r[2] ||= (e) => b(K).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
e.config.branding !== !1 && !b(V).isWhiteLabeled.value ? (s(), v(ue, {
key: 0,
"position-class": [b(R).state.previewMode ? "tpl:left-0 tpl:right-0" : b(K).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]"]
}, null, 8, ["position-class"])) : w("", !0),
p("div", {
class: "tpl-sr-only",
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
"aria-label": b(B).t.landmarks.reorderAnnouncements
}, c(b(B).keyboardReorder.announcement.value), 9, Ft),
T(g(te, {
"selected-block": b(R).selectedBlock.value,
settings: b(R).content.value.settings,
"shifted-left": b(K).rightPanelOpen.value,
onUpdateBlock: r[3] ||= (e) => b(R).updateBlock(b(R).selectedBlock.value.id, e),
onDeleteBlock: r[4] ||= (e) => b(B).blockActions.deleteBlock(b(R).selectedBlock.value.id),
onDuplicateBlock: r[5] ||= (e) => b(B).blockActions.duplicateBlock(b(R).selectedBlock.value),
onUpdateSettings: b(R).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[D, !b(R).state.previewMode]]),
!b(A) && b(j) ? (s(), v(ht, {
key: 1,
ref_key: "cloudPanelsRef",
ref: S,
config: f.config,
editor: b(R),
core: b(B),
"panel-state": b(K),
"plan-config-instance": b(N),
"test-email": b(U),
"media-lib": b(H),
onSendTestEmail: me
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib"
])) : w("", !0),
b(G).isAvailable.value ? (s(), v(b(d), {
key: 2,
feature: b(G)
}, null, 8, ["feature"])) : w("", !0),
p("div", {
ref: (e) => b(B).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
g(se),
g(fe),
b(le) ? (s(), v(de, { key: 3 })) : w("", !0)
], 46, Mt));
}
}), [["__scopeId", "data-v-04940787"]]);
//#endregion
export { It as default };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display