🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@templatical/editor

Package Overview
Dependencies
Maintainers
1
Versions
42
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.9.0
to
0.9.1
+1163
dist/cdn/chunks/CloudEditor-CrZk-OwQ.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 ee } from "./draggable-BwWMFq33.js";
import { $t as O, A as k, At as A, Dt as j, E as M, En as N, Et as P, Ft as F, Ht as I, It as te, Nt as ne, Qt as L, Rt as re, S as R, Ut as z, Vt as B, Z as ie, Zt as V, _ as H, _t as U, b as W, c as G, d as K, f as q, g as J, h as Y, in as X, l as ae, m as oe, p as se, pn as Z, pt as ce, rt as le, s as ue, st as de, tt as Q, u as fe, ut as pe, v as me, vt as he, x as ge, xn as _e, y as ve, zn as ye } from "./features-D-2kVhHY.js";
import { C as be, S as xe } from "./icons-fZoyKV_s.js";
import { a as Se, c as Ce, i as we, l as Te, n as Ee, o as De, r as Oe, s as ke, t as Ae } from "./styles-CVUvPdKD.js";
import { d as $ } from "./styleConstants-lGobwiLH.js";
//#region src/cloud/composables/useSnapshotPreview.ts
function je(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 = q({
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;
} 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 Me() {
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 X(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 Ne(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = c(!1), a = c(!1), { start: o } = Z(() => {
a.value = !1;
}, ye, { 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 Pe(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 } = Z(() => {
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 Fe(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: i } = e, a = null;
async function o() {
if (t) {
let e = await t({ accept: ["images"] });
return e ? {
url: e.url,
alt: e.alt_text || void 0
} : null;
}
return a &&= (a(null), null), i.value = ["images"], n.value = !0, new Promise((e) => {
a = (t) => {
e(t);
};
});
}
function s(e) {
n.value = !1, a?.({
url: e.url,
alt: e.alt_text || void 0
}), a = null;
}
function c() {
n.value = !1, a?.(null), a = null;
}
return r(() => {
a &&= (a(null), null);
}), {
handleRequestMedia: o,
handleMediaSelect: s,
handleMediaLibraryClose: c
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function Ie(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 M({
...t.auth,
onError: t.onError
}), _ = ae({
authManager: g,
onError: t.onError
}), v = c(/* @__PURE__ */ new Map()), y = ge({
authManager: g,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: v
}), b = oe({
authManager: g,
onError: t.onError
});
t.mcp?.enabled && ue({
editor: y,
channel: b.channel,
onOperation: t.mcp.onOperation
});
let x = null;
t.collaboration?.enabled && (x = J({
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
}), ee(() => x.lockedBlocks.value, (e) => {
v.value = e;
}, { immediate: !0 }), Y(y, x));
let S = f(() => !!t.collaboration?.enabled && _.hasFeature("collaboration")), C = k({
editor: y,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
customBlocks: [],
mergeTags: t.mergeTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: Te(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 = Ne({
isCollaborationEnabled: S,
getCollaboratorCount: () => x?.collaborators.value.length ?? 0,
canUndo: C.history.canUndo
});
h = w;
let T = je({
authManager: g,
editor: y,
history: C.history,
conditionPreview: C.conditionPreview,
autoSave: C.autoSave,
onError: t.onError
});
m = T;
let E = Me(), D = W(t.ai), A = Pe({
planConfigInstance: _,
aiConfig: D,
editor: y
}), j = Fe({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: E.mediaLibraryOpen,
mediaLibraryAccept: E.mediaLibraryAccept
});
ie({
onBlockMove: y.moveBlock,
onBlockAdd: y.addBlock
});
let N = fe({
authManager: g,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => _.hasFeature("custom_fonts")
}), P = K({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null,
save: () => y.save(),
exportHtml: (e) => N.exportHtml(e),
onError: t.onError,
isAuthReady: l,
onBeforeTestEmail: t.onBeforeTestEmail
}), F = me({
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")
});
H({
comments: F,
channel: b.channel
});
let I = se({
authManager: g,
onError: t.onError
}), R = c(!1), U = c(null), q = c(!1), X = ve({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null
});
function Z(e) {
E.commentsOpen.value = !0, queueMicrotask(() => {
o()?.filterByBlock(e);
});
}
a(V, j.handleRequestMedia), a(re, g), a(te, D), a(z, F), a(L, I), a(O, X), a(B, {
plan: _,
ai: D,
comments: {
getBlockCount: (e) => F.commentCountByBlock.value.get(e) ?? 0,
openForBlock: Z
},
savedModules: {
openSaveDialog: (e) => {
U.value = e ?? null, R.value = !0;
},
openBrowser: () => {
q.value = !0;
},
moduleCount: f(() => I.modules.value.length)
}
});
function ce(e) {
_.hasFeature("theme_customization") && (C.themeOverrides.value = e);
}
function le(e) {
y.setUiTheme(e);
}
async function de() {
s.value = !0, u.value = null;
try {
if (await g.initialize(), d) return;
l.value = !0;
let e = await G({ 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 || ne.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), t.modules !== !1 && _.hasFeature("saved_modules") && I.loadModules(), 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 Q() {
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: A,
mediaLib: j,
exporter: N,
testEmail: P,
commentsInstance: F,
savedModulesHeadless: I,
scoringInstance: X,
panelState: E,
snapshotPreview: T,
collabWarning: w,
showSaveModuleDialog: R,
showModuleBrowserModal: q,
saveModulePreSelectedBlockId: U,
onSaveHook: p,
initialize: de,
destroy: Q,
setThemeOverrides: ce,
setUiTheme: le,
openCommentsForBlock: Z
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Le(e, t) {
let n = async (e) => {
if (N(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 Re(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return R(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 Le(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 ze(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 Be = ["aria-label"], Ve = { 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)]" }, He = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Ue = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, We = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Ge = { 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" }, Ke = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, qe = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Je = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, Ye = /* @__PURE__ */ E({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
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", Ve, [
x("header", He, [D(h(de), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), x("h2", Ue, d(h(r).saveGate.title), 1)]),
x("p", We, d(h(r).saveGate.body), 1),
x("ul", Ge, [(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", Ke, d(e.message), 1), x("span", qe, d(e.ruleId), 1)]))), 128))]),
x("footer", Je, [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, Be)) : m("", !0)]),
_: 1
}));
}
}), Xe = {
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)"
}
}, Ze = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, Qe = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, $e = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, et = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, tt = ["data-tooltip"], nt = {
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)]"
}, rt = {
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)]"
}, it = ["aria-label", "aria-expanded"], at = {
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)]"
}, ot = ["aria-expanded"], st = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, ct = ["disabled"], lt = ["disabled"], ut = /* @__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-C4CFs5EJ.js")), n = u(() => import("./features-D-2kVhHY.js").then((e) => e.r)), r = u(() => import("./AiFeatureMenu-Dayzk2H7.js")), { t: a, format: o } = Q();
return (c, l) => (i(), p("header", Xe, [
x("div", Ze, [e.featureFlags.templateLimit.value === null ? m("", !0) : (i(), p("span", Qe, d(h(o)(h(a).header.templatesUsed, {
used: e.featureFlags.templateCount.value,
max: e.featureFlags.templateLimit.value
})), 1))]),
x("div", $e, [
D(Se, {
viewport: e.editor.state.viewport,
onChange: e.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
D(Oe, {
"dark-mode": e.editor.state.darkMode,
onChange: e.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
D(we, {
"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", et, [
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(j), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saveFailed), 1)], 8, tt)) : e.featureFlags.saveStatus.value === "saved" ? (i(), p("div", nt, [D(h(A), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saved), 1)])) : e.editor.state.isDirty ? (i(), p("div", rt, [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(U), {
size: 16,
"stroke-width": 2
}),
T(" " + d(h(a).comments.button) + " ", 1),
e.commentsInstance.unresolvedCount.value > 0 && !e.panelState.commentsOpen.value ? (i(), p("span", at, d(e.commentsInstance.unresolvedCount.value), 1)) : m("", !0)
], 14, it)) : 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(pe), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), T(" " + d(h(a).aiChat.button), 1)], 10, ot), 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", st, [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(he), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(ce), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(h(a).testEmail.button), 1)], 10, ct)) : 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(he), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(xe), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(e.isSaving ? h(a).header.saving : h(a).header.save), 1)], 10, lt)
])
]));
}
}), dt = /* @__PURE__ */ E({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {},
savedModulesHeadless: {},
showSaveModuleDialog: { type: Boolean },
saveModulePreSelectedBlockId: {},
showModuleBrowserModal: { type: Boolean }
},
emits: [
"update:showSaveModuleDialog",
"update:saveModulePreSelectedBlockId",
"update:showModuleBrowserModal",
"send-test-email",
"module-insert"
],
setup(e, { expose: t, emit: n }) {
let r = u(() => import("./features-D-2kVhHY.js").then((e) => e.o)), a = u(() => import("./features-D-2kVhHY.js").then((e) => e.a)), o = u(() => import("./features-D-2kVhHY.js").then((e) => e.i)), s = u(() => import("./features-D-2kVhHY.js").then((e) => e.n)), l = u(() => import("./features-D-2kVhHY.js").then((e) => e.t)), d = u(() => import("./SaveModuleDialog-BrtDXzIz.js")), f = u(() => import("./ModuleBrowserModal-Cgjz4xAz.js")), g = u(async () => {
try {
return (await import("./src-ftxPuuQh.js")).MediaLibraryModal;
} catch {
throw Error("[Templatical] Cloud media library requires the optional peer dependency '@templatical/media-library'. Please install it.");
}
}), _ = n;
function y(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
function b(e, t) {
_("module-insert", e, t);
}
let x = c(null);
function S(e) {
x.value?.filterByBlock(e);
}
return t({ filterCommentsByBlock: S }), (t, n) => (i(), p(w, null, [
D(h(r), {
visible: e.panelState.aiChatOpen.value,
"on-apply": (t) => y(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) => y(t, e.core, e.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
D(h(a), {
ref_key: "commentsSidebar",
ref: x,
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) => _("send-test-email", e),
onClose: n[6] ||= (t) => e.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
e.planConfigInstance.hasFeature("saved_modules") && e.config.modules !== !1 ? (i(), v(h(d), {
key: 0,
visible: e.showSaveModuleDialog,
"pre-selected-block-id": e.saveModulePreSelectedBlockId,
onClose: n[7] ||= (e) => {
_("update:showSaveModuleDialog", !1), _("update:saveModulePreSelectedBlockId", null);
},
onSaved: n[8] ||= (t) => e.savedModulesHeadless.loadModules()
}, null, 8, ["visible", "pre-selected-block-id"])) : m("", !0),
e.planConfigInstance.hasFeature("saved_modules") && e.config.modules !== !1 ? (i(), v(h(f), {
key: 1,
visible: e.showModuleBrowserModal,
onClose: n[9] ||= (e) => _("update:showModuleBrowserModal", !1),
onInsert: b
}, null, 8, ["visible"])) : m("", !0),
D(h(g), {
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));
}
}), ft = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, pt = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, mt = { 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)]" }, ht = /* @__PURE__ */ E({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(e) {
return (t, n) => e.visible ? (i(), p("div", ft, [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", pt, [x("div", mt, [(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);
}
}), gt = {
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)]"
}, _t = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, vt = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, yt = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, bt = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, xt = /* @__PURE__ */ E({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
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", gt, [
x("div", _t, [D(h(j), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
x("div", vt, [x("h2", yt, d(h(r).error.title), 1), x("p", bt, 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);
}
}), St = {
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)]"
}, Ct = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, wt = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Tt = /* @__PURE__ */ E({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
return (t, a) => e.visible ? (i(), p("div", St, [x("div", Ct, [D(h(P), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), x("span", null, d(h(r).snapshotPreview.message), 1)]), x("div", wt, [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);
}
}), Et = {
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)"
}
}, Dt = /* @__PURE__ */ E({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(e) {
let { t } = F();
return (n, r) => e.visible ? (i(), p("div", Et, d(h(t).history.collabWarning), 1)) : m("", !0);
}
}), Ot = ["data-tpl-theme"], kt = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, At = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, jt = ["aria-label"], Mt = /* @__PURE__ */ le(/* @__PURE__ */ E({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(e, { expose: r, emit: o }) {
let l = e;
a(I, l.cloudTranslations);
let u = o, f = c(null), _ = c(null), w = Ie({
config: l.config,
translations: l.translations,
fontsManager: l.fontsManager,
emit: u,
getCommentsSidebar: () => f.value ? { filterByBlock: f.value.filterCommentsByBlock } : null,
editorRoot: l.shadowRoot,
containerEl: _
}), { isInitializing: E, isAuthReady: ee, initError: O, planConfigInstance: k, websocket: A, collaboration: j, isCollaborationEnabled: M, editor: N, core: P, featureFlags: F, mediaLib: te, exporter: ne, testEmail: L, commentsInstance: re, savedModulesHeadless: R, panelState: z, snapshotPreview: B, collabWarning: ie, showSaveModuleDialog: V, showModuleBrowserModal: H, saveModulePreSelectedBlockId: U, setThemeOverrides: W, setUiTheme: G } = w;
async function K(e) {
try {
await L.sendTestEmail(e), z.testEmailModalOpen.value = !1;
} catch {}
}
function q(e, t) {
for (let n = 0; n < e.content.length; n++) {
let r = _e(e.content[n]), i = t === void 0 ? void 0 : t + n;
N.addBlock(r, void 0, void 0, i);
}
H.value = !1;
}
let J = Re({
config: l.config,
editor: N,
websocket: A,
planConfigInstance: k,
snapshotPreview: B,
core: P,
exporter: ne,
featureFlags: F,
isDestroyed: w.isDestroyed
}), Y = ze({
issues: P.templateLint ? P.templateLint.issues : c([]),
planConfig: k.config
});
async function X() {
await Y.tryRunSave(() => J.saveTemplate().catch((e) => l.config.onError?.(e)));
}
return w.onSaveHook.value = X, t(() => {
w.initialize();
}), g(() => {
w.destroy();
}), r({
getContent: () => N.content.value,
setContent: (e) => N.setContent(e),
setTheme: G,
setThemeOverrides: W,
create: J.createTemplate,
load: J.loadTemplate,
save: J.saveTemplate,
sendTestEmail: L.sendTestEmail
}), (t, r) => (i(), p("div", {
ref_key: "rootEl",
ref: _,
class: b(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": h(N).state.darkMode }]),
"data-tpl-theme": h(P).resolvedTheme.value,
style: C(h(P).themeStyles.value)
}, [
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(ht, { visible: h(E) || h(N).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(xt, {
error: h(O),
visible: !!h(O) && !h(E),
onRetry: h(w).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
D(ut, {
editor: h(N),
core: h(P),
"feature-flags": h(F),
"panel-state": h(z),
"snapshot-preview": h(B),
"comments-instance": h(re),
"test-email": h(L),
websocket: h(A),
collaboration: h(j),
"is-collaboration-enabled": h(M),
"is-saving": h(N).state.isSaving || h(F).isSaveExporting.value,
"is-save-disabled": h(N).state.isSaving || h(F).isSaveExporting.value || !h(N).state.isDirty,
onSave: X
}, 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(Ye, {
open: h(Y).modalOpen.value,
issues: h(Y).blockingIssues.value,
onCancel: h(Y).cancel,
onConfirm: h(Y).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
D(Tt, {
visible: h(B).isPreviewingSnapshot.value,
onCancel: h(B).cancelPreview,
onConfirm: h(B).confirmRestoreSnapshot
}, null, 8, [
"visible",
"onCancel",
"onConfirm"
]),
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(Dt, { visible: h(ie).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
n(D(ke, null, null, 512), [[S, !h(N).state.previewMode]]),
x("div", {
class: b(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [h(N).state.previewMode ? "tpl:left-0 tpl:right-0" : h(z).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", h(B).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", kt, [D(y, { name: "tpl-restore-btn" }, {
default: s(() => [h(P).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(P).conditionPreview.reset()
}, [D(h(be), {
size: 13,
"stroke-width": 2
}), T(" " + d(h(P).t.blockSettings.restoreHiddenBlocks), 1)])) : m("", !0)]),
_: 1
})]), x("main", At, [D(Ce, {
viewport: h(N).state.viewport,
content: h(N).content.value,
"selected-block-id": h(N).state.selectedBlockId,
"dark-mode": h(N).state.darkMode,
"preview-mode": h(N).state.previewMode,
"locked-blocks": h(j)?.lockedBlocks.value ?? void 0,
onSelectBlock: h(N).selectBlock,
onOpenAiChat: r[1] ||= (e) => h(z).aiChatOpen.value = !0,
onOpenDesignReference: r[2] ||= (e) => h(z).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
e.config.branding !== !1 && !h(F).isWhiteLabeled.value ? (i(), v(Ee, {
key: 0,
"position-class": [h(N).state.previewMode ? "tpl:left-0 tpl:right-0" : h(z).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(P).t.landmarks.reorderAnnouncements
}, d(h(P).keyboardReorder.announcement.value), 9, jt),
n(D(De, {
"selected-block": h(N).selectedBlock.value,
settings: h(N).content.value.settings,
"shifted-left": h(z).rightPanelOpen.value,
onUpdateBlock: r[3] ||= (e) => h(N).updateBlock(h(N).selectedBlock.value.id, e),
onDeleteBlock: r[4] ||= (e) => h(P).blockActions.deleteBlock(h(N).selectedBlock.value.id),
onDuplicateBlock: r[5] ||= (e) => h(P).blockActions.duplicateBlock(h(N).selectedBlock.value),
onUpdateSettings: h(N).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[S, !h(N).state.previewMode]]),
!h(E) && h(ee) ? (i(), v(dt, {
key: 1,
ref_key: "cloudPanelsRef",
ref: f,
config: l.config,
editor: h(N),
core: h(P),
"panel-state": h(z),
"plan-config-instance": h(k),
"test-email": h(L),
"media-lib": h(te),
"saved-modules-headless": h(R),
"show-save-module-dialog": h(V),
"save-module-pre-selected-block-id": h(U),
"show-module-browser-modal": h(H),
"onUpdate:showSaveModuleDialog": r[6] ||= (e) => V.value = e,
"onUpdate:saveModulePreSelectedBlockId": r[7] ||= (e) => U.value = e,
"onUpdate:showModuleBrowserModal": r[8] ||= (e) => H.value = e,
onSendTestEmail: K,
onModuleInsert: q
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib",
"saved-modules-headless",
"show-save-module-dialog",
"save-module-pre-selected-block-id",
"show-module-browser-modal"
])) : m("", !0),
x("div", {
ref: (e) => h(P).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
D(Ae)
], 14, Ot));
}
}), [["__scopeId", "data-v-3f0f5cfa"]]);
//#endregion
export { Mt as default };
//# sourceMappingURL=CloudEditor-CrZk-OwQ.js.map

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

import { n as e } from "./rolldown-runtime-Dqa2HsxW.js";
import { An as t, Dn as n, En as r, Fn as i, In as a, Ln as o, Mn as s, Nn as c, On as l, Pn as u, Rn as d, Tn as f, jn as p, kn as m } from "./features-D-2kVhHY.js";
//#endregion
//#region ../renderer/src/render-context.ts
var h = `https://unpkg.com/@templatical/renderer@${{
name: "@templatical/renderer",
description: "Render Templatical email templates to MJML",
version: "0.9.1",
bugs: "https://github.com/templatical/sdk/issues",
dependencies: { "@templatical/types": "workspace:*" },
devDependencies: {
"@resvg/resvg-js": "^2.6.2",
mjml: "^5.2.2",
tsup: "^8.5.1",
typescript: "^6.0.3",
vitest: "^4.1.7"
},
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: "tsup && 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`, g = {
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"
}, _ = class e {
containerWidth;
customFonts;
defaultFallbackFont;
allowHtmlBlocks;
customBlockHtml;
socialIconsBaseUrl;
constructor(e, t, n, r, i = /* @__PURE__ */ new Map(), a = h) {
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 g[e.toLowerCase()] || e;
}
}, v = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
"\"": "&quot;",
"'": "&#039;"
}, y = /[&<>"']/g;
function b(e) {
return e === "" ? "" : e.replace(y, (e) => v[e] ?? e);
}
function x(e) {
return e === "" ? "" : e.replace(y, (e) => v[e] ?? e);
}
function S(e) {
return e === "" ? "" : x(e).replace(/[;{}\r\n]/g, "");
}
function C(e) {
return e === "" ? "" : ee(e, (e) => w(e, "data-merge-tag") ?? w(e, "data-logic-merge-tag"));
}
function ee(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.tablet && !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.tablet || n.push("tpl-hide-tablet"), t.mobile || n.push("tpl-hide-mobile"), n.join(" ");
}
//#endregion
//#region ../renderer/src/renderers/title.ts
function te(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = ne(C(e.content)), a = d[e.level] ?? d[2], o = x(e.color), s = e.textAlign, c = re(e.fontFamily, t), l = O(e), u = `h${d[e.level] ? e.level : 2}`;
return `<mj-text
font-size="${a}px"
color="${o}"
align="${s}"
line-height="1.3"
padding="${n}"${r}${c}${l}
><${u} style="margin:0;font-size:inherit;color:inherit;line-height:inherit">${i}</${u}></mj-text>`;
}
function ne(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 re(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/paragraph.ts
function A(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 = C(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 j(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="${x(e.linkUrl)}"`, e.linkOpenInNewTab && (o += " target=\"_blank\" rel=\"noopener\""));
let s = x(e.src), c = e.decorative === !0;
return `<mj-image
src="${s}"
alt="${c ? "" : x(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 === "" ? "" : x(e.url), o = a === "" ? "" : ` href="${a}"`, s = x(e.backgroundColor), c = x(e.textColor), l = e.fontSize, u = e.borderRadius, d = b(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)}${O(e)}
>${d}</mj-button>`;
}
function N(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/divider.ts
function P(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = e.styles.backgroundColor ? ` container-background-color="${x(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="${x(e.color)}"
width="${i}"
padding="${n}"${r}${O(e)}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/spacer.ts
function F(e, t) {
return D(e) ? "" : `<mj-spacer height="${e.height}px" padding="0"${e.styles.backgroundColor ? ` container-background-color="${x(e.styles.backgroundColor)}"` : ""}${O(e)} />`;
}
//#endregion
//#region ../renderer/src/renderers/html.ts
function I(e, t) {
if (D(e) || !t.allowHtmlBlocks) return "";
let n = e.content;
return n === "" ? "" : `<mj-text${O(e)}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/renderers/social.ts
function L(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="${x(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 = x(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 R(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 = V(e.fontFamily, t), o = e.textAlign;
return `<mj-text
font-size="${e.fontSize}px"
color="${x(e.color)}"
align="${o}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${z(e)}</mj-text>`;
}
function z(e) {
let t = e.items, n = b(e.separator), r = S(e.separatorColor), i = e.spacing, a = e.linkColor ?? e.color, o = [], s = t.length;
for (let e = 0; e < s; e++) o.push(B(t[e], a)), e < s - 1 && o.push(`<span style="color: ${r}; padding: 0 ${i}px;">${n}</span>`);
return o.join("");
}
function B(e, t) {
let n = b(e.text), r = x(e.url), i = S(e.color ?? t), a = e.openInNewTab ? " target=\"_blank\" rel=\"noopener\"" : "", o = [`color: ${i}`, "text-decoration: none"];
return e.bold && o.push("font-weight: bold"), e.underline && o.push("text-decoration: underline"), `<a href="${r}" style="${o.join("; ")}"${a}>${n}</a>`;
}
function V(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/table.ts
function H(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 = ie(e.fontFamily, t);
return `<mj-text
font-size="${e.fontSize}px"
color="${x(e.color)}"
align="${e.textAlign}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${U(e)}</mj-text>`;
}
function U(e) {
let t = S(e.borderColor), n = e.borderWidth, r = "";
for (let i = 0; i < e.rows.length; i++) {
let a = e.rows[i];
r += W(a, e, e.hasHeaderRow && i === 0, t, n);
}
return `<table style="width: 100%; border-collapse: collapse;">${r}</table>`;
}
function W(e, t, n, r, i) {
let a = "";
for (let o of e.cells) a += G(o, t, n, r, i);
return `<tr>${a}</tr>`;
}
function G(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: ${S(t.headerBackgroundColor)}`));
let s = o.join("; "), c = C(e.content), l = n ? "th" : "td";
return `<${l} style="${s}">${c}</${l}>`;
}
function ie(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/custom.ts
function K(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${E(e.styles?.backgroundColor, "container")}${r}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/columns.ts
function q(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 J(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/renderers/section.ts
function Y(e, t, n) {
if (D(e)) return "";
let r = e.columns, i = q(r), a = J(r, t.containerWidth), o = T(e.styles.padding), c = E(e.styles.backgroundColor, "native"), l = O(e), u = e.children, d = [];
for (let e = 0; e < u.length; e++) {
let r = u[e], o = i[e] ?? "100%", c = Math.floor(a[e] ?? t.containerWidth), l = ae(r, t.allowHtmlBlocks).filter((e) => !s(e)), f = t.withContainerWidth(c), p = l.map((e) => n(e, f)).filter((e) => e !== "").join("\n");
d.push(`<mj-column width="${o}">
${p === "" ? "<mj-text>&nbsp;</mj-text>" : p}
</mj-column>`);
}
return `<mj-section${c} padding="${o}"${l}>
${d.join("\n")}
</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="${x(n)}"
alt="${x(e.alt)}"
width="${a}"
align="${e.align}"
padding="${r}"
href="${x(e.url)}"
target="_blank"
rel="noopener"${i}${o}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/index.ts
function X(e, d) {
return s(e) ? Y(e, d, X) : a(e) ? te(e, d) : p(e) ? A(e, d) : m(e) ? j(e, d) : f(e) ? M(e, d) : n(e) ? P(e, d) : u(e) ? F(e, d) : l(e) ? I(e, d) : c(e) ? L(e, d) : t(e) ? R(e, d) : i(e) ? H(e, d) : o(e) ? se(e, d) : r(e) ? K(e, d) : "";
}
//#endregion
//#region ../renderer/src/index.ts
var ce = /* @__PURE__ */ e({
DEFAULT_SOCIAL_ICONS_BASE_URL: () => h,
RenderContext: () => _,
convertMergeTagsToValues: () => C,
escapeAttr: () => x,
escapeHtml: () => b,
getCssClassAttr: () => O,
getCssClasses: () => k,
getWidthPercentages: () => q,
getWidthPixels: () => J,
isHiddenOnAll: () => D,
renderBlock: () => X,
renderToMjml: () => Z,
toPaddingString: () => T
});
async function Z(e, t) {
let n = t?.customFonts ?? [], r = t?.defaultFallbackFont ?? "Arial, sans-serif", i = t?.allowHtmlBlocks ?? !0, a = de(t?.socialIconsBaseUrl ?? h), o = await he(e, t?.renderCustomBlock), s = new _(e.settings.width, n, r, i, o, a), c = me(e.blocks, i), l = s.resolveFontFamily(e.settings.fontFamily), u = e.settings.backgroundColor, d = c.map((e) => le(e, s)).filter((e) => e !== "").join("\n"), f = pe(n), p = fe(e.settings.preheaderText);
return `<mjml lang="${x(e.settings.locale)}">
<mj-head>${p}
<mj-attributes>
<mj-all font-family="${l}" />
<mj-text font-size="14px" />
<mj-section padding="0" />
<mj-column padding="0" />
<mj-image fluid-on-mobile="true" />
</mj-attributes>${f}
<mj-style>
a { color: inherit; text-decoration: none; }
@media only screen and (max-width: 480px) {
.tpl-hide-mobile { display: none !important; mso-hide: all !important; }
}
@media only screen and (min-width: 481px) and (max-width: 768px) {
.tpl-hide-tablet { display: none !important; mso-hide: all !important; }
}
@media only screen and (min-width: 769px) {
.tpl-hide-desktop { display: none !important; mso-hide: all !important; }
}
</mj-style>
</mj-head>
<mj-body width="${s.containerWidth}px" background-color="${u}">
${d}
</mj-body>
</mjml>`;
}
function le(e, t) {
return s(e) ? Q(e, X(e, t)) : Q(e, ue(X(e, t)));
}
function Q(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;
}
function ue(e) {
return e === "" ? "" : `<mj-section>
<mj-column>
${e}
</mj-column>
</mj-section>`;
}
function de(e) {
return e.endsWith("/") ? e.slice(0, -1) : e;
}
function fe(e) {
if (!e) return "";
let t = e.trim();
return t === "" ? "" : `\n <mj-preview>${b(t)}</mj-preview>`;
}
function pe(e) {
return e.length === 0 ? "" : e.map((e) => `\n <mj-font name="${x(e.name)}" href="${x(e.url)}" />`).join("");
}
function me(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, t) {
for (let n of e) {
if (r(n)) {
t.push(n);
continue;
}
if (s(n)) for (let e of n.children) $(e, t);
}
}
//#endregion
export { ce as t };
//# sourceMappingURL=renderer-CfHPFI5v.js.map

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

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

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

import { A as e, B as t, L as n, M as r, O as i, Q as a, X as o, _ as s, at as c, b as l, c as u, d, f, g as p, h as m, j as h, k as g, l as _, m as v, o as y, ot as b, p as x, q as S, rt as C, st as w, t as T, v as E, y as D, z as O } from "./vue.runtime.esm-bundler-BDSGA5hA.js";
import { t as k } from "./timeouts-Bmi_yePw.js";
import { E as A, i as j } from "./dist-CIV3Brg-.js";
import { P as M, S as N, t as P } from "./useEditorCore-CEkf_VWX.js";
import { c as F, t as I } from "./dist-CNLAS2v2.js";
import { E as L, S as R, T as z, c as B, l as V, r as ee, s as te, t as H } from "./keys-BiQlvx51.js";
import { t as U } from "./useI18n-Besvmtxy.js";
import { t as W } from "./createLucideIcon-XgXOJ05E.js";
import { t as G } from "./check-ChQyfxJ3.js";
import { t as K } from "./circle-alert-CPH6l3Lc.js";
import { a as q, c as ne, i as J, l as re, n as ie, o as ae, r as oe, s as se, t as ce, u as le } from "./styles-CxwIlb7Y.js";
import { t as ue } from "./clock-DHl_BIkU.js";
import { t as Y } from "./loader-circle-Rz_4vJLH.js";
import { t as X } from "./message-circle-D-umK_MU.js";
import { t as Z } from "./send-BhbhbIFT.js";
import { t as de } from "./sparkles-CrUN0KWY.js";
import { t as fe } from "./triangle-alert-MwJBKR2e.js";
import { t as pe } from "./_plugin-vue_export-helper-B3ysoDQm.js";
import { n as Q } from "./useCloudI18n-DKWJg6rJ.js";
import { d as $ } from "./styleConstants-lGobwiLH.js";
import { _ as me, a as he, c as ge, d as _e, f as ve, g as ye, h as be, l as xe, m as Se, n as Ce, o as we, p as Te, r as Ee, s as De, t as Oe, v as ke, y as Ae } from "./cloud-VxYMtfXC.js";
var je = 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 Me(e) {
let { authManager: t, editor: n, history: r, conditionPreview: i, autoSave: s, onError: c } = e, l = a(null), u = o(null), f = o(null), p = !1;
S(() => {
p = !0;
});
let m = d(() => u.value !== null), h = d(() => l.value?.snapshots.value ?? []), g = d(() => l.value?.isLoading.value ?? !1), _ = d(() => l.value?.isRestoring.value ?? !1);
function v() {
n.state.template?.id && !l.value && (l.value = ye({
authManager: t,
templateId: n.state.template.id,
onRestore: y,
onError: c
}), l.value.loadSnapshots());
}
function y(e) {
n.setContent(e.content, !1), r.clear(), i.reset();
}
async function b(e) {
if (!p) {
if (u.value) {
u.value = e, n.setContent(e.content, !1);
return;
}
n.state.isDirty && n.hasTemplate() && (await n.createSnapshot(), p) || (f.value = structuredClone(n.content.value), s?.pause(), u.value = e, n.setContent(e.content, !1));
}
}
async function x() {
if (!(!u.value || !l.value)) try {
if (await l.value.restoreSnapshot(u.value.id), p || (await l.value.loadSnapshots(), p)) return;
} finally {
p || (u.value = null, f.value = null, s?.resume());
}
}
function C() {
!u.value || !f.value || (n.setContent(f.value, !1), u.value = null, f.value = null, s?.resume());
}
async function w() {
p || l.value && await l.value.loadSnapshots();
}
return {
snapshotHistoryInstance: l,
previewingSnapshot: u,
contentBeforePreview: f,
isPreviewingSnapshot: m,
snapshotHistorySnapshots: h,
snapshotHistoryIsLoading: g,
snapshotHistoryIsRestoring: _,
initSnapshotHistory: v,
handleRestore: y,
handleSnapshotNavigate: b,
confirmRestoreSnapshot: x,
cancelPreview: C,
loadSnapshotHistory: w
};
}
//#endregion
//#region src/cloud/composables/useCloudPanelState.ts
function Ne() {
let e = o(null), t = d({
get: () => e.value === "ai-chat",
set: (t) => e.value = t ? "ai-chat" : null
}), n = d({
get: () => e.value === "scoring",
set: (t) => e.value = t ? "scoring" : null
}), r = d({
get: () => e.value === "design-reference",
set: (t) => e.value = t ? "design-reference" : null
}), i = d({
get: () => e.value === "comments",
set: (t) => e.value = t ? "comments" : null
}), a = o(!1), s = o(!1), c = o(void 0), l = o(!1), u = o(null), f = d(() => e.value !== null), p = d(() => {
let t = e.value;
return t === "ai-chat" || t === "design-reference" || t === "scoring" ? t : null;
}), m = d(() => 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: s,
mediaLibraryAccept: c,
aiMenuOpen: l,
aiMenuRef: u,
rightPanelOpen: f,
activeAiFeature: p,
aiButtonActive: m,
toggleAiMenu: h,
handleAiFeatureSelect: g
};
}
//#endregion
//#region src/cloud/composables/useCollabUndoWarning.ts
function Pe(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = o(!1), a = o(!1), { start: s } = F(() => {
a.value = !1;
}, k, { immediate: !1 });
function c() {
i.value || !t.value || n() === 0 || !r.value || (i.value = !0, a.value = !0, s());
}
return {
collabUndoWarningVisible: a,
showCollabUndoWarning: c
};
}
//#endregion
//#region src/cloud/composables/useCloudFeatureFlags.ts
function Fe(e) {
let { planConfigInstance: t, aiConfig: n, editor: r } = e, i = d(() => t.hasFeature("ai_generation") && n.hasAnyMenuFeature.value), a = d(() => t.hasFeature("test_email")), s = d(() => !!r.state.template?.id), c = d(() => t.hasFeature("white_label")), l = d(() => t.config.value?.limits.max_templates ?? null), u = d(() => t.config.value?.template_count ?? 0), f = o(!1), p = o("idle"), m = o(""), { start: h } = F(() => {
p.value = "idle";
}, 3e3, { immediate: !1 });
return {
canUseAiGeneration: i,
canSendTestEmail: a,
hasTemplateSaved: s,
isWhiteLabeled: c,
templateLimit: l,
templateCount: u,
isSaveExporting: f,
saveStatus: p,
saveErrorMessage: m,
startSaveStatusClear: h
};
}
//#endregion
//#region src/cloud/composables/useCloudMediaLibrary.ts
function Ie(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: r } = e, i = null;
async function a() {
if (t) {
let e = await t({ accept: ["images"] });
return e ? {
url: e.url,
alt: e.alt_text || void 0
} : null;
}
return i &&= (i(null), null), r.value = ["images"], n.value = !0, new Promise((e) => {
i = (t) => {
e(t);
};
});
}
function o(e) {
n.value = !1, i?.({
url: e.url,
alt: e.alt_text || void 0
}), i = null;
}
function s() {
n.value = !1, i?.(null), i = null;
}
return S(() => {
i &&= (i(null), null);
}), {
handleRequestMedia: a,
handleMediaSelect: o,
handleMediaLibraryClose: s
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function Le(e) {
let { config: t, translations: r, fontsManager: i, emit: a, getCommentsSidebar: s } = e, c = o(!0), l = o(!1), u = o(null), f = !1, p = { value: null }, m = null, g = null, _ = new Oe({
...t.auth,
onError: t.onError
}), v = Se({
authManager: _,
onError: t.onError
}), y = o(/* @__PURE__ */ new Map()), b = _e({
authManager: _,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: y
}), x = Ae({
authManager: _,
onError: t.onError
});
t.mcp?.enabled && Te({
editor: b,
channel: x.channel,
onOperation: t.mcp.onOperation
});
let S = null;
t.collaboration?.enabled && (S = we({
authManager: _,
editor: b,
channel: x.channel,
onError: t.onError,
onCollaboratorJoined: t.collaboration.onCollaboratorJoined,
onCollaboratorLeft: t.collaboration.onCollaboratorLeft,
onBlockLocked: t.collaboration.onBlockLocked,
onBlockUnlocked: t.collaboration.onBlockUnlocked
}), n(() => S.lockedBlocks.value, (e) => {
y.value = e;
}, { immediate: !0 }), De(b, S));
let C = d(() => !!t.collaboration?.enabled && v.hasFeature("collaboration")), w = P({
editor: b,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
customBlocks: [],
mergeTags: t.mergeTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: re(t),
onSave: () => {
p.value?.().catch((e) => {
t.onError?.(e);
});
}
},
translations: r,
fontsManager: i,
historyOptions: S ? { isRemoteOperation: () => S._isProcessingRemoteOperation() } : void 0,
autoSaveOptions: {
onChange: async () => {
b.hasTemplate() && (await b.createSnapshot(), m?.snapshotHistoryInstance.value?.loadSnapshots());
},
debounce: t.autoSaveDebounce ?? 5e3,
enabled: () => t.autoSave !== !1 && v.hasFeature("auto_save")
},
themeExtraStyles: () => ({ "--tpl-drop-text": `"${r.canvas.dropHere}"` }),
keyboardOptions: { onBeforeUndo: () => g?.showCollabUndoWarning() },
editorRoot: e.editorRoot,
containerEl: e.containerEl
}), T = Pe({
isCollaborationEnabled: C,
getCollaboratorCount: () => S?.collaborators.value.length ?? 0,
canUndo: w.history.canUndo
});
g = T;
let E = Me({
authManager: _,
editor: b,
history: w.history,
conditionPreview: w.conditionPreview,
autoSave: w.autoSave,
onError: t.onError
});
m = E;
let D = Ne(), O = he(t.ai), k = Fe({
planConfigInstance: v,
aiConfig: O,
editor: b
}), A = Ie({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: D.mediaLibraryOpen,
mediaLibraryAccept: D.mediaLibraryAccept
});
N({
onBlockMove: b.moveBlock,
onBlockAdd: b.addBlock
});
let j = ve({
authManager: _,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => v.hasFeature("custom_fonts")
}), F = ke({
authManager: _,
getTemplateId: () => b.state.template?.id ?? null,
save: () => b.save(),
exportHtml: (e) => j.exportHtml(e),
onError: t.onError,
isAuthReady: l,
onBeforeTestEmail: t.onBeforeTestEmail
}), I = xe({
authManager: _,
getTemplateId: () => b.state.template?.id ?? null,
getSocketId: () => x.getSocketId(),
onComment: t.onComment,
onError: t.onError,
isAuthReady: l,
hasCommentingFeature: () => t.commenting !== !1 && v.hasFeature("commenting")
});
ge({
comments: I,
channel: x.channel
});
let B = be({
authManager: _,
onError: t.onError
}), U = o(!1), W = o(null), G = o(!1), K = me({
authManager: _,
getTemplateId: () => b.state.template?.id ?? null
});
function q(e) {
D.commentsOpen.value = !0, queueMicrotask(() => {
s()?.filterByBlock(e);
});
}
h(R, A.handleRequestMedia), h(ee, _), h(H, O), h(V, I), h(z, B), h(L, K), h(te, {
plan: v,
ai: O,
comments: {
getBlockCount: (e) => I.commentCountByBlock.value.get(e) ?? 0,
openForBlock: q
},
savedModules: {
openSaveDialog: (e) => {
W.value = e ?? null, U.value = !0;
},
openBrowser: () => {
G.value = !0;
},
moduleCount: d(() => B.modules.value.length)
}
});
function ne(e) {
v.hasFeature("theme_customization") && (w.themeOverrides.value = e);
}
function J(e) {
b.setUiTheme(e);
}
async function ie() {
c.value = !0, u.value = null;
try {
if (await _.initialize(), f) return;
l.value = !0;
let e = await Ce({ authManager: _ });
if (f) 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 v.fetchConfig(), f) return;
i.setCustomFontsEnabled(v.hasFeature("custom_fonts")), t.customBlocks?.length && v.hasFeature("custom_blocks") && w.registerCustomBlocks(t.customBlocks), t.theme && v.hasFeature("theme_customization") && (w.themeOverrides.value = t.theme), t.modules !== !1 && v.hasFeature("saved_modules") && B.loadModules(), a("ready");
} catch (e) {
if (f) return;
let n = e instanceof Error ? e : Error("Initialization failed", { cause: e });
u.value = n, t.onError?.(n);
} finally {
f || (c.value = !1);
}
}
function ae() {
f = !0, i.cleanupFontLinks(), x.disconnect(), w.destroy(), t.onUnmount?.();
}
return {
isInitializing: c,
isAuthReady: l,
initError: u,
isDestroyed: () => f,
authManager: _,
planConfigInstance: v,
websocket: x,
collaboration: S,
isCollaborationEnabled: C,
editor: b,
core: w,
aiConfig: O,
featureFlags: k,
mediaLib: A,
exporter: j,
testEmail: F,
commentsInstance: I,
savedModulesHeadless: B,
scoringInstance: K,
panelState: D,
snapshotPreview: E,
collabWarning: T,
showSaveModuleDialog: U,
showModuleBrowserModal: G,
saveModulePreSelectedBlockId: W,
onSaveHook: p,
initialize: ie,
destroy: ae,
setThemeOverrides: ne,
setUiTheme: J,
openCommentsForBlock: q
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Re(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 ze(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return Ee(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 Re(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 Be(e) {
let t = o(!1), n = null, r = d(() => e.planConfig.value?.accessibility?.blockOnError === !0), i = d(() => r.value ? e.issues.value.filter((e) => e.severity === "error") : []), a = d(() => i.value.length > 0);
async function s(e) {
return a.value ? (n = e, t.value = !0, !1) : (await e(), !0);
}
async function c() {
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: s,
confirmAndSave: c,
cancel: l
};
}
//#endregion
//#region src/cloud/components/CloudSaveGateModal.vue?vue&type=script&setup=true&lang.ts
var Ve = ["aria-label"], He = { 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)]" }, Ue = { class: "tpl:flex tpl:items-center tpl:gap-2" }, We = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, Ge = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Ke = { 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" }, qe = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, Je = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Ye = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, Xe = /* @__PURE__ */ l({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(t, { emit: n }) {
let i = n, { t: a } = Q();
return (n, o) => (e(), x(T, {
"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: O(() => [t.open ? (e(), m("div", {
key: 0,
role: "dialog",
"aria-modal": "true",
"aria-label": C(a).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: o[2] ||= u((e) => i("cancel"), ["self"])
}, [f("div", He, [
f("header", Ue, [E(C(fe), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), f("h2", We, w(C(a).saveGate.title), 1)]),
f("p", Ge, w(C(a).saveGate.body), 1),
f("ul", Ke, [(e(!0), m(_, null, r(t.issues, (t) => (e(), m("li", {
key: `${t.ruleId}-${t.blockId ?? "template"}`,
class: "tpl:flex tpl:flex-col tpl:gap-0.5 tpl:rounded tpl:px-2 tpl:py-1.5"
}, [f("span", qe, w(t.message), 1), f("span", Je, w(t.ruleId), 1)]))), 128))]),
f("footer", Ye, [f("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: o[0] ||= (e) => i("cancel")
}, w(C(a).saveGate.cancel), 1), f("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: o[1] ||= (e) => i("confirm")
}, w(C(a).saveGate.confirm), 1)])
])], 8, Ve)) : v("", !0)]),
_: 1
}));
}
}), Ze = {
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)"
}
}, Qe = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, $e = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, et = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, tt = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, nt = ["data-tooltip"], rt = {
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)]"
}, it = {
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)]"
}, at = ["aria-label", "aria-expanded"], ot = {
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)]"
}, st = ["aria-expanded"], ct = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, lt = ["disabled"], ut = ["disabled"], dt = /* @__PURE__ */ l({
__name: "CloudHeader",
props: {
editor: {},
core: {},
featureFlags: {},
panelState: {},
snapshotPreview: {},
commentsInstance: {},
testEmail: {},
websocket: {},
collaboration: {},
isCollaborationEnabled: { type: Boolean },
isSaveDisabled: { type: Boolean },
isSaving: { type: Boolean }
},
emits: ["save"],
setup(t) {
let n = D(() => import("./CollaboratorBar-Bc6q0gB9.js")), r = D(() => import("./SnapshotHistory-CIo2Jaw-.js")), i = D(() => import("./AiFeatureMenu-Co14YVJt.js")), { t: a, format: o } = Q();
return (l, d) => (e(), m("header", Ze, [
f("div", Qe, [t.featureFlags.templateLimit.value === null ? v("", !0) : (e(), m("span", $e, w(C(o)(C(a).header.templatesUsed, {
used: t.featureFlags.templateCount.value,
max: t.featureFlags.templateLimit.value
})), 1))]),
f("div", et, [
E(q, {
viewport: t.editor.state.viewport,
onChange: t.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
E(oe, {
"dark-mode": t.editor.state.darkMode,
onChange: t.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
E(J, {
"preview-mode": t.editor.state.previewMode,
onChange: t.editor.setPreviewMode
}, null, 8, ["preview-mode", "onChange"]),
t.collaboration && t.isCollaborationEnabled ? (e(), x(C(n), {
key: 0,
collaborators: t.collaboration.collaborators.value,
"is-connected": t.websocket.isConnected.value
}, null, 8, ["collaborators", "is-connected"])) : v("", !0),
t.snapshotPreview.snapshotHistoryInstance.value ? (e(), x(C(r), {
key: 1,
snapshots: t.snapshotPreview.snapshotHistorySnapshots.value,
"is-loading": t.snapshotPreview.snapshotHistoryIsLoading.value,
"is-restoring": t.snapshotPreview.snapshotHistoryIsRestoring.value,
onLoad: t.snapshotPreview.loadSnapshotHistory,
onNavigate: t.snapshotPreview.handleSnapshotNavigate
}, null, 8, [
"snapshots",
"is-loading",
"is-restoring",
"onLoad",
"onNavigate"
])) : v("", !0)
]),
f("div", tt, [
t.featureFlags.saveStatus.value === "error" ? (e(), 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": t.featureFlags.saveErrorMessage.value
}, [E(C(K), {
size: 12,
"stroke-width": 2.5
}), s(" " + w(C(a).header.saveFailed), 1)], 8, nt)) : t.featureFlags.saveStatus.value === "saved" ? (e(), m("div", rt, [E(C(G), {
size: 12,
"stroke-width": 2.5
}), s(" " + w(C(a).header.saved), 1)])) : t.editor.state.isDirty ? (e(), m("div", it, [d[4] ||= f("span", { class: "tpl-pulse tpl:size-1.5 tpl:rounded-full tpl:bg-[var(--tpl-primary)]" }, null, -1), s(" " + w(C(a).header.unsaved), 1)])) : v("", !0),
t.commentsInstance.isEnabled.value && t.featureFlags.hasTemplateSaved.value ? (e(), m("button", {
key: 3,
"aria-label": t.commentsInstance.unresolvedCount.value > 0 ? `${C(a).comments.button} (${t.commentsInstance.unresolvedCount.value})` : C(a).comments.button,
"aria-expanded": t.panelState.commentsOpen.value,
class: c(C($)),
style: b({
backgroundColor: t.panelState.commentsOpen.value ? "var(--tpl-primary)" : "transparent",
color: t.panelState.commentsOpen.value ? "var(--tpl-bg)" : "var(--tpl-primary)",
borderColor: "var(--tpl-primary)"
}),
onClick: d[0] ||= (e) => t.panelState.commentsOpen.value = !t.panelState.commentsOpen.value
}, [
E(C(X), {
size: 16,
"stroke-width": 2
}),
s(" " + w(C(a).comments.button) + " ", 1),
t.commentsInstance.unresolvedCount.value > 0 && !t.panelState.commentsOpen.value ? (e(), m("span", ot, w(t.commentsInstance.unresolvedCount.value), 1)) : v("", !0)
], 14, at)) : v("", !0),
t.featureFlags.canUseAiGeneration.value && t.featureFlags.hasTemplateSaved.value ? (e(), m("div", {
key: 4,
ref: (e) => t.panelState.aiMenuRef.value = e,
class: "tpl:relative"
}, [f("button", {
"aria-expanded": t.panelState.aiMenuOpen.value,
class: c(["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", t.panelState.aiButtonActive.value ? "tpl-ai-btn--active" : "tpl-ai-btn--idle"]),
onClick: d[1] ||= u((...e) => t.panelState.toggleAiMenu && t.panelState.toggleAiMenu(...e), ["stop"])
}, [E(C(de), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), s(" " + w(C(a).aiChat.button), 1)], 10, st), E(T, {
"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: O(() => [t.panelState.aiMenuOpen.value ? (e(), m("div", ct, [E(C(i), {
"active-feature": t.panelState.activeAiFeature.value,
onSelect: t.panelState.handleAiFeatureSelect
}, null, 8, ["active-feature", "onSelect"])])) : v("", !0)]),
_: 1
})], 512)) : v("", !0),
t.testEmail.isEnabled.value && t.featureFlags.canSendTestEmail.value ? (e(), m("button", {
key: 5,
class: c(C($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: t.testEmail.isSending.value || !t.featureFlags.hasTemplateSaved.value,
onClick: d[2] ||= (e) => t.panelState.testEmailModalOpen.value = !0
}, [t.testEmail.isSending.value ? (e(), x(C(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (e(), x(C(Z), {
key: 0,
size: 16,
"stroke-width": 2
})), s(" " + w(C(a).testEmail.button), 1)], 10, lt)) : v("", !0),
f("button", {
class: c(C($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: t.isSaveDisabled,
onClick: d[3] ||= (e) => l.$emit("save")
}, [t.isSaving ? (e(), x(C(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (e(), x(C(je), {
key: 0,
size: 16,
"stroke-width": 2
})), s(" " + w(t.isSaving ? C(a).header.saving : C(a).header.save), 1)], 10, ut)
])
]));
}
}), ft = /* @__PURE__ */ l({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {},
savedModulesHeadless: {},
showSaveModuleDialog: { type: Boolean },
saveModulePreSelectedBlockId: {},
showModuleBrowserModal: { type: Boolean }
},
emits: [
"update:showSaveModuleDialog",
"update:saveModulePreSelectedBlockId",
"update:showModuleBrowserModal",
"send-test-email",
"module-insert"
],
setup(t, { expose: n, emit: r }) {
let i = D(() => import("./AiChatSidebar-BUKj9n02.js")), a = D(() => import("./CommentsSidebar-DiH4R4F0.js")), s = D(() => import("./DesignReferenceSidebar-BP32MgpS.js")), c = D(() => import("./TemplateScoringPanel-seBvvn8O.js")), l = D(() => import("./TestEmailModal-BuCuWp3N.js")), u = D(() => import("./SaveModuleDialog-DWidA0c9.js")), d = D(() => import("./ModuleBrowserModal-CWegFoOA.js")), f = D(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.");
}
}), p = r;
function h(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
function g(e, t) {
p("module-insert", e, t);
}
let y = o(null);
function b(e) {
y.value?.filterByBlock(e);
}
return n({ filterCommentsByBlock: b }), (n, r) => (e(), m(_, null, [
E(C(i), {
visible: t.panelState.aiChatOpen.value,
"on-apply": (e) => h(e, t.core, t.editor),
onClose: r[0] ||= (e) => t.panelState.aiChatOpen.value = !1
}, null, 8, ["visible", "on-apply"]),
E(C(c), {
visible: t.panelState.scoringPanelOpen.value,
onClose: r[1] ||= (e) => t.panelState.scoringPanelOpen.value = !1
}, null, 8, ["visible"]),
E(C(s), {
visible: t.panelState.designReferenceOpen.value,
"has-existing-blocks": t.editor.content.value.blocks.length > 0,
onClose: r[2] ||= (e) => t.panelState.designReferenceOpen.value = !1,
onApply: r[3] ||= (e) => h(e, t.core, t.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
E(C(a), {
ref_key: "commentsSidebar",
ref: y,
visible: t.panelState.commentsOpen.value,
onClose: r[4] ||= (e) => t.panelState.commentsOpen.value = !1
}, null, 8, ["visible"]),
E(C(l), {
visible: t.panelState.testEmailModalOpen.value,
"allowed-emails": t.testEmail.allowedEmails.value,
"is-sending": t.testEmail.isSending.value,
error: t.testEmail.error.value,
onSend: r[5] ||= (e) => p("send-test-email", e),
onClose: r[6] ||= (e) => t.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
t.planConfigInstance.hasFeature("saved_modules") && t.config.modules !== !1 ? (e(), x(C(u), {
key: 0,
visible: t.showSaveModuleDialog,
"pre-selected-block-id": t.saveModulePreSelectedBlockId,
onClose: r[7] ||= (e) => {
p("update:showSaveModuleDialog", !1), p("update:saveModulePreSelectedBlockId", null);
},
onSaved: r[8] ||= (e) => t.savedModulesHeadless.loadModules()
}, null, 8, ["visible", "pre-selected-block-id"])) : v("", !0),
t.planConfigInstance.hasFeature("saved_modules") && t.config.modules !== !1 ? (e(), x(C(d), {
key: 1,
visible: t.showModuleBrowserModal,
onClose: r[9] ||= (e) => p("update:showModuleBrowserModal", !1),
onInsert: g
}, null, 8, ["visible"])) : v("", !0),
E(C(f), {
visible: t.panelState.mediaLibraryOpen.value,
accept: t.panelState.mediaLibraryAccept.value,
"popover-target": t.core.popoverRoot.value,
onSelect: t.mediaLib.handleMediaSelect,
onClose: t.mediaLib.handleMediaLibraryClose
}, null, 8, [
"visible",
"accept",
"popover-target",
"onSelect",
"onClose"
])
], 64));
}
}), pt = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, mt = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, ht = { 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)]" }, gt = /* @__PURE__ */ l({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(t) {
return (n, i) => t.visible ? (e(), m("div", pt, [i[1] ||= p("<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), f("div", mt, [f("div", ht, [(e(), m(_, null, r(5, (e) => f("div", {
key: e,
class: "tpl-shimmer tpl:size-7 tpl:rounded-[var(--tpl-radius-sm)]"
})), 64))]), i[0] ||= p("<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)])])) : v("", !0);
}
}), _t = {
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)]"
}, vt = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, yt = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, bt = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, xt = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, St = /* @__PURE__ */ l({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(t, { emit: n }) {
let r = n, { t: i } = Q();
function a(e) {
return "isUnauthorized" in e && e.isUnauthorized ? i.error.authFailed : "isNotFound" in e && e.isNotFound ? i.error.templateNotFound : i.error.defaultMessage;
}
function o(e) {
return "isNotFound" in e && !!e.isNotFound;
}
return (n, s) => t.visible && t.error ? (e(), m("div", _t, [
f("div", vt, [E(C(K), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
f("div", yt, [f("h2", bt, w(C(i).error.title), 1), f("p", xt, w(a(t.error)), 1)]),
o(t.error) ? v("", !0) : (e(), 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: s[0] ||= (e) => r("retry")
}, w(C(i).error.retry), 1))
])) : v("", !0);
}
}), Ct = {
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)]"
}, wt = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, Tt = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Et = /* @__PURE__ */ l({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(t, { emit: n }) {
let r = n, { t: i } = Q();
return (n, a) => t.visible ? (e(), m("div", Ct, [f("div", wt, [E(C(ue), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), f("span", null, w(C(i).snapshotPreview.message), 1)]), f("div", Tt, [f("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) => r("cancel")
}, w(C(i).snapshotPreview.cancel), 1), f("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) => r("confirm")
}, w(C(i).snapshotPreview.restore), 1)])])) : v("", !0);
}
}), Dt = {
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)"
}
}, Ot = /* @__PURE__ */ l({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(t) {
let { t: n } = U();
return (r, i) => t.visible ? (e(), m("div", Dt, w(C(n).history.collabWarning), 1)) : v("", !0);
}
}), kt = ["data-tpl-theme"], At = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, jt = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, Mt = ["aria-label"], Nt = /* @__PURE__ */ pe(/* @__PURE__ */ l({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(n, { expose: r, emit: a }) {
let l = n;
h(B, l.cloudTranslations);
let u = a, d = o(null), p = o(null), _ = Le({
config: l.config,
translations: l.translations,
fontsManager: l.fontsManager,
emit: u,
getCommentsSidebar: () => d.value ? { filterByBlock: d.value.filterCommentsByBlock } : null,
editorRoot: l.shadowRoot,
containerEl: p
}), { isInitializing: S, isAuthReady: D, initError: k, planConfigInstance: A, websocket: M, collaboration: N, isCollaborationEnabled: P, editor: F, core: I, featureFlags: L, mediaLib: R, exporter: z, testEmail: V, commentsInstance: ee, savedModulesHeadless: te, panelState: H, snapshotPreview: U, collabWarning: W, showSaveModuleDialog: G, showModuleBrowserModal: K, saveModulePreSelectedBlockId: q, setThemeOverrides: J, setUiTheme: re } = _;
async function oe(e) {
try {
await V.sendTestEmail(e), H.testEmailModalOpen.value = !1;
} catch {}
}
function ue(e, t) {
for (let n = 0; n < e.content.length; n++) {
let r = j(e.content[n]), i = t === void 0 ? void 0 : t + n;
F.addBlock(r, void 0, void 0, i);
}
K.value = !1;
}
let Y = ze({
config: l.config,
editor: F,
websocket: M,
planConfigInstance: A,
snapshotPreview: U,
core: I,
exporter: z,
featureFlags: L,
isDestroyed: _.isDestroyed
}), X = Be({
issues: I.templateLint ? I.templateLint.issues : o([]),
planConfig: A.config
});
async function Z() {
await X.tryRunSave(() => Y.saveTemplate().catch((e) => l.config.onError?.(e)));
}
return _.onSaveHook.value = Z, i(() => {
_.initialize();
}), g(() => {
_.destroy();
}), r({
getContent: () => F.content.value,
setContent: (e) => F.setContent(e),
setTheme: re,
setThemeOverrides: J,
create: Y.createTemplate,
load: Y.loadTemplate,
save: Y.saveTemplate,
sendTestEmail: V.sendTestEmail
}), (r, i) => (e(), m("div", {
ref_key: "rootEl",
ref: p,
class: c(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": C(F).state.darkMode }]),
"data-tpl-theme": C(I).resolvedTheme.value,
style: b(C(I).themeStyles.value)
}, [
E(T, {
"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: O(() => [E(gt, { visible: C(S) || C(F).state.isLoading }, null, 8, ["visible"])]),
_: 1
}),
E(T, {
"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: O(() => [E(St, {
error: C(k),
visible: !!C(k) && !C(S),
onRetry: C(_).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
E(dt, {
editor: C(F),
core: C(I),
"feature-flags": C(L),
"panel-state": C(H),
"snapshot-preview": C(U),
"comments-instance": C(ee),
"test-email": C(V),
websocket: C(M),
collaboration: C(N),
"is-collaboration-enabled": C(P),
"is-saving": C(F).state.isSaving || C(L).isSaveExporting.value,
"is-save-disabled": C(F).state.isSaving || C(L).isSaveExporting.value || !C(F).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"
]),
E(Xe, {
open: C(X).modalOpen.value,
issues: C(X).blockingIssues.value,
onCancel: C(X).cancel,
onConfirm: C(X).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
E(Et, {
visible: C(U).isPreviewingSnapshot.value,
onCancel: C(U).cancelPreview,
onConfirm: C(U).confirmRestoreSnapshot
}, null, 8, [
"visible",
"onCancel",
"onConfirm"
]),
E(T, {
"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: O(() => [E(Ot, { visible: C(W).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
t(E(se, null, null, 512), [[y, !C(F).state.previewMode]]),
f("div", {
class: c(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [C(F).state.previewMode ? "tpl:left-0 tpl:right-0" : C(H).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", C(U).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)"
}
}, [f("div", At, [E(T, { name: "tpl-restore-btn" }, {
default: O(() => [C(I).conditionPreview.hasHiddenBlocks.value ? (e(), 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: i[0] ||= (e) => C(I).conditionPreview.reset()
}, [E(C(le), {
size: 13,
"stroke-width": 2
}), s(" " + w(C(I).t.blockSettings.restoreHiddenBlocks), 1)])) : v("", !0)]),
_: 1
})]), f("main", jt, [E(ne, {
viewport: C(F).state.viewport,
content: C(F).content.value,
"selected-block-id": C(F).state.selectedBlockId,
"dark-mode": C(F).state.darkMode,
"preview-mode": C(F).state.previewMode,
"locked-blocks": C(N)?.lockedBlocks.value ?? void 0,
onSelectBlock: C(F).selectBlock,
onOpenAiChat: i[1] ||= (e) => C(H).aiChatOpen.value = !0,
onOpenDesignReference: i[2] ||= (e) => C(H).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
n.config.branding !== !1 && !C(L).isWhiteLabeled.value ? (e(), x(ie, {
key: 0,
"position-class": [C(F).state.previewMode ? "tpl:left-0 tpl:right-0" : C(H).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]"]
}, null, 8, ["position-class"])) : v("", !0),
f("div", {
class: "tpl-sr-only",
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
"aria-label": C(I).t.landmarks.reorderAnnouncements
}, w(C(I).keyboardReorder.announcement.value), 9, Mt),
t(E(ae, {
"selected-block": C(F).selectedBlock.value,
settings: C(F).content.value.settings,
"shifted-left": C(H).rightPanelOpen.value,
onUpdateBlock: i[3] ||= (e) => C(F).updateBlock(C(F).selectedBlock.value.id, e),
onDeleteBlock: i[4] ||= (e) => C(I).blockActions.deleteBlock(C(F).selectedBlock.value.id),
onDuplicateBlock: i[5] ||= (e) => C(I).blockActions.duplicateBlock(C(F).selectedBlock.value),
onUpdateSettings: C(F).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[y, !C(F).state.previewMode]]),
!C(S) && C(D) ? (e(), x(ft, {
key: 1,
ref_key: "cloudPanelsRef",
ref: d,
config: l.config,
editor: C(F),
core: C(I),
"panel-state": C(H),
"plan-config-instance": C(A),
"test-email": C(V),
"media-lib": C(R),
"saved-modules-headless": C(te),
"show-save-module-dialog": C(G),
"save-module-pre-selected-block-id": C(q),
"show-module-browser-modal": C(K),
"onUpdate:showSaveModuleDialog": i[6] ||= (e) => G.value = e,
"onUpdate:saveModulePreSelectedBlockId": i[7] ||= (e) => q.value = e,
"onUpdate:showModuleBrowserModal": i[8] ||= (e) => K.value = e,
onSendTestEmail: oe,
onModuleInsert: ue
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib",
"saved-modules-headless",
"show-save-module-dialog",
"save-module-pre-selected-block-id",
"show-module-browser-modal"
])) : v("", !0),
f("div", {
ref: (e) => C(I).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
E(ce)
], 14, kt));
}
}), [["__scopeId", "data-v-3f0f5cfa"]]);
//#endregion
export { Nt as default };

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

+4
-4
{
"version": "0.9.0",
"initialGzipBytes": 157590,
"initialRawBytes": 551204,
"version": "0.9.1",
"initialGzipBytes": 157631,
"initialRawBytes": 551337,
"initialFileCount": 36,

@@ -9,3 +9,3 @@ "lazyGzipBytes": 265837,

"lazyFileCount": 46,
"generatedAt": "2026-05-26T19:29:12.906Z"
"generatedAt": "2026-05-27T08:11:21.639Z"
}
{
"name": "@templatical/editor",
"description": "Vue 3 visual drag-and-drop email editor powered by Templatical",
"version": "0.9.0",
"version": "0.9.1",
"bugs": "https://github.com/templatical/sdk/issues",

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

"vue-tsc": "^3.3.1",
"@templatical/core": "0.9.0",
"@templatical/quality": "0.9.0",
"@templatical/types": "0.9.0"
"@templatical/quality": "0.9.1",
"@templatical/core": "0.9.1",
"@templatical/types": "0.9.1"
},

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

"peerDependencies": {
"@templatical/media-library": "0.9.0",
"@templatical/quality": "0.9.0",
"@templatical/renderer": "0.9.0"
"@templatical/quality": "0.9.1",
"@templatical/media-library": "0.9.1",
"@templatical/renderer": "0.9.1"
},

@@ -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 ee } from "./draggable-BwWMFq33.js";
import { $t as O, A as k, At as A, Dt as j, E as M, En as N, Et as P, Ft as F, Ht as I, It as te, Nt as ne, Qt as L, Rt as re, S as R, Ut as z, Vt as B, Z as ie, Zt as V, _ as H, _t as U, b as W, c as G, d as K, f as q, g as J, h as Y, in as X, l as ae, m as oe, p as se, pn as Z, pt as ce, rt as le, s as ue, st as de, tt as Q, u as fe, ut as pe, v as me, vt as he, x as ge, xn as _e, y as ve, zn as ye } from "./features-D-2kVhHY.js";
import { C as be, S as xe } from "./icons-fZoyKV_s.js";
import { a as Se, c as Ce, i as we, l as Te, n as Ee, o as De, r as Oe, s as ke, t as Ae } from "./styles-o0HIrw9F.js";
import { d as $ } from "./styleConstants-lGobwiLH.js";
//#region src/cloud/composables/useSnapshotPreview.ts
function je(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 = q({
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;
} 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 Me() {
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 X(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 Ne(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = c(!1), a = c(!1), { start: o } = Z(() => {
a.value = !1;
}, ye, { 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 Pe(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 } = Z(() => {
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 Fe(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: i } = e, a = null;
async function o() {
if (t) {
let e = await t({ accept: ["images"] });
return e ? {
url: e.url,
alt: e.alt_text || void 0
} : null;
}
return a &&= (a(null), null), i.value = ["images"], n.value = !0, new Promise((e) => {
a = (t) => {
e(t);
};
});
}
function s(e) {
n.value = !1, a?.({
url: e.url,
alt: e.alt_text || void 0
}), a = null;
}
function c() {
n.value = !1, a?.(null), a = null;
}
return r(() => {
a &&= (a(null), null);
}), {
handleRequestMedia: o,
handleMediaSelect: s,
handleMediaLibraryClose: c
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function Ie(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 M({
...t.auth,
onError: t.onError
}), _ = ae({
authManager: g,
onError: t.onError
}), v = c(/* @__PURE__ */ new Map()), y = ge({
authManager: g,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: v
}), b = oe({
authManager: g,
onError: t.onError
});
t.mcp?.enabled && ue({
editor: y,
channel: b.channel,
onOperation: t.mcp.onOperation
});
let x = null;
t.collaboration?.enabled && (x = J({
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
}), ee(() => x.lockedBlocks.value, (e) => {
v.value = e;
}, { immediate: !0 }), Y(y, x));
let S = f(() => !!t.collaboration?.enabled && _.hasFeature("collaboration")), C = k({
editor: y,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
customBlocks: [],
mergeTags: t.mergeTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: Te(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 = Ne({
isCollaborationEnabled: S,
getCollaboratorCount: () => x?.collaborators.value.length ?? 0,
canUndo: C.history.canUndo
});
h = w;
let T = je({
authManager: g,
editor: y,
history: C.history,
conditionPreview: C.conditionPreview,
autoSave: C.autoSave,
onError: t.onError
});
m = T;
let E = Me(), D = W(t.ai), A = Pe({
planConfigInstance: _,
aiConfig: D,
editor: y
}), j = Fe({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: E.mediaLibraryOpen,
mediaLibraryAccept: E.mediaLibraryAccept
});
ie({
onBlockMove: y.moveBlock,
onBlockAdd: y.addBlock
});
let N = fe({
authManager: g,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => _.hasFeature("custom_fonts")
}), P = K({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null,
save: () => y.save(),
exportHtml: (e) => N.exportHtml(e),
onError: t.onError,
isAuthReady: l,
onBeforeTestEmail: t.onBeforeTestEmail
}), F = me({
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")
});
H({
comments: F,
channel: b.channel
});
let I = se({
authManager: g,
onError: t.onError
}), R = c(!1), U = c(null), q = c(!1), X = ve({
authManager: g,
getTemplateId: () => y.state.template?.id ?? null
});
function Z(e) {
E.commentsOpen.value = !0, queueMicrotask(() => {
o()?.filterByBlock(e);
});
}
a(V, j.handleRequestMedia), a(re, g), a(te, D), a(z, F), a(L, I), a(O, X), a(B, {
plan: _,
ai: D,
comments: {
getBlockCount: (e) => F.commentCountByBlock.value.get(e) ?? 0,
openForBlock: Z
},
savedModules: {
openSaveDialog: (e) => {
U.value = e ?? null, R.value = !0;
},
openBrowser: () => {
q.value = !0;
},
moduleCount: f(() => I.modules.value.length)
}
});
function ce(e) {
_.hasFeature("theme_customization") && (C.themeOverrides.value = e);
}
function le(e) {
y.setUiTheme(e);
}
async function de() {
s.value = !0, u.value = null;
try {
if (await g.initialize(), d) return;
l.value = !0;
let e = await G({ 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 || ne.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), t.modules !== !1 && _.hasFeature("saved_modules") && I.loadModules(), 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 Q() {
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: A,
mediaLib: j,
exporter: N,
testEmail: P,
commentsInstance: F,
savedModulesHeadless: I,
scoringInstance: X,
panelState: E,
snapshotPreview: T,
collabWarning: w,
showSaveModuleDialog: R,
showModuleBrowserModal: q,
saveModulePreSelectedBlockId: U,
onSaveHook: p,
initialize: de,
destroy: Q,
setThemeOverrides: ce,
setUiTheme: le,
openCommentsForBlock: Z
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Le(e, t) {
let n = async (e) => {
if (N(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 Re(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return R(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 Le(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 ze(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 Be = ["aria-label"], Ve = { 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)]" }, He = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Ue = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, We = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Ge = { 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" }, Ke = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, qe = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Je = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, Ye = /* @__PURE__ */ E({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
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", Ve, [
x("header", He, [D(h(de), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), x("h2", Ue, d(h(r).saveGate.title), 1)]),
x("p", We, d(h(r).saveGate.body), 1),
x("ul", Ge, [(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", Ke, d(e.message), 1), x("span", qe, d(e.ruleId), 1)]))), 128))]),
x("footer", Je, [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, Be)) : m("", !0)]),
_: 1
}));
}
}), Xe = {
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)"
}
}, Ze = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, Qe = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, $e = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, et = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, tt = ["data-tooltip"], nt = {
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)]"
}, rt = {
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)]"
}, it = ["aria-label", "aria-expanded"], at = {
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)]"
}, ot = ["aria-expanded"], st = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, ct = ["disabled"], lt = ["disabled"], ut = /* @__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-C4CFs5EJ.js")), n = u(() => import("./features-D-2kVhHY.js").then((e) => e.r)), r = u(() => import("./AiFeatureMenu-Dayzk2H7.js")), { t: a, format: o } = Q();
return (c, l) => (i(), p("header", Xe, [
x("div", Ze, [e.featureFlags.templateLimit.value === null ? m("", !0) : (i(), p("span", Qe, d(h(o)(h(a).header.templatesUsed, {
used: e.featureFlags.templateCount.value,
max: e.featureFlags.templateLimit.value
})), 1))]),
x("div", $e, [
D(Se, {
viewport: e.editor.state.viewport,
onChange: e.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
D(Oe, {
"dark-mode": e.editor.state.darkMode,
onChange: e.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
D(we, {
"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", et, [
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(j), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saveFailed), 1)], 8, tt)) : e.featureFlags.saveStatus.value === "saved" ? (i(), p("div", nt, [D(h(A), {
size: 12,
"stroke-width": 2.5
}), T(" " + d(h(a).header.saved), 1)])) : e.editor.state.isDirty ? (i(), p("div", rt, [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(U), {
size: 16,
"stroke-width": 2
}),
T(" " + d(h(a).comments.button) + " ", 1),
e.commentsInstance.unresolvedCount.value > 0 && !e.panelState.commentsOpen.value ? (i(), p("span", at, d(e.commentsInstance.unresolvedCount.value), 1)) : m("", !0)
], 14, it)) : 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(pe), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), T(" " + d(h(a).aiChat.button), 1)], 10, ot), 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", st, [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(he), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(ce), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(h(a).testEmail.button), 1)], 10, ct)) : 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(he), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (i(), v(h(xe), {
key: 0,
size: 16,
"stroke-width": 2
})), T(" " + d(e.isSaving ? h(a).header.saving : h(a).header.save), 1)], 10, lt)
])
]));
}
}), dt = /* @__PURE__ */ E({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {},
savedModulesHeadless: {},
showSaveModuleDialog: { type: Boolean },
saveModulePreSelectedBlockId: {},
showModuleBrowserModal: { type: Boolean }
},
emits: [
"update:showSaveModuleDialog",
"update:saveModulePreSelectedBlockId",
"update:showModuleBrowserModal",
"send-test-email",
"module-insert"
],
setup(e, { expose: t, emit: n }) {
let r = u(() => import("./features-D-2kVhHY.js").then((e) => e.o)), a = u(() => import("./features-D-2kVhHY.js").then((e) => e.a)), o = u(() => import("./features-D-2kVhHY.js").then((e) => e.i)), s = u(() => import("./features-D-2kVhHY.js").then((e) => e.n)), l = u(() => import("./features-D-2kVhHY.js").then((e) => e.t)), d = u(() => import("./SaveModuleDialog-BrtDXzIz.js")), f = u(() => import("./ModuleBrowserModal-Cgjz4xAz.js")), g = u(async () => {
try {
return (await import("./src-ftxPuuQh.js")).MediaLibraryModal;
} catch {
throw Error("[Templatical] Cloud media library requires the optional peer dependency '@templatical/media-library'. Please install it.");
}
}), _ = n;
function y(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
function b(e, t) {
_("module-insert", e, t);
}
let x = c(null);
function S(e) {
x.value?.filterByBlock(e);
}
return t({ filterCommentsByBlock: S }), (t, n) => (i(), p(w, null, [
D(h(r), {
visible: e.panelState.aiChatOpen.value,
"on-apply": (t) => y(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) => y(t, e.core, e.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
D(h(a), {
ref_key: "commentsSidebar",
ref: x,
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) => _("send-test-email", e),
onClose: n[6] ||= (t) => e.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
e.planConfigInstance.hasFeature("saved_modules") && e.config.modules !== !1 ? (i(), v(h(d), {
key: 0,
visible: e.showSaveModuleDialog,
"pre-selected-block-id": e.saveModulePreSelectedBlockId,
onClose: n[7] ||= (e) => {
_("update:showSaveModuleDialog", !1), _("update:saveModulePreSelectedBlockId", null);
},
onSaved: n[8] ||= (t) => e.savedModulesHeadless.loadModules()
}, null, 8, ["visible", "pre-selected-block-id"])) : m("", !0),
e.planConfigInstance.hasFeature("saved_modules") && e.config.modules !== !1 ? (i(), v(h(f), {
key: 1,
visible: e.showModuleBrowserModal,
onClose: n[9] ||= (e) => _("update:showModuleBrowserModal", !1),
onInsert: b
}, null, 8, ["visible"])) : m("", !0),
D(h(g), {
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));
}
}), ft = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, pt = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, mt = { 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)]" }, ht = /* @__PURE__ */ E({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(e) {
return (t, n) => e.visible ? (i(), p("div", ft, [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", pt, [x("div", mt, [(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);
}
}), gt = {
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)]"
}, _t = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, vt = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, yt = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, bt = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, xt = /* @__PURE__ */ E({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
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", gt, [
x("div", _t, [D(h(j), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
x("div", vt, [x("h2", yt, d(h(r).error.title), 1), x("p", bt, 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);
}
}), St = {
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)]"
}, Ct = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, wt = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Tt = /* @__PURE__ */ E({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(e, { emit: t }) {
let n = t, { t: r } = Q();
return (t, a) => e.visible ? (i(), p("div", St, [x("div", Ct, [D(h(P), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), x("span", null, d(h(r).snapshotPreview.message), 1)]), x("div", wt, [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);
}
}), Et = {
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)"
}
}, Dt = /* @__PURE__ */ E({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(e) {
let { t } = F();
return (n, r) => e.visible ? (i(), p("div", Et, d(h(t).history.collabWarning), 1)) : m("", !0);
}
}), Ot = ["data-tpl-theme"], kt = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, At = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, jt = ["aria-label"], Mt = /* @__PURE__ */ le(/* @__PURE__ */ E({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(e, { expose: r, emit: o }) {
let l = e;
a(I, l.cloudTranslations);
let u = o, f = c(null), _ = c(null), w = Ie({
config: l.config,
translations: l.translations,
fontsManager: l.fontsManager,
emit: u,
getCommentsSidebar: () => f.value ? { filterByBlock: f.value.filterCommentsByBlock } : null,
editorRoot: l.shadowRoot,
containerEl: _
}), { isInitializing: E, isAuthReady: ee, initError: O, planConfigInstance: k, websocket: A, collaboration: j, isCollaborationEnabled: M, editor: N, core: P, featureFlags: F, mediaLib: te, exporter: ne, testEmail: L, commentsInstance: re, savedModulesHeadless: R, panelState: z, snapshotPreview: B, collabWarning: ie, showSaveModuleDialog: V, showModuleBrowserModal: H, saveModulePreSelectedBlockId: U, setThemeOverrides: W, setUiTheme: G } = w;
async function K(e) {
try {
await L.sendTestEmail(e), z.testEmailModalOpen.value = !1;
} catch {}
}
function q(e, t) {
for (let n = 0; n < e.content.length; n++) {
let r = _e(e.content[n]), i = t === void 0 ? void 0 : t + n;
N.addBlock(r, void 0, void 0, i);
}
H.value = !1;
}
let J = Re({
config: l.config,
editor: N,
websocket: A,
planConfigInstance: k,
snapshotPreview: B,
core: P,
exporter: ne,
featureFlags: F,
isDestroyed: w.isDestroyed
}), Y = ze({
issues: P.templateLint ? P.templateLint.issues : c([]),
planConfig: k.config
});
async function X() {
await Y.tryRunSave(() => J.saveTemplate().catch((e) => l.config.onError?.(e)));
}
return w.onSaveHook.value = X, t(() => {
w.initialize();
}), g(() => {
w.destroy();
}), r({
getContent: () => N.content.value,
setContent: (e) => N.setContent(e),
setTheme: G,
setThemeOverrides: W,
create: J.createTemplate,
load: J.loadTemplate,
save: J.saveTemplate,
sendTestEmail: L.sendTestEmail
}), (t, r) => (i(), p("div", {
ref_key: "rootEl",
ref: _,
class: b(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": h(N).state.darkMode }]),
"data-tpl-theme": h(P).resolvedTheme.value,
style: C(h(P).themeStyles.value)
}, [
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(ht, { visible: h(E) || h(N).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(xt, {
error: h(O),
visible: !!h(O) && !h(E),
onRetry: h(w).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
D(ut, {
editor: h(N),
core: h(P),
"feature-flags": h(F),
"panel-state": h(z),
"snapshot-preview": h(B),
"comments-instance": h(re),
"test-email": h(L),
websocket: h(A),
collaboration: h(j),
"is-collaboration-enabled": h(M),
"is-saving": h(N).state.isSaving || h(F).isSaveExporting.value,
"is-save-disabled": h(N).state.isSaving || h(F).isSaveExporting.value || !h(N).state.isDirty,
onSave: X
}, 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(Ye, {
open: h(Y).modalOpen.value,
issues: h(Y).blockingIssues.value,
onCancel: h(Y).cancel,
onConfirm: h(Y).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
D(Tt, {
visible: h(B).isPreviewingSnapshot.value,
onCancel: h(B).cancelPreview,
onConfirm: h(B).confirmRestoreSnapshot
}, null, 8, [
"visible",
"onCancel",
"onConfirm"
]),
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(Dt, { visible: h(ie).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
n(D(ke, null, null, 512), [[S, !h(N).state.previewMode]]),
x("div", {
class: b(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [h(N).state.previewMode ? "tpl:left-0 tpl:right-0" : h(z).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", h(B).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", kt, [D(y, { name: "tpl-restore-btn" }, {
default: s(() => [h(P).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(P).conditionPreview.reset()
}, [D(h(be), {
size: 13,
"stroke-width": 2
}), T(" " + d(h(P).t.blockSettings.restoreHiddenBlocks), 1)])) : m("", !0)]),
_: 1
})]), x("main", At, [D(Ce, {
viewport: h(N).state.viewport,
content: h(N).content.value,
"selected-block-id": h(N).state.selectedBlockId,
"dark-mode": h(N).state.darkMode,
"preview-mode": h(N).state.previewMode,
"locked-blocks": h(j)?.lockedBlocks.value ?? void 0,
onSelectBlock: h(N).selectBlock,
onOpenAiChat: r[1] ||= (e) => h(z).aiChatOpen.value = !0,
onOpenDesignReference: r[2] ||= (e) => h(z).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
e.config.branding !== !1 && !h(F).isWhiteLabeled.value ? (i(), v(Ee, {
key: 0,
"position-class": [h(N).state.previewMode ? "tpl:left-0 tpl:right-0" : h(z).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(P).t.landmarks.reorderAnnouncements
}, d(h(P).keyboardReorder.announcement.value), 9, jt),
n(D(De, {
"selected-block": h(N).selectedBlock.value,
settings: h(N).content.value.settings,
"shifted-left": h(z).rightPanelOpen.value,
onUpdateBlock: r[3] ||= (e) => h(N).updateBlock(h(N).selectedBlock.value.id, e),
onDeleteBlock: r[4] ||= (e) => h(P).blockActions.deleteBlock(h(N).selectedBlock.value.id),
onDuplicateBlock: r[5] ||= (e) => h(P).blockActions.duplicateBlock(h(N).selectedBlock.value),
onUpdateSettings: h(N).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[S, !h(N).state.previewMode]]),
!h(E) && h(ee) ? (i(), v(dt, {
key: 1,
ref_key: "cloudPanelsRef",
ref: f,
config: l.config,
editor: h(N),
core: h(P),
"panel-state": h(z),
"plan-config-instance": h(k),
"test-email": h(L),
"media-lib": h(te),
"saved-modules-headless": h(R),
"show-save-module-dialog": h(V),
"save-module-pre-selected-block-id": h(U),
"show-module-browser-modal": h(H),
"onUpdate:showSaveModuleDialog": r[6] ||= (e) => V.value = e,
"onUpdate:saveModulePreSelectedBlockId": r[7] ||= (e) => U.value = e,
"onUpdate:showModuleBrowserModal": r[8] ||= (e) => H.value = e,
onSendTestEmail: K,
onModuleInsert: q
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib",
"saved-modules-headless",
"show-save-module-dialog",
"save-module-pre-selected-block-id",
"show-module-browser-modal"
])) : m("", !0),
x("div", {
ref: (e) => h(P).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
D(Ae)
], 14, Ot));
}
}), [["__scopeId", "data-v-3f0f5cfa"]]);
//#endregion
export { Mt as default };
//# sourceMappingURL=CloudEditor-CyJItWsK.js.map

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

import { n as e } from "./rolldown-runtime-Dqa2HsxW.js";
import { An as t, Dn as n, En as r, Fn as i, In as a, Ln as o, Mn as s, Nn as c, On as l, Pn as u, Rn as d, Tn as f, jn as p, kn as m } from "./features-D-2kVhHY.js";
//#endregion
//#region ../renderer/src/render-context.ts
var h = `https://unpkg.com/@templatical/renderer@${{
name: "@templatical/renderer",
description: "Render Templatical email templates to MJML",
version: "0.9.0",
bugs: "https://github.com/templatical/sdk/issues",
dependencies: { "@templatical/types": "workspace:*" },
devDependencies: {
"@resvg/resvg-js": "^2.6.2",
mjml: "^5.2.2",
tsup: "^8.5.1",
typescript: "^6.0.3",
vitest: "^4.1.7"
},
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: "tsup && 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`, g = {
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"
}, _ = class e {
containerWidth;
customFonts;
defaultFallbackFont;
allowHtmlBlocks;
customBlockHtml;
socialIconsBaseUrl;
constructor(e, t, n, r, i = /* @__PURE__ */ new Map(), a = h) {
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 g[e.toLowerCase()] || e;
}
}, v = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
"\"": "&quot;",
"'": "&#039;"
}, y = /[&<>"']/g;
function b(e) {
return e === "" ? "" : e.replace(y, (e) => v[e] ?? e);
}
function x(e) {
return e === "" ? "" : e.replace(y, (e) => v[e] ?? e);
}
function S(e) {
return e === "" ? "" : x(e).replace(/[;{}\r\n]/g, "");
}
function C(e) {
return e === "" ? "" : ee(e, (e) => w(e, "data-merge-tag") ?? w(e, "data-logic-merge-tag"));
}
function ee(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.tablet && !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.tablet || n.push("tpl-hide-tablet"), t.mobile || n.push("tpl-hide-mobile"), n.join(" ");
}
//#endregion
//#region ../renderer/src/renderers/title.ts
function te(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = E(e.styles.backgroundColor, "container"), i = ne(C(e.content)), a = d[e.level] ?? d[2], o = x(e.color), s = e.textAlign, c = re(e.fontFamily, t), l = O(e), u = `h${d[e.level] ? e.level : 2}`;
return `<mj-text
font-size="${a}px"
color="${o}"
align="${s}"
line-height="1.3"
padding="${n}"${r}${c}${l}
><${u} style="margin:0;font-size:inherit;color:inherit;line-height:inherit">${i}</${u}></mj-text>`;
}
function ne(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 re(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/paragraph.ts
function A(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 = C(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 j(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="${x(e.linkUrl)}"`, e.linkOpenInNewTab && (o += " target=\"_blank\" rel=\"noopener\""));
let s = x(e.src), c = e.decorative === !0;
return `<mj-image
src="${s}"
alt="${c ? "" : x(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 === "" ? "" : x(e.url), o = a === "" ? "" : ` href="${a}"`, s = x(e.backgroundColor), c = x(e.textColor), l = e.fontSize, u = e.borderRadius, d = b(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)}${O(e)}
>${d}</mj-button>`;
}
function N(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/divider.ts
function P(e, t) {
if (D(e)) return "";
let n = T(e.styles.padding), r = e.styles.backgroundColor ? ` container-background-color="${x(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="${x(e.color)}"
width="${i}"
padding="${n}"${r}${O(e)}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/spacer.ts
function F(e, t) {
return D(e) ? "" : `<mj-spacer height="${e.height}px" padding="0"${e.styles.backgroundColor ? ` container-background-color="${x(e.styles.backgroundColor)}"` : ""}${O(e)} />`;
}
//#endregion
//#region ../renderer/src/renderers/html.ts
function I(e, t) {
if (D(e) || !t.allowHtmlBlocks) return "";
let n = e.content;
return n === "" ? "" : `<mj-text${O(e)}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/renderers/social.ts
function L(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="${x(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 = x(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 R(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 = V(e.fontFamily, t), o = e.textAlign;
return `<mj-text
font-size="${e.fontSize}px"
color="${x(e.color)}"
align="${o}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${z(e)}</mj-text>`;
}
function z(e) {
let t = e.items, n = b(e.separator), r = S(e.separatorColor), i = e.spacing, a = e.linkColor ?? e.color, o = [], s = t.length;
for (let e = 0; e < s; e++) o.push(B(t[e], a)), e < s - 1 && o.push(`<span style="color: ${r}; padding: 0 ${i}px;">${n}</span>`);
return o.join("");
}
function B(e, t) {
let n = b(e.text), r = x(e.url), i = S(e.color ?? t), a = e.openInNewTab ? " target=\"_blank\" rel=\"noopener\"" : "", o = [`color: ${i}`, "text-decoration: none"];
return e.bold && o.push("font-weight: bold"), e.underline && o.push("text-decoration: underline"), `<a href="${r}" style="${o.join("; ")}"${a}>${n}</a>`;
}
function V(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/table.ts
function H(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 = ie(e.fontFamily, t);
return `<mj-text
font-size="${e.fontSize}px"
color="${x(e.color)}"
align="${e.textAlign}"
line-height="1.5"
padding="${n}"${r}${a}${i}
>${U(e)}</mj-text>`;
}
function U(e) {
let t = S(e.borderColor), n = e.borderWidth, r = "";
for (let i = 0; i < e.rows.length; i++) {
let a = e.rows[i];
r += W(a, e, e.hasHeaderRow && i === 0, t, n);
}
return `<table style="width: 100%; border-collapse: collapse;">${r}</table>`;
}
function W(e, t, n, r, i) {
let a = "";
for (let o of e.cells) a += G(o, t, n, r, i);
return `<tr>${a}</tr>`;
}
function G(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: ${S(t.headerBackgroundColor)}`));
let s = o.join("; "), c = C(e.content), l = n ? "th" : "td";
return `<${l} style="${s}">${c}</${l}>`;
}
function ie(e, t) {
return e ? ` font-family="${t.resolveFontFamily(e)}"` : "";
}
//#endregion
//#region ../renderer/src/renderers/custom.ts
function K(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${E(e.styles?.backgroundColor, "container")}${r}>
${n}
</mj-text>`;
}
//#endregion
//#region ../renderer/src/columns.ts
function q(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 J(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/renderers/section.ts
function Y(e, t, n) {
if (D(e)) return "";
let r = e.columns, i = q(r), a = J(r, t.containerWidth), o = T(e.styles.padding), c = E(e.styles.backgroundColor, "native"), l = O(e), u = e.children, d = [];
for (let e = 0; e < u.length; e++) {
let r = u[e], o = i[e] ?? "100%", c = Math.floor(a[e] ?? t.containerWidth), l = ae(r, t.allowHtmlBlocks).filter((e) => !s(e)), f = t.withContainerWidth(c), p = l.map((e) => n(e, f)).filter((e) => e !== "").join("\n");
d.push(`<mj-column width="${o}">
${p === "" ? "<mj-text>&nbsp;</mj-text>" : p}
</mj-column>`);
}
return `<mj-section${c} padding="${o}"${l}>
${d.join("\n")}
</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="${x(n)}"
alt="${x(e.alt)}"
width="${a}"
align="${e.align}"
padding="${r}"
href="${x(e.url)}"
target="_blank"
rel="noopener"${i}${o}
/>`;
}
//#endregion
//#region ../renderer/src/renderers/index.ts
function X(e, d) {
return s(e) ? Y(e, d, X) : a(e) ? te(e, d) : p(e) ? A(e, d) : m(e) ? j(e, d) : f(e) ? M(e, d) : n(e) ? P(e, d) : u(e) ? F(e, d) : l(e) ? I(e, d) : c(e) ? L(e, d) : t(e) ? R(e, d) : i(e) ? H(e, d) : o(e) ? se(e, d) : r(e) ? K(e, d) : "";
}
//#endregion
//#region ../renderer/src/index.ts
var ce = /* @__PURE__ */ e({
DEFAULT_SOCIAL_ICONS_BASE_URL: () => h,
RenderContext: () => _,
convertMergeTagsToValues: () => C,
escapeAttr: () => x,
escapeHtml: () => b,
getCssClassAttr: () => O,
getCssClasses: () => k,
getWidthPercentages: () => q,
getWidthPixels: () => J,
isHiddenOnAll: () => D,
renderBlock: () => X,
renderToMjml: () => Z,
toPaddingString: () => T
});
async function Z(e, t) {
let n = t?.customFonts ?? [], r = t?.defaultFallbackFont ?? "Arial, sans-serif", i = t?.allowHtmlBlocks ?? !0, a = de(t?.socialIconsBaseUrl ?? h), o = await he(e, t?.renderCustomBlock), s = new _(e.settings.width, n, r, i, o, a), c = me(e.blocks, i), l = s.resolveFontFamily(e.settings.fontFamily), u = e.settings.backgroundColor, d = c.map((e) => le(e, s)).filter((e) => e !== "").join("\n"), f = pe(n), p = fe(e.settings.preheaderText);
return `<mjml lang="${x(e.settings.locale)}">
<mj-head>${p}
<mj-attributes>
<mj-all font-family="${l}" />
<mj-text font-size="14px" />
<mj-section padding="0" />
<mj-column padding="0" />
<mj-image fluid-on-mobile="true" />
</mj-attributes>${f}
<mj-style>
a { color: inherit; text-decoration: none; }
@media only screen and (max-width: 480px) {
.tpl-hide-mobile { display: none !important; mso-hide: all !important; }
}
@media only screen and (min-width: 481px) and (max-width: 768px) {
.tpl-hide-tablet { display: none !important; mso-hide: all !important; }
}
@media only screen and (min-width: 769px) {
.tpl-hide-desktop { display: none !important; mso-hide: all !important; }
}
</mj-style>
</mj-head>
<mj-body width="${s.containerWidth}px" background-color="${u}">
${d}
</mj-body>
</mjml>`;
}
function le(e, t) {
return s(e) ? Q(e, X(e, t)) : Q(e, ue(X(e, t)));
}
function Q(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;
}
function ue(e) {
return e === "" ? "" : `<mj-section>
<mj-column>
${e}
</mj-column>
</mj-section>`;
}
function de(e) {
return e.endsWith("/") ? e.slice(0, -1) : e;
}
function fe(e) {
if (!e) return "";
let t = e.trim();
return t === "" ? "" : `\n <mj-preview>${b(t)}</mj-preview>`;
}
function pe(e) {
return e.length === 0 ? "" : e.map((e) => `\n <mj-font name="${x(e.name)}" href="${x(e.url)}" />`).join("");
}
function me(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, t) {
for (let n of e) {
if (r(n)) {
t.push(n);
continue;
}
if (s(n)) for (let e of n.children) $(e, t);
}
}
//#endregion
export { ce as t };
//# sourceMappingURL=renderer-7z2t_bYQ.js.map

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

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

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

import { A as e, B as t, L as n, M as r, O as i, Q as a, X as o, _ as s, at as c, b as l, c as u, d, f, g as p, h as m, j as h, k as g, l as _, m as v, o as y, ot as b, p as x, q as S, rt as C, st as w, t as T, v as E, y as D, z as O } from "./vue.runtime.esm-bundler-BDSGA5hA.js";
import { t as k } from "./timeouts-Bmi_yePw.js";
import { E as A, i as j } from "./dist-CIV3Brg-.js";
import { P as M, S as N, t as P } from "./useEditorCore-CEkf_VWX.js";
import { c as F, t as I } from "./dist-CNLAS2v2.js";
import { E as L, S as R, T as z, c as B, l as V, r as ee, s as te, t as H } from "./keys-BiQlvx51.js";
import { t as U } from "./useI18n-Besvmtxy.js";
import { t as W } from "./createLucideIcon-XgXOJ05E.js";
import { t as G } from "./check-ChQyfxJ3.js";
import { t as K } from "./circle-alert-CPH6l3Lc.js";
import { a as q, c as ne, i as J, l as re, n as ie, o as ae, r as oe, s as se, t as ce, u as le } from "./styles-CJtcKmsx.js";
import { t as ue } from "./clock-DHl_BIkU.js";
import { t as Y } from "./loader-circle-Rz_4vJLH.js";
import { t as X } from "./message-circle-D-umK_MU.js";
import { t as Z } from "./send-BhbhbIFT.js";
import { t as de } from "./sparkles-CrUN0KWY.js";
import { t as fe } from "./triangle-alert-MwJBKR2e.js";
import { t as pe } from "./_plugin-vue_export-helper-B3ysoDQm.js";
import { n as Q } from "./useCloudI18n-DKWJg6rJ.js";
import { d as $ } from "./styleConstants-lGobwiLH.js";
import { _ as me, a as he, c as ge, d as _e, f as ve, g as ye, h as be, l as xe, m as Se, n as Ce, o as we, p as Te, r as Ee, s as De, t as Oe, v as ke, y as Ae } from "./cloud-VxYMtfXC.js";
var je = 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 Me(e) {
let { authManager: t, editor: n, history: r, conditionPreview: i, autoSave: s, onError: c } = e, l = a(null), u = o(null), f = o(null), p = !1;
S(() => {
p = !0;
});
let m = d(() => u.value !== null), h = d(() => l.value?.snapshots.value ?? []), g = d(() => l.value?.isLoading.value ?? !1), _ = d(() => l.value?.isRestoring.value ?? !1);
function v() {
n.state.template?.id && !l.value && (l.value = ye({
authManager: t,
templateId: n.state.template.id,
onRestore: y,
onError: c
}), l.value.loadSnapshots());
}
function y(e) {
n.setContent(e.content, !1), r.clear(), i.reset();
}
async function b(e) {
if (!p) {
if (u.value) {
u.value = e, n.setContent(e.content, !1);
return;
}
n.state.isDirty && n.hasTemplate() && (await n.createSnapshot(), p) || (f.value = structuredClone(n.content.value), s?.pause(), u.value = e, n.setContent(e.content, !1));
}
}
async function x() {
if (!(!u.value || !l.value)) try {
if (await l.value.restoreSnapshot(u.value.id), p || (await l.value.loadSnapshots(), p)) return;
} finally {
p || (u.value = null, f.value = null, s?.resume());
}
}
function C() {
!u.value || !f.value || (n.setContent(f.value, !1), u.value = null, f.value = null, s?.resume());
}
async function w() {
p || l.value && await l.value.loadSnapshots();
}
return {
snapshotHistoryInstance: l,
previewingSnapshot: u,
contentBeforePreview: f,
isPreviewingSnapshot: m,
snapshotHistorySnapshots: h,
snapshotHistoryIsLoading: g,
snapshotHistoryIsRestoring: _,
initSnapshotHistory: v,
handleRestore: y,
handleSnapshotNavigate: b,
confirmRestoreSnapshot: x,
cancelPreview: C,
loadSnapshotHistory: w
};
}
//#endregion
//#region src/cloud/composables/useCloudPanelState.ts
function Ne() {
let e = o(null), t = d({
get: () => e.value === "ai-chat",
set: (t) => e.value = t ? "ai-chat" : null
}), n = d({
get: () => e.value === "scoring",
set: (t) => e.value = t ? "scoring" : null
}), r = d({
get: () => e.value === "design-reference",
set: (t) => e.value = t ? "design-reference" : null
}), i = d({
get: () => e.value === "comments",
set: (t) => e.value = t ? "comments" : null
}), a = o(!1), s = o(!1), c = o(void 0), l = o(!1), u = o(null), f = d(() => e.value !== null), p = d(() => {
let t = e.value;
return t === "ai-chat" || t === "design-reference" || t === "scoring" ? t : null;
}), m = d(() => 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: s,
mediaLibraryAccept: c,
aiMenuOpen: l,
aiMenuRef: u,
rightPanelOpen: f,
activeAiFeature: p,
aiButtonActive: m,
toggleAiMenu: h,
handleAiFeatureSelect: g
};
}
//#endregion
//#region src/cloud/composables/useCollabUndoWarning.ts
function Pe(e) {
let { isCollaborationEnabled: t, getCollaboratorCount: n, canUndo: r } = e, i = o(!1), a = o(!1), { start: s } = F(() => {
a.value = !1;
}, k, { immediate: !1 });
function c() {
i.value || !t.value || n() === 0 || !r.value || (i.value = !0, a.value = !0, s());
}
return {
collabUndoWarningVisible: a,
showCollabUndoWarning: c
};
}
//#endregion
//#region src/cloud/composables/useCloudFeatureFlags.ts
function Fe(e) {
let { planConfigInstance: t, aiConfig: n, editor: r } = e, i = d(() => t.hasFeature("ai_generation") && n.hasAnyMenuFeature.value), a = d(() => t.hasFeature("test_email")), s = d(() => !!r.state.template?.id), c = d(() => t.hasFeature("white_label")), l = d(() => t.config.value?.limits.max_templates ?? null), u = d(() => t.config.value?.template_count ?? 0), f = o(!1), p = o("idle"), m = o(""), { start: h } = F(() => {
p.value = "idle";
}, 3e3, { immediate: !1 });
return {
canUseAiGeneration: i,
canSendTestEmail: a,
hasTemplateSaved: s,
isWhiteLabeled: c,
templateLimit: l,
templateCount: u,
isSaveExporting: f,
saveStatus: p,
saveErrorMessage: m,
startSaveStatusClear: h
};
}
//#endregion
//#region src/cloud/composables/useCloudMediaLibrary.ts
function Ie(e) {
let { onRequestMedia: t, mediaLibraryOpen: n, mediaLibraryAccept: r } = e, i = null;
async function a() {
if (t) {
let e = await t({ accept: ["images"] });
return e ? {
url: e.url,
alt: e.alt_text || void 0
} : null;
}
return i &&= (i(null), null), r.value = ["images"], n.value = !0, new Promise((e) => {
i = (t) => {
e(t);
};
});
}
function o(e) {
n.value = !1, i?.({
url: e.url,
alt: e.alt_text || void 0
}), i = null;
}
function s() {
n.value = !1, i?.(null), i = null;
}
return S(() => {
i &&= (i(null), null);
}), {
handleRequestMedia: a,
handleMediaSelect: o,
handleMediaLibraryClose: s
};
}
//#endregion
//#region src/cloud/composables/useCloudInitialization.ts
function Le(e) {
let { config: t, translations: r, fontsManager: i, emit: a, getCommentsSidebar: s } = e, c = o(!0), l = o(!1), u = o(null), f = !1, p = { value: null }, m = null, g = null, _ = new Oe({
...t.auth,
onError: t.onError
}), v = Se({
authManager: _,
onError: t.onError
}), y = o(/* @__PURE__ */ new Map()), b = _e({
authManager: _,
defaultFontFamily: t.fonts?.defaultFont,
templateDefaults: t.templateDefaults,
onError: t.onError,
lockedBlocks: y
}), x = Ae({
authManager: _,
onError: t.onError
});
t.mcp?.enabled && Te({
editor: b,
channel: x.channel,
onOperation: t.mcp.onOperation
});
let S = null;
t.collaboration?.enabled && (S = we({
authManager: _,
editor: b,
channel: x.channel,
onError: t.onError,
onCollaboratorJoined: t.collaboration.onCollaboratorJoined,
onCollaboratorLeft: t.collaboration.onCollaboratorLeft,
onBlockLocked: t.collaboration.onBlockLocked,
onBlockUnlocked: t.collaboration.onBlockUnlocked
}), n(() => S.lockedBlocks.value, (e) => {
y.value = e;
}, { immediate: !0 }), De(b, S));
let C = d(() => !!t.collaboration?.enabled && v.hasFeature("collaboration")), w = P({
editor: b,
config: {
uiTheme: t.uiTheme,
theme: void 0,
blockDefaults: t.blockDefaults,
customBlocks: [],
mergeTags: t.mergeTags,
displayConditions: t.displayConditions,
onRequestMedia: null,
lint: re(t),
onSave: () => {
p.value?.().catch((e) => {
t.onError?.(e);
});
}
},
translations: r,
fontsManager: i,
historyOptions: S ? { isRemoteOperation: () => S._isProcessingRemoteOperation() } : void 0,
autoSaveOptions: {
onChange: async () => {
b.hasTemplate() && (await b.createSnapshot(), m?.snapshotHistoryInstance.value?.loadSnapshots());
},
debounce: t.autoSaveDebounce ?? 5e3,
enabled: () => t.autoSave !== !1 && v.hasFeature("auto_save")
},
themeExtraStyles: () => ({ "--tpl-drop-text": `"${r.canvas.dropHere}"` }),
keyboardOptions: { onBeforeUndo: () => g?.showCollabUndoWarning() },
editorRoot: e.editorRoot,
containerEl: e.containerEl
}), T = Pe({
isCollaborationEnabled: C,
getCollaboratorCount: () => S?.collaborators.value.length ?? 0,
canUndo: w.history.canUndo
});
g = T;
let E = Me({
authManager: _,
editor: b,
history: w.history,
conditionPreview: w.conditionPreview,
autoSave: w.autoSave,
onError: t.onError
});
m = E;
let D = Ne(), O = he(t.ai), k = Fe({
planConfigInstance: v,
aiConfig: O,
editor: b
}), A = Ie({
onRequestMedia: t.onRequestMedia,
mediaLibraryOpen: D.mediaLibraryOpen,
mediaLibraryAccept: D.mediaLibraryAccept
});
N({
onBlockMove: b.moveBlock,
onBlockAdd: b.addBlock
});
let j = ve({
authManager: _,
getFontsConfig: () => t.fonts,
canUseCustomFonts: () => v.hasFeature("custom_fonts")
}), F = ke({
authManager: _,
getTemplateId: () => b.state.template?.id ?? null,
save: () => b.save(),
exportHtml: (e) => j.exportHtml(e),
onError: t.onError,
isAuthReady: l,
onBeforeTestEmail: t.onBeforeTestEmail
}), I = xe({
authManager: _,
getTemplateId: () => b.state.template?.id ?? null,
getSocketId: () => x.getSocketId(),
onComment: t.onComment,
onError: t.onError,
isAuthReady: l,
hasCommentingFeature: () => t.commenting !== !1 && v.hasFeature("commenting")
});
ge({
comments: I,
channel: x.channel
});
let B = be({
authManager: _,
onError: t.onError
}), U = o(!1), W = o(null), G = o(!1), K = me({
authManager: _,
getTemplateId: () => b.state.template?.id ?? null
});
function q(e) {
D.commentsOpen.value = !0, queueMicrotask(() => {
s()?.filterByBlock(e);
});
}
h(R, A.handleRequestMedia), h(ee, _), h(H, O), h(V, I), h(z, B), h(L, K), h(te, {
plan: v,
ai: O,
comments: {
getBlockCount: (e) => I.commentCountByBlock.value.get(e) ?? 0,
openForBlock: q
},
savedModules: {
openSaveDialog: (e) => {
W.value = e ?? null, U.value = !0;
},
openBrowser: () => {
G.value = !0;
},
moduleCount: d(() => B.modules.value.length)
}
});
function ne(e) {
v.hasFeature("theme_customization") && (w.themeOverrides.value = e);
}
function J(e) {
b.setUiTheme(e);
}
async function ie() {
c.value = !0, u.value = null;
try {
if (await _.initialize(), f) return;
l.value = !0;
let e = await Ce({ authManager: _ });
if (f) 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 v.fetchConfig(), f) return;
i.setCustomFontsEnabled(v.hasFeature("custom_fonts")), t.customBlocks?.length && v.hasFeature("custom_blocks") && w.registerCustomBlocks(t.customBlocks), t.theme && v.hasFeature("theme_customization") && (w.themeOverrides.value = t.theme), t.modules !== !1 && v.hasFeature("saved_modules") && B.loadModules(), a("ready");
} catch (e) {
if (f) return;
let n = e instanceof Error ? e : Error("Initialization failed", { cause: e });
u.value = n, t.onError?.(n);
} finally {
f || (c.value = !1);
}
}
function ae() {
f = !0, i.cleanupFontLinks(), x.disconnect(), w.destroy(), t.onUnmount?.();
}
return {
isInitializing: c,
isAuthReady: l,
initError: u,
isDestroyed: () => f,
authManager: _,
planConfigInstance: v,
websocket: x,
collaboration: S,
isCollaborationEnabled: C,
editor: b,
core: w,
aiConfig: O,
featureFlags: k,
mediaLib: A,
exporter: j,
testEmail: F,
commentsInstance: I,
savedModulesHeadless: B,
scoringInstance: K,
panelState: D,
snapshotPreview: E,
collabWarning: T,
showSaveModuleDialog: U,
showModuleBrowserModal: G,
saveModulePreSelectedBlockId: W,
onSaveHook: p,
initialize: ie,
destroy: ae,
setThemeOverrides: ne,
setUiTheme: J,
openCommentsForBlock: q
};
}
//#endregion
//#region src/utils/preRenderCustomBlocks.ts
async function Re(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 ze(e) {
let { config: t, editor: n, websocket: r, planConfigInstance: i, snapshotPreview: a, core: o, exporter: s, featureFlags: c, isDestroyed: l } = e;
function u() {
return Ee(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 Re(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 Be(e) {
let t = o(!1), n = null, r = d(() => e.planConfig.value?.accessibility?.blockOnError === !0), i = d(() => r.value ? e.issues.value.filter((e) => e.severity === "error") : []), a = d(() => i.value.length > 0);
async function s(e) {
return a.value ? (n = e, t.value = !0, !1) : (await e(), !0);
}
async function c() {
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: s,
confirmAndSave: c,
cancel: l
};
}
//#endregion
//#region src/cloud/components/CloudSaveGateModal.vue?vue&type=script&setup=true&lang.ts
var Ve = ["aria-label"], He = { 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)]" }, Ue = { class: "tpl:flex tpl:items-center tpl:gap-2" }, We = { class: "tpl:m-0 tpl:text-base tpl:font-semibold tpl:text-[var(--tpl-text)]" }, Ge = { class: "tpl:m-0 tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Ke = { 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" }, qe = { class: "tpl:text-xs tpl:text-[var(--tpl-text)]" }, Je = { class: "tpl:font-mono tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]" }, Ye = { class: "tpl:flex tpl:justify-end tpl:gap-2" }, Xe = /* @__PURE__ */ l({
__name: "CloudSaveGateModal",
props: {
open: { type: Boolean },
issues: {}
},
emits: ["cancel", "confirm"],
setup(t, { emit: n }) {
let i = n, { t: a } = Q();
return (n, o) => (e(), x(T, {
"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: O(() => [t.open ? (e(), m("div", {
key: 0,
role: "dialog",
"aria-modal": "true",
"aria-label": C(a).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: o[2] ||= u((e) => i("cancel"), ["self"])
}, [f("div", He, [
f("header", Ue, [E(C(fe), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-warning)]"
}), f("h2", We, w(C(a).saveGate.title), 1)]),
f("p", Ge, w(C(a).saveGate.body), 1),
f("ul", Ke, [(e(!0), m(_, null, r(t.issues, (t) => (e(), m("li", {
key: `${t.ruleId}-${t.blockId ?? "template"}`,
class: "tpl:flex tpl:flex-col tpl:gap-0.5 tpl:rounded tpl:px-2 tpl:py-1.5"
}, [f("span", qe, w(t.message), 1), f("span", Je, w(t.ruleId), 1)]))), 128))]),
f("footer", Ye, [f("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: o[0] ||= (e) => i("cancel")
}, w(C(a).saveGate.cancel), 1), f("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: o[1] ||= (e) => i("confirm")
}, w(C(a).saveGate.confirm), 1)])
])], 8, Ve)) : v("", !0)]),
_: 1
}));
}
}), Ze = {
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)"
}
}, Qe = { class: "tpl-header-left tpl:flex tpl:min-w-[200px] tpl:items-center tpl:gap-3" }, $e = {
key: 0,
class: "tpl:text-xs tpl:opacity-60 tpl:text-[var(--tpl-text-muted)]"
}, et = { class: "tpl-header-center tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, tt = { class: "tpl-header-right tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, nt = ["data-tooltip"], rt = {
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)]"
}, it = {
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)]"
}, at = ["aria-label", "aria-expanded"], ot = {
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)]"
}, st = ["aria-expanded"], ct = {
key: 0,
class: "tpl:absolute tpl:right-0 tpl:top-full tpl:z-50 tpl:mt-1 tpl:origin-top-right"
}, lt = ["disabled"], ut = ["disabled"], dt = /* @__PURE__ */ l({
__name: "CloudHeader",
props: {
editor: {},
core: {},
featureFlags: {},
panelState: {},
snapshotPreview: {},
commentsInstance: {},
testEmail: {},
websocket: {},
collaboration: {},
isCollaborationEnabled: { type: Boolean },
isSaveDisabled: { type: Boolean },
isSaving: { type: Boolean }
},
emits: ["save"],
setup(t) {
let n = D(() => import("./CollaboratorBar-Bc6q0gB9.js")), r = D(() => import("./SnapshotHistory-CIo2Jaw-.js")), i = D(() => import("./AiFeatureMenu-Co14YVJt.js")), { t: a, format: o } = Q();
return (l, d) => (e(), m("header", Ze, [
f("div", Qe, [t.featureFlags.templateLimit.value === null ? v("", !0) : (e(), m("span", $e, w(C(o)(C(a).header.templatesUsed, {
used: t.featureFlags.templateCount.value,
max: t.featureFlags.templateLimit.value
})), 1))]),
f("div", et, [
E(q, {
viewport: t.editor.state.viewport,
onChange: t.editor.setViewport
}, null, 8, ["viewport", "onChange"]),
E(oe, {
"dark-mode": t.editor.state.darkMode,
onChange: t.editor.setDarkMode
}, null, 8, ["dark-mode", "onChange"]),
E(J, {
"preview-mode": t.editor.state.previewMode,
onChange: t.editor.setPreviewMode
}, null, 8, ["preview-mode", "onChange"]),
t.collaboration && t.isCollaborationEnabled ? (e(), x(C(n), {
key: 0,
collaborators: t.collaboration.collaborators.value,
"is-connected": t.websocket.isConnected.value
}, null, 8, ["collaborators", "is-connected"])) : v("", !0),
t.snapshotPreview.snapshotHistoryInstance.value ? (e(), x(C(r), {
key: 1,
snapshots: t.snapshotPreview.snapshotHistorySnapshots.value,
"is-loading": t.snapshotPreview.snapshotHistoryIsLoading.value,
"is-restoring": t.snapshotPreview.snapshotHistoryIsRestoring.value,
onLoad: t.snapshotPreview.loadSnapshotHistory,
onNavigate: t.snapshotPreview.handleSnapshotNavigate
}, null, 8, [
"snapshots",
"is-loading",
"is-restoring",
"onLoad",
"onNavigate"
])) : v("", !0)
]),
f("div", tt, [
t.featureFlags.saveStatus.value === "error" ? (e(), 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": t.featureFlags.saveErrorMessage.value
}, [E(C(K), {
size: 12,
"stroke-width": 2.5
}), s(" " + w(C(a).header.saveFailed), 1)], 8, nt)) : t.featureFlags.saveStatus.value === "saved" ? (e(), m("div", rt, [E(C(G), {
size: 12,
"stroke-width": 2.5
}), s(" " + w(C(a).header.saved), 1)])) : t.editor.state.isDirty ? (e(), m("div", it, [d[4] ||= f("span", { class: "tpl-pulse tpl:size-1.5 tpl:rounded-full tpl:bg-[var(--tpl-primary)]" }, null, -1), s(" " + w(C(a).header.unsaved), 1)])) : v("", !0),
t.commentsInstance.isEnabled.value && t.featureFlags.hasTemplateSaved.value ? (e(), m("button", {
key: 3,
"aria-label": t.commentsInstance.unresolvedCount.value > 0 ? `${C(a).comments.button} (${t.commentsInstance.unresolvedCount.value})` : C(a).comments.button,
"aria-expanded": t.panelState.commentsOpen.value,
class: c(C($)),
style: b({
backgroundColor: t.panelState.commentsOpen.value ? "var(--tpl-primary)" : "transparent",
color: t.panelState.commentsOpen.value ? "var(--tpl-bg)" : "var(--tpl-primary)",
borderColor: "var(--tpl-primary)"
}),
onClick: d[0] ||= (e) => t.panelState.commentsOpen.value = !t.panelState.commentsOpen.value
}, [
E(C(X), {
size: 16,
"stroke-width": 2
}),
s(" " + w(C(a).comments.button) + " ", 1),
t.commentsInstance.unresolvedCount.value > 0 && !t.panelState.commentsOpen.value ? (e(), m("span", ot, w(t.commentsInstance.unresolvedCount.value), 1)) : v("", !0)
], 14, at)) : v("", !0),
t.featureFlags.canUseAiGeneration.value && t.featureFlags.hasTemplateSaved.value ? (e(), m("div", {
key: 4,
ref: (e) => t.panelState.aiMenuRef.value = e,
class: "tpl:relative"
}, [f("button", {
"aria-expanded": t.panelState.aiMenuOpen.value,
class: c(["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", t.panelState.aiButtonActive.value ? "tpl-ai-btn--active" : "tpl-ai-btn--idle"]),
onClick: d[1] ||= u((...e) => t.panelState.toggleAiMenu && t.panelState.toggleAiMenu(...e), ["stop"])
}, [E(C(de), {
size: 16,
"stroke-width": 2,
class: "tpl-ai-btn-icon"
}), s(" " + w(C(a).aiChat.button), 1)], 10, st), E(T, {
"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: O(() => [t.panelState.aiMenuOpen.value ? (e(), m("div", ct, [E(C(i), {
"active-feature": t.panelState.activeAiFeature.value,
onSelect: t.panelState.handleAiFeatureSelect
}, null, 8, ["active-feature", "onSelect"])])) : v("", !0)]),
_: 1
})], 512)) : v("", !0),
t.testEmail.isEnabled.value && t.featureFlags.canSendTestEmail.value ? (e(), m("button", {
key: 5,
class: c(C($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: t.testEmail.isSending.value || !t.featureFlags.hasTemplateSaved.value,
onClick: d[2] ||= (e) => t.panelState.testEmailModalOpen.value = !0
}, [t.testEmail.isSending.value ? (e(), x(C(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (e(), x(C(Z), {
key: 0,
size: 16,
"stroke-width": 2
})), s(" " + w(C(a).testEmail.button), 1)], 10, lt)) : v("", !0),
f("button", {
class: c(C($)),
style: {
"background-color": "transparent",
color: "var(--tpl-primary)",
"border-color": "var(--tpl-primary)"
},
disabled: t.isSaveDisabled,
onClick: d[3] ||= (e) => l.$emit("save")
}, [t.isSaving ? (e(), x(C(Y), {
key: 1,
class: "tpl-spinner",
size: 16,
"stroke-width": 2
})) : (e(), x(C(je), {
key: 0,
size: 16,
"stroke-width": 2
})), s(" " + w(t.isSaving ? C(a).header.saving : C(a).header.save), 1)], 10, ut)
])
]));
}
}), ft = /* @__PURE__ */ l({
__name: "CloudPanels",
props: {
config: {},
editor: {},
core: {},
panelState: {},
planConfigInstance: {},
testEmail: {},
mediaLib: {},
savedModulesHeadless: {},
showSaveModuleDialog: { type: Boolean },
saveModulePreSelectedBlockId: {},
showModuleBrowserModal: { type: Boolean }
},
emits: [
"update:showSaveModuleDialog",
"update:saveModulePreSelectedBlockId",
"update:showModuleBrowserModal",
"send-test-email",
"module-insert"
],
setup(t, { expose: n, emit: r }) {
let i = D(() => import("./AiChatSidebar-BUKj9n02.js")), a = D(() => import("./CommentsSidebar-DiH4R4F0.js")), s = D(() => import("./DesignReferenceSidebar-BP32MgpS.js")), c = D(() => import("./TemplateScoringPanel-seBvvn8O.js")), l = D(() => import("./TestEmailModal-BuCuWp3N.js")), u = D(() => import("./SaveModuleDialog-DWidA0c9.js")), d = D(() => import("./ModuleBrowserModal-CWegFoOA.js")), f = D(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.");
}
}), p = r;
function h(e, t, n) {
t.history.record(), n.setContent(e), t.conditionPreview.reset();
}
function g(e, t) {
p("module-insert", e, t);
}
let y = o(null);
function b(e) {
y.value?.filterByBlock(e);
}
return n({ filterCommentsByBlock: b }), (n, r) => (e(), m(_, null, [
E(C(i), {
visible: t.panelState.aiChatOpen.value,
"on-apply": (e) => h(e, t.core, t.editor),
onClose: r[0] ||= (e) => t.panelState.aiChatOpen.value = !1
}, null, 8, ["visible", "on-apply"]),
E(C(c), {
visible: t.panelState.scoringPanelOpen.value,
onClose: r[1] ||= (e) => t.panelState.scoringPanelOpen.value = !1
}, null, 8, ["visible"]),
E(C(s), {
visible: t.panelState.designReferenceOpen.value,
"has-existing-blocks": t.editor.content.value.blocks.length > 0,
onClose: r[2] ||= (e) => t.panelState.designReferenceOpen.value = !1,
onApply: r[3] ||= (e) => h(e, t.core, t.editor)
}, null, 8, ["visible", "has-existing-blocks"]),
E(C(a), {
ref_key: "commentsSidebar",
ref: y,
visible: t.panelState.commentsOpen.value,
onClose: r[4] ||= (e) => t.panelState.commentsOpen.value = !1
}, null, 8, ["visible"]),
E(C(l), {
visible: t.panelState.testEmailModalOpen.value,
"allowed-emails": t.testEmail.allowedEmails.value,
"is-sending": t.testEmail.isSending.value,
error: t.testEmail.error.value,
onSend: r[5] ||= (e) => p("send-test-email", e),
onClose: r[6] ||= (e) => t.panelState.testEmailModalOpen.value = !1
}, null, 8, [
"visible",
"allowed-emails",
"is-sending",
"error"
]),
t.planConfigInstance.hasFeature("saved_modules") && t.config.modules !== !1 ? (e(), x(C(u), {
key: 0,
visible: t.showSaveModuleDialog,
"pre-selected-block-id": t.saveModulePreSelectedBlockId,
onClose: r[7] ||= (e) => {
p("update:showSaveModuleDialog", !1), p("update:saveModulePreSelectedBlockId", null);
},
onSaved: r[8] ||= (e) => t.savedModulesHeadless.loadModules()
}, null, 8, ["visible", "pre-selected-block-id"])) : v("", !0),
t.planConfigInstance.hasFeature("saved_modules") && t.config.modules !== !1 ? (e(), x(C(d), {
key: 1,
visible: t.showModuleBrowserModal,
onClose: r[9] ||= (e) => p("update:showModuleBrowserModal", !1),
onInsert: g
}, null, 8, ["visible"])) : v("", !0),
E(C(f), {
visible: t.panelState.mediaLibraryOpen.value,
accept: t.panelState.mediaLibraryAccept.value,
"popover-target": t.core.popoverRoot.value,
onSelect: t.mediaLib.handleMediaSelect,
onClose: t.mediaLib.handleMediaLibraryClose
}, null, 8, [
"visible",
"accept",
"popover-target",
"onSelect",
"onClose"
])
], 64));
}
}), pt = {
key: 0,
class: "tpl-loading tpl:absolute tpl:inset-0 tpl:z-overlay tpl:flex tpl:flex-col tpl:bg-[var(--tpl-bg)]"
}, mt = { class: "tpl:flex tpl:flex-1 tpl:overflow-hidden" }, ht = { 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)]" }, gt = /* @__PURE__ */ l({
__name: "CloudLoadingOverlay",
props: { visible: { type: Boolean } },
setup(t) {
return (n, i) => t.visible ? (e(), m("div", pt, [i[1] ||= p("<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), f("div", mt, [f("div", ht, [(e(), m(_, null, r(5, (e) => f("div", {
key: e,
class: "tpl-shimmer tpl:size-7 tpl:rounded-[var(--tpl-radius-sm)]"
})), 64))]), i[0] ||= p("<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)])])) : v("", !0);
}
}), _t = {
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)]"
}, vt = { class: "tpl:flex tpl:size-16 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-danger-light)]" }, yt = { class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:text-center" }, bt = { class: "tpl:text-lg tpl:font-semibold tpl:text-[var(--tpl-text)]" }, xt = { class: "tpl:max-w-md tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, St = /* @__PURE__ */ l({
__name: "CloudErrorOverlay",
props: {
error: {},
visible: { type: Boolean }
},
emits: ["retry"],
setup(t, { emit: n }) {
let r = n, { t: i } = Q();
function a(e) {
return "isUnauthorized" in e && e.isUnauthorized ? i.error.authFailed : "isNotFound" in e && e.isNotFound ? i.error.templateNotFound : i.error.defaultMessage;
}
function o(e) {
return "isNotFound" in e && !!e.isNotFound;
}
return (n, s) => t.visible && t.error ? (e(), m("div", _t, [
f("div", vt, [E(C(K), {
size: 32,
"stroke-width": 1.5,
class: "tpl:text-[var(--tpl-danger)]"
})]),
f("div", yt, [f("h2", bt, w(C(i).error.title), 1), f("p", xt, w(a(t.error)), 1)]),
o(t.error) ? v("", !0) : (e(), 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: s[0] ||= (e) => r("retry")
}, w(C(i).error.retry), 1))
])) : v("", !0);
}
}), Ct = {
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)]"
}, wt = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:text-[var(--tpl-text)]" }, Tt = { class: "tpl:flex tpl:items-center tpl:gap-2" }, Et = /* @__PURE__ */ l({
__name: "SnapshotPreviewBanner",
props: { visible: { type: Boolean } },
emits: ["cancel", "confirm"],
setup(t, { emit: n }) {
let r = n, { t: i } = Q();
return (n, a) => t.visible ? (e(), m("div", Ct, [f("div", wt, [E(C(ue), {
size: 18,
"stroke-width": 2,
class: "tpl:text-[var(--tpl-primary)]"
}), f("span", null, w(C(i).snapshotPreview.message), 1)]), f("div", Tt, [f("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) => r("cancel")
}, w(C(i).snapshotPreview.cancel), 1), f("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) => r("confirm")
}, w(C(i).snapshotPreview.restore), 1)])])) : v("", !0);
}
}), Dt = {
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)"
}
}, Ot = /* @__PURE__ */ l({
__name: "CollabUndoToast",
props: { visible: { type: Boolean } },
setup(t) {
let { t: n } = U();
return (r, i) => t.visible ? (e(), m("div", Dt, w(C(n).history.collabWarning), 1)) : v("", !0);
}
}), kt = ["data-tpl-theme"], At = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, jt = { class: "tpl-main tpl:flex tpl:justify-center tpl:p-8" }, Mt = ["aria-label"], Nt = /* @__PURE__ */ pe(/* @__PURE__ */ l({
__name: "CloudEditor",
props: {
config: {},
translations: {},
cloudTranslations: {},
fontsManager: {},
shadowRoot: {}
},
emits: ["ready"],
setup(n, { expose: r, emit: a }) {
let l = n;
h(B, l.cloudTranslations);
let u = a, d = o(null), p = o(null), _ = Le({
config: l.config,
translations: l.translations,
fontsManager: l.fontsManager,
emit: u,
getCommentsSidebar: () => d.value ? { filterByBlock: d.value.filterCommentsByBlock } : null,
editorRoot: l.shadowRoot,
containerEl: p
}), { isInitializing: S, isAuthReady: D, initError: k, planConfigInstance: A, websocket: M, collaboration: N, isCollaborationEnabled: P, editor: F, core: I, featureFlags: L, mediaLib: R, exporter: z, testEmail: V, commentsInstance: ee, savedModulesHeadless: te, panelState: H, snapshotPreview: U, collabWarning: W, showSaveModuleDialog: G, showModuleBrowserModal: K, saveModulePreSelectedBlockId: q, setThemeOverrides: J, setUiTheme: re } = _;
async function oe(e) {
try {
await V.sendTestEmail(e), H.testEmailModalOpen.value = !1;
} catch {}
}
function ue(e, t) {
for (let n = 0; n < e.content.length; n++) {
let r = j(e.content[n]), i = t === void 0 ? void 0 : t + n;
F.addBlock(r, void 0, void 0, i);
}
K.value = !1;
}
let Y = ze({
config: l.config,
editor: F,
websocket: M,
planConfigInstance: A,
snapshotPreview: U,
core: I,
exporter: z,
featureFlags: L,
isDestroyed: _.isDestroyed
}), X = Be({
issues: I.templateLint ? I.templateLint.issues : o([]),
planConfig: A.config
});
async function Z() {
await X.tryRunSave(() => Y.saveTemplate().catch((e) => l.config.onError?.(e)));
}
return _.onSaveHook.value = Z, i(() => {
_.initialize();
}), g(() => {
_.destroy();
}), r({
getContent: () => F.content.value,
setContent: (e) => F.setContent(e),
setTheme: re,
setThemeOverrides: J,
create: Y.createTemplate,
load: Y.loadTemplate,
save: Y.saveTemplate,
sendTestEmail: V.sendTestEmail
}), (r, i) => (e(), m("div", {
ref_key: "rootEl",
ref: p,
class: c(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": C(F).state.darkMode }]),
"data-tpl-theme": C(I).resolvedTheme.value,
style: b(C(I).themeStyles.value)
}, [
E(T, {
"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: O(() => [E(gt, { visible: C(S) || C(F).state.isLoading }, null, 8, ["visible"])]),
_: 1
}),
E(T, {
"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: O(() => [E(St, {
error: C(k),
visible: !!C(k) && !C(S),
onRetry: C(_).initialize
}, null, 8, [
"error",
"visible",
"onRetry"
])]),
_: 1
}),
E(dt, {
editor: C(F),
core: C(I),
"feature-flags": C(L),
"panel-state": C(H),
"snapshot-preview": C(U),
"comments-instance": C(ee),
"test-email": C(V),
websocket: C(M),
collaboration: C(N),
"is-collaboration-enabled": C(P),
"is-saving": C(F).state.isSaving || C(L).isSaveExporting.value,
"is-save-disabled": C(F).state.isSaving || C(L).isSaveExporting.value || !C(F).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"
]),
E(Xe, {
open: C(X).modalOpen.value,
issues: C(X).blockingIssues.value,
onCancel: C(X).cancel,
onConfirm: C(X).confirmAndSave
}, null, 8, [
"open",
"issues",
"onCancel",
"onConfirm"
]),
E(Et, {
visible: C(U).isPreviewingSnapshot.value,
onCancel: C(U).cancelPreview,
onConfirm: C(U).confirmRestoreSnapshot
}, null, 8, [
"visible",
"onCancel",
"onConfirm"
]),
E(T, {
"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: O(() => [E(Ot, { visible: C(W).collabUndoWarningVisible.value }, null, 8, ["visible"])]),
_: 1
}),
t(E(se, null, null, 512), [[y, !C(F).state.previewMode]]),
f("div", {
class: c(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto", [C(F).state.previewMode ? "tpl:left-0 tpl:right-0" : C(H).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]", C(U).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)"
}
}, [f("div", At, [E(T, { name: "tpl-restore-btn" }, {
default: O(() => [C(I).conditionPreview.hasHiddenBlocks.value ? (e(), 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: i[0] ||= (e) => C(I).conditionPreview.reset()
}, [E(C(le), {
size: 13,
"stroke-width": 2
}), s(" " + w(C(I).t.blockSettings.restoreHiddenBlocks), 1)])) : v("", !0)]),
_: 1
})]), f("main", jt, [E(ne, {
viewport: C(F).state.viewport,
content: C(F).content.value,
"selected-block-id": C(F).state.selectedBlockId,
"dark-mode": C(F).state.darkMode,
"preview-mode": C(F).state.previewMode,
"locked-blocks": C(N)?.lockedBlocks.value ?? void 0,
onSelectBlock: C(F).selectBlock,
onOpenAiChat: i[1] ||= (e) => C(H).aiChatOpen.value = !0,
onOpenDesignReference: i[2] ||= (e) => C(H).designReferenceOpen.value = !0
}, null, 8, [
"viewport",
"content",
"selected-block-id",
"dark-mode",
"preview-mode",
"locked-blocks",
"onSelectBlock"
])])], 2),
n.config.branding !== !1 && !C(L).isWhiteLabeled.value ? (e(), x(ie, {
key: 0,
"position-class": [C(F).state.previewMode ? "tpl:left-0 tpl:right-0" : C(H).rightPanelOpen.value ? "tpl:left-12 tpl:right-[680px]" : "tpl:left-12 tpl:right-[320px]"]
}, null, 8, ["position-class"])) : v("", !0),
f("div", {
class: "tpl-sr-only",
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
"aria-label": C(I).t.landmarks.reorderAnnouncements
}, w(C(I).keyboardReorder.announcement.value), 9, Mt),
t(E(ae, {
"selected-block": C(F).selectedBlock.value,
settings: C(F).content.value.settings,
"shifted-left": C(H).rightPanelOpen.value,
onUpdateBlock: i[3] ||= (e) => C(F).updateBlock(C(F).selectedBlock.value.id, e),
onDeleteBlock: i[4] ||= (e) => C(I).blockActions.deleteBlock(C(F).selectedBlock.value.id),
onDuplicateBlock: i[5] ||= (e) => C(I).blockActions.duplicateBlock(C(F).selectedBlock.value),
onUpdateSettings: C(F).updateSettings
}, null, 8, [
"selected-block",
"settings",
"shifted-left",
"onUpdateSettings"
]), [[y, !C(F).state.previewMode]]),
!C(S) && C(D) ? (e(), x(ft, {
key: 1,
ref_key: "cloudPanelsRef",
ref: d,
config: l.config,
editor: C(F),
core: C(I),
"panel-state": C(H),
"plan-config-instance": C(A),
"test-email": C(V),
"media-lib": C(R),
"saved-modules-headless": C(te),
"show-save-module-dialog": C(G),
"save-module-pre-selected-block-id": C(q),
"show-module-browser-modal": C(K),
"onUpdate:showSaveModuleDialog": i[6] ||= (e) => G.value = e,
"onUpdate:saveModulePreSelectedBlockId": i[7] ||= (e) => q.value = e,
"onUpdate:showModuleBrowserModal": i[8] ||= (e) => K.value = e,
onSendTestEmail: oe,
onModuleInsert: ue
}, null, 8, [
"config",
"editor",
"core",
"panel-state",
"plan-config-instance",
"test-email",
"media-lib",
"saved-modules-headless",
"show-save-module-dialog",
"save-module-pre-selected-block-id",
"show-module-browser-modal"
])) : v("", !0),
f("div", {
ref: (e) => C(I).popoverRoot.value = e,
class: "tpl-popover-root"
}, null, 512),
E(ce)
], 14, kt));
}
}), [["__scopeId", "data-v-3f0f5cfa"]]);
//#endregion
export { Nt as default };

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

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

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