@fonderie/vue-courier-admin-screens 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +136 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +137 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28
28
|
|
|
29
29
|
// src/screens/TemplateCreateScreen.ts
|
|
30
30
|
var import_client = require("@fonderie/client");
|
|
31
|
+
var import_vue_courier_admin = require("@fonderie/vue-courier-admin");
|
|
31
32
|
var import_vue = require("vue");
|
|
32
33
|
|
|
33
34
|
// src/styles.ts
|
|
@@ -269,6 +270,16 @@ var styles = {
|
|
|
269
270
|
// src/screens/TemplateCreateScreen.ts
|
|
270
271
|
var TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;
|
|
271
272
|
var LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
273
|
+
var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
274
|
+
var PREVIEW_DEBOUNCE_MS = 500;
|
|
275
|
+
var notice = {
|
|
276
|
+
fontSize: "13px",
|
|
277
|
+
color: "var(--fonderie-text,#171717)",
|
|
278
|
+
background: "color-mix(in srgb, var(--fonderie-warning,#f5a623) 16%, transparent)",
|
|
279
|
+
borderRadius: "6px",
|
|
280
|
+
padding: "8px 12px",
|
|
281
|
+
margin: "12px 0 0"
|
|
282
|
+
};
|
|
272
283
|
var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
273
284
|
name: "FonderieTemplateCreateScreen",
|
|
274
285
|
props: {
|
|
@@ -297,6 +308,14 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
297
308
|
const text = (0, import_vue.ref)("");
|
|
298
309
|
const error = (0, import_vue.ref)(null);
|
|
299
310
|
const busy = (0, import_vue.ref)(false);
|
|
311
|
+
const source = (0, import_vue.ref)(null);
|
|
312
|
+
const {
|
|
313
|
+
preview,
|
|
314
|
+
isPreviewing,
|
|
315
|
+
error: previewError,
|
|
316
|
+
renderPreview
|
|
317
|
+
} = (0, import_vue_courier_admin.useTemplatePreview)(props.client);
|
|
318
|
+
let variables = [];
|
|
300
319
|
const tr = (key, params) => (0, import_client.createAdminT)(props.locale)(key, params);
|
|
301
320
|
(0, import_vue.onMounted)(() => {
|
|
302
321
|
if (!props.type) return;
|
|
@@ -304,8 +323,50 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
304
323
|
subject.value = result.subject ?? "";
|
|
305
324
|
html.value = result.html ?? "";
|
|
306
325
|
text.value = result.text;
|
|
326
|
+
source.value = {
|
|
327
|
+
subject: result.subject ?? "",
|
|
328
|
+
html: result.html ?? "",
|
|
329
|
+
text: result.text
|
|
330
|
+
};
|
|
307
331
|
}).catch(() => void 0);
|
|
308
332
|
});
|
|
333
|
+
let timer;
|
|
334
|
+
(0, import_vue.watch)([newType, targetLocale, subject, html, text], () => {
|
|
335
|
+
clearTimeout(timer);
|
|
336
|
+
const type = addingLocale ? props.type : newType.value.trim();
|
|
337
|
+
const l = targetLocale.value.trim();
|
|
338
|
+
if (!TYPE_RE.test(type) || !text.value.trim()) return;
|
|
339
|
+
timer = setTimeout(async () => {
|
|
340
|
+
const input = {
|
|
341
|
+
text: text.value,
|
|
342
|
+
...subject.value ? { subject: subject.value } : {},
|
|
343
|
+
...html.value ? { html: html.value } : {}
|
|
344
|
+
};
|
|
345
|
+
const render = () => renderPreview(
|
|
346
|
+
type,
|
|
347
|
+
{ ...input, data: Object.fromEntries(variables.map((v) => [v, v])) },
|
|
348
|
+
LOCALE_RE.test(l) ? l : null
|
|
349
|
+
);
|
|
350
|
+
try {
|
|
351
|
+
const result = await render();
|
|
352
|
+
const used = result.variables.filter((v) => !IMPLICIT.has(v));
|
|
353
|
+
if (used.some((v) => !variables.includes(v))) {
|
|
354
|
+
variables = used;
|
|
355
|
+
await render();
|
|
356
|
+
}
|
|
357
|
+
} catch {
|
|
358
|
+
}
|
|
359
|
+
}, PREVIEW_DEBOUNCE_MS);
|
|
360
|
+
});
|
|
361
|
+
const untranslated = (0, import_vue.computed)(() => {
|
|
362
|
+
const src = source.value;
|
|
363
|
+
if (!src) return [];
|
|
364
|
+
return [
|
|
365
|
+
subject.value && subject.value === src.subject ? tr("templates.subject") : null,
|
|
366
|
+
html.value && html.value === src.html ? tr("templates.htmlBody") : null,
|
|
367
|
+
text.value === src.text ? tr("templates.textBody") : null
|
|
368
|
+
].filter((f) => f !== null);
|
|
369
|
+
});
|
|
309
370
|
async function submit(e) {
|
|
310
371
|
e.preventDefault();
|
|
311
372
|
error.value = null;
|
|
@@ -363,7 +424,7 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
363
424
|
}
|
|
364
425
|
})
|
|
365
426
|
];
|
|
366
|
-
return () => (0, import_vue.h)("div", { style:
|
|
427
|
+
return () => (0, import_vue.h)("div", { style: styles.container }, [
|
|
367
428
|
(0, import_vue.h)(
|
|
368
429
|
"h1",
|
|
369
430
|
{ style: styles.title },
|
|
@@ -374,35 +435,69 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
374
435
|
{ style: { ...styles.meta, lineHeight: 1.5 } },
|
|
375
436
|
addingLocale ? tr("templates.create.hintLocale") : tr("templates.create.hintNew")
|
|
376
437
|
),
|
|
377
|
-
(0, import_vue.h)("
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
"
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
438
|
+
(0, import_vue.h)("div", { style: styles.split }, [
|
|
439
|
+
(0, import_vue.h)("form", { style: styles.form, onSubmit: (ev) => void submit(ev) }, [
|
|
440
|
+
...addingLocale ? [] : field("new-template-type", tr("templates.create.type"), newType, {
|
|
441
|
+
placeholder: "weekly-digest"
|
|
442
|
+
}),
|
|
443
|
+
...field(
|
|
444
|
+
"new-template-locale",
|
|
445
|
+
addingLocale ? tr("templates.create.locale") : tr("templates.create.localeOptional"),
|
|
446
|
+
targetLocale,
|
|
447
|
+
{ placeholder: "fr", list: "new-template-locales" }
|
|
448
|
+
),
|
|
449
|
+
(0, import_vue.h)(
|
|
450
|
+
"datalist",
|
|
451
|
+
{ id: "new-template-locales" },
|
|
452
|
+
[...new Set(props.locales)].map((l) => (0, import_vue.h)("option", { key: l, value: l }))
|
|
453
|
+
),
|
|
454
|
+
...field("new-template-subject", tr("templates.subject"), subject),
|
|
455
|
+
...field("new-template-html", tr("templates.htmlBody"), html, {
|
|
456
|
+
textarea: true,
|
|
457
|
+
minHeight: "160px"
|
|
458
|
+
}),
|
|
459
|
+
...field("new-template-text", tr("templates.textBody"), text, {
|
|
460
|
+
textarea: true,
|
|
461
|
+
minHeight: "100px"
|
|
462
|
+
}),
|
|
463
|
+
untranslated.value.length > 0 ? (0, import_vue.h)(
|
|
464
|
+
"p",
|
|
465
|
+
{ style: notice },
|
|
466
|
+
tr("templates.create.untranslated", { fields: untranslated.value.join(", ") })
|
|
467
|
+
) : null,
|
|
468
|
+
error.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, error.value) : null,
|
|
469
|
+
(0, import_vue.h)(
|
|
470
|
+
"button",
|
|
471
|
+
{
|
|
472
|
+
type: "submit",
|
|
473
|
+
disabled: busy.value,
|
|
474
|
+
style: { ...styles.button, marginTop: "16px" }
|
|
475
|
+
},
|
|
476
|
+
busy.value ? tr("templates.create.creating") : addingLocale ? tr("templates.create.submitLocale") : tr("templates.create.submitNew")
|
|
477
|
+
)
|
|
478
|
+
]),
|
|
479
|
+
(0, import_vue.h)("div", { style: styles.previewColumn }, [
|
|
480
|
+
(0, import_vue.h)("div", { style: styles.previewHeader }, [
|
|
481
|
+
(0, import_vue.h)("span", { style: styles.label }, tr("templates.editor.preview")),
|
|
482
|
+
(0, import_vue.h)(
|
|
483
|
+
"span",
|
|
484
|
+
{ style: styles.meta },
|
|
485
|
+
isPreviewing.value ? tr("templates.editor.rendering") : tr("templates.editor.live")
|
|
486
|
+
)
|
|
487
|
+
]),
|
|
488
|
+
previewError.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, previewError.value.explanation) : null,
|
|
489
|
+
preview.value?.subject ? (0, import_vue.h)("p", { style: styles.previewSubject }, preview.value.subject) : null,
|
|
490
|
+
preview.value?.html ? (
|
|
491
|
+
// sandbox= — no scripts, no same-origin: operator-authored HTML must
|
|
492
|
+
// never execute in the console's origin.
|
|
493
|
+
(0, import_vue.h)("iframe", {
|
|
494
|
+
title: tr("templates.editor.previewTitle"),
|
|
495
|
+
style: styles.previewFrame,
|
|
496
|
+
sandbox: "",
|
|
497
|
+
srcdoc: preview.value.html
|
|
498
|
+
})
|
|
499
|
+
) : preview.value ? (0, import_vue.h)("pre", { style: styles.previewText }, preview.value.text) : (0, import_vue.h)("p", { style: styles.meta }, tr("templates.editor.nothingRendered"))
|
|
500
|
+
])
|
|
406
501
|
])
|
|
407
502
|
]);
|
|
408
503
|
}
|
|
@@ -410,10 +505,10 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
410
505
|
|
|
411
506
|
// src/screens/TemplateEditorScreen.ts
|
|
412
507
|
var import_client2 = require("@fonderie/client");
|
|
413
|
-
var
|
|
508
|
+
var import_vue_courier_admin2 = require("@fonderie/vue-courier-admin");
|
|
414
509
|
var import_vue2 = require("vue");
|
|
415
|
-
var
|
|
416
|
-
var
|
|
510
|
+
var PREVIEW_DEBOUNCE_MS2 = 500;
|
|
511
|
+
var IMPLICIT2 = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
417
512
|
var tab = {
|
|
418
513
|
height: "32px",
|
|
419
514
|
padding: "0 10px",
|
|
@@ -477,17 +572,17 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
477
572
|
},
|
|
478
573
|
setup(props, { emit }) {
|
|
479
574
|
const t = (key, params) => (0, import_client2.createAdminT)(props.uiLocale)(key, params);
|
|
480
|
-
const { template, isLoading, error, refresh } = (0,
|
|
575
|
+
const { template, isLoading, error, refresh } = (0, import_vue_courier_admin2.useTemplate)(
|
|
481
576
|
props.client,
|
|
482
577
|
props.type,
|
|
483
578
|
props.locale
|
|
484
579
|
);
|
|
485
|
-
const { templates, saveTemplate, removeTemplate } = (0,
|
|
580
|
+
const { templates, saveTemplate, removeTemplate } = (0, import_vue_courier_admin2.useTemplates)(props.client);
|
|
486
581
|
const siblings = (0, import_vue2.computed)(
|
|
487
582
|
() => (0, import_client2.groupTemplatesByType)(templates.value).find((g) => g.type === props.type)?.entries ?? []
|
|
488
583
|
);
|
|
489
584
|
const isDeleting = (0, import_vue2.ref)(false);
|
|
490
|
-
const { revisions, rollback } = (0,
|
|
585
|
+
const { revisions, rollback } = (0, import_vue_courier_admin2.useTemplateRevisions)(props.client, props.type, props.locale);
|
|
491
586
|
const isSaving = (0, import_vue2.ref)(false);
|
|
492
587
|
const saveError = (0, import_vue2.ref)(null);
|
|
493
588
|
const subject = (0, import_vue2.ref)("");
|
|
@@ -506,7 +601,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
506
601
|
isPreviewing,
|
|
507
602
|
error: previewError,
|
|
508
603
|
renderPreview
|
|
509
|
-
} = (0,
|
|
604
|
+
} = (0, import_vue_courier_admin2.useTemplatePreview)(props.client);
|
|
510
605
|
const sampleJson = (0, import_vue2.ref)("{}");
|
|
511
606
|
const sampleError = (0, import_vue2.ref)(null);
|
|
512
607
|
async function run() {
|
|
@@ -533,7 +628,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
533
628
|
},
|
|
534
629
|
props.locale
|
|
535
630
|
);
|
|
536
|
-
const missing = result.variables.filter((v) => !
|
|
631
|
+
const missing = result.variables.filter((v) => !IMPLICIT2.has(v) && !(v in data));
|
|
537
632
|
if (missing.length > 0) {
|
|
538
633
|
sampleJson.value = JSON.stringify(
|
|
539
634
|
{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },
|
|
@@ -546,7 +641,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
546
641
|
(0, import_vue2.watch)([template, subject, html, text, sampleJson], () => {
|
|
547
642
|
if (!template.value) return;
|
|
548
643
|
clearTimeout(previewTimer);
|
|
549
|
-
previewTimer = setTimeout(() => void run(),
|
|
644
|
+
previewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS2);
|
|
550
645
|
});
|
|
551
646
|
const dirty = (0, import_vue2.computed)(() => {
|
|
552
647
|
const tpl = template.value;
|
|
@@ -793,7 +888,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
793
888
|
|
|
794
889
|
// src/screens/TemplateListScreen.ts
|
|
795
890
|
var import_client3 = require("@fonderie/client");
|
|
796
|
-
var
|
|
891
|
+
var import_vue_courier_admin3 = require("@fonderie/vue-courier-admin");
|
|
797
892
|
var import_vue3 = require("vue");
|
|
798
893
|
var builtIn = {
|
|
799
894
|
fontSize: "11px",
|
|
@@ -864,7 +959,7 @@ var TemplateListScreen = (0, import_vue3.defineComponent)({
|
|
|
864
959
|
"create-template": (_context) => true
|
|
865
960
|
},
|
|
866
961
|
setup(props, { emit }) {
|
|
867
|
-
const { templates, isLoading, error } = (0,
|
|
962
|
+
const { templates, isLoading, error } = (0, import_vue_courier_admin3.useTemplates)(props.client);
|
|
868
963
|
const t = (key, params) => (0, import_client3.createAdminT)(props.locale)(key, params);
|
|
869
964
|
function renderRow(group) {
|
|
870
965
|
const primary = group.primary;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/screens/TemplateCreateScreen.ts","../src/styles.ts","../src/screens/TemplateEditorScreen.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["export { TemplateCreateScreen, TemplateEditorScreen, TemplateListScreen } from './screens';\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tISetTemplateInput,\n} from '@fonderie/client';\nimport { createAdminT, FonderieApiError } from '@fonderie/client';\nimport type { PropType } from 'vue';\nimport { defineComponent, h, onMounted, ref } from 'vue';\nimport { styles } from '../styles';\n\nconst TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;\nconst LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;\n\n// Creating is its own screen: the editor loads an existing row, and a new\n// template or locale has none yet. Once saved, the editor takes over.\nexport const TemplateCreateScreen = defineComponent({\n\tname: 'FonderieTemplateCreateScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/**\n\t\t * Given ⇒ add a LOCALE of this existing template: the type is fixed and the\n\t\t * form starts from its default-locale copy. Omitted ⇒ a brand-new template\n\t\t * type (one the app sends that has no stored copy yet).\n\t\t */\n\t\ttype: { type: String, default: undefined },\n\t\t/** Locales already in use, offered as suggestions. */\n\t\tlocales: { type: Array as PropType<string[]>, default: () => [] },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/** What was created, so the caller can open it in the editor. */\n\t\tcreated: (_created: { type: string; locale: string | null }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst addingLocale = props.type !== undefined;\n\t\tconst newType = ref('');\n\t\tconst targetLocale = ref('');\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst error = ref<string | null>(null);\n\t\tconst busy = ref(false);\n\t\t// `tr`, not `t`: submit() uses `t` for the template type.\n\t\tconst tr = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\t// A new locale starts from the default copy, so translating is editing.\n\t\tonMounted(() => {\n\t\t\tif (!props.type) return;\n\t\t\tprops.client\n\t\t\t\t.getTemplate(props.type, null)\n\t\t\t\t.then(({ result }) => {\n\t\t\t\t\tsubject.value = result.subject ?? '';\n\t\t\t\t\thtml.value = result.html ?? '';\n\t\t\t\t\ttext.value = result.text;\n\t\t\t\t})\n\t\t\t\t.catch(() => undefined);\n\t\t});\n\n\t\tasync function submit(e: Event) {\n\t\t\te.preventDefault();\n\t\t\terror.value = null;\n\t\t\tconst t = addingLocale ? (props.type as string) : newType.value.trim();\n\t\t\tconst l = targetLocale.value.trim() || null;\n\t\t\tif (!TYPE_RE.test(t)) {\n\t\t\t\terror.value = tr('templates.create.errorType');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (addingLocale && !l) {\n\t\t\t\terror.value = tr('templates.create.errorLocaleRequired');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (l && !LOCALE_RE.test(l)) {\n\t\t\t\terror.value = tr('templates.create.errorLocale');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!text.value.trim()) {\n\t\t\t\terror.value = tr('templates.create.errorText');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbusy.value = true;\n\t\t\ttry {\n\t\t\t\t// Refuse to overwrite: creating an existing row would replace it.\n\t\t\t\tconst exists = await props.client.getTemplate(t, l).then(\n\t\t\t\t\t() => true,\n\t\t\t\t\t(err: unknown) => !(err instanceof FonderieApiError && err.status === 404),\n\t\t\t\t);\n\t\t\t\tif (exists) {\n\t\t\t\t\terror.value = l\n\t\t\t\t\t\t? tr('templates.create.existsLocale', { type: t, locale: l })\n\t\t\t\t\t\t: tr('templates.create.exists', { type: t });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: true };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tawait props.client.setTemplate(t, input, l);\n\t\t\t\temit('created', { type: t, locale: l });\n\t\t\t} catch (err) {\n\t\t\t\terror.value = err instanceof FonderieApiError ? err.explanation : String(err);\n\t\t\t} finally {\n\t\t\t\tbusy.value = false;\n\t\t\t}\n\t\t}\n\n\t\tconst field = (\n\t\t\tid: string,\n\t\t\tlabel: string,\n\t\t\tmodel: typeof subject,\n\t\t\topts: Record<string, unknown> = {},\n\t\t) => [\n\t\t\th('label', { style: styles.label, for: id }, label),\n\t\t\th(opts.textarea ? 'textarea' : 'input', {\n\t\t\t\tid,\n\t\t\t\tstyle: opts.textarea ? { ...styles.textarea, minHeight: opts.minHeight } : styles.input,\n\t\t\t\tvalue: model.value,\n\t\t\t\tautocomplete: 'off',\n\t\t\t\tspellcheck: false,\n\t\t\t\t...(opts.placeholder ? { placeholder: opts.placeholder } : {}),\n\t\t\t\t...(opts.list ? { list: opts.list } : {}),\n\t\t\t\tonInput: (ev: Event) => {\n\t\t\t\t\tmodel.value = (ev.target as HTMLInputElement).value;\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\n\t\treturn () =>\n\t\t\th('div', { style: { ...styles.container, maxWidth: '760px' } }, [\n\t\t\t\th(\n\t\t\t\t\t'h1',\n\t\t\t\t\t{ style: styles.title },\n\t\t\t\t\taddingLocale\n\t\t\t\t\t\t? tr('templates.create.titleLocale', { type: props.type as string })\n\t\t\t\t\t\t: tr('templates.create.titleNew'),\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: { ...styles.meta, lineHeight: 1.5 } },\n\t\t\t\t\taddingLocale\n\t\t\t\t\t\t? tr('templates.create.hintLocale')\n\t\t\t\t\t\t: tr('templates.create.hintNew'),\n\t\t\t\t),\n\t\t\t\th('form', { style: styles.form, onSubmit: (ev: Event) => void submit(ev) }, [\n\t\t\t\t\t...(addingLocale\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: field('new-template-type', tr('templates.create.type'), newType, { placeholder: 'weekly-digest' })),\n\t\t\t\t\t...field(\n\t\t\t\t\t\t'new-template-locale',\n\t\t\t\t\t\taddingLocale ? tr('templates.create.locale') : tr('templates.create.localeOptional'),\n\t\t\t\t\t\ttargetLocale,\n\t\t\t\t\t\t{ placeholder: 'fr', list: 'new-template-locales' },\n\t\t\t\t\t),\n\t\t\t\t\th(\n\t\t\t\t\t\t'datalist',\n\t\t\t\t\t\t{ id: 'new-template-locales' },\n\t\t\t\t\t\t[...new Set(props.locales)].map((l) => h('option', { key: l, value: l })),\n\t\t\t\t\t),\n\t\t\t\t\t...field('new-template-subject', tr('templates.subject'), subject),\n\t\t\t\t\t...field('new-template-html', tr('templates.htmlBody'), html, { textarea: true, minHeight: '160px' }),\n\t\t\t\t\t...field('new-template-text', tr('templates.textBody'), text, {\n\t\t\t\t\t\ttextarea: true,\n\t\t\t\t\t\tminHeight: '100px',\n\t\t\t\t\t}),\n\t\t\t\t\terror.value ? h('p', { style: styles.error, role: 'alert' }, error.value) : null,\n\t\t\t\t\th(\n\t\t\t\t\t\t'button',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\tdisabled: busy.value,\n\t\t\t\t\t\t\tstyle: { ...styles.button, marginTop: '16px' },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbusy.value\n\t\t\t\t\t\t\t? tr('templates.create.creating')\n\t\t\t\t\t\t\t: addingLocale\n\t\t\t\t\t\t\t\t? tr('templates.create.submitLocale')\n\t\t\t\t\t\t\t\t: tr('templates.create.submitNew'),\n\t\t\t\t\t),\n\t\t\t\t]),\n\t\t\t]);\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '8px 40px 64px', maxWidth: '1400px', boxSizing: 'border-box' },\n\t// Two columns, always: editor left, rendered result right. Stacking the\n\t// preview under a long form hid it below the fold.\n\tsplit: {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',\n\t\tgap: '24px',\n\t\talignItems: 'start',\n\t},\n\tcolumn: { minWidth: '0', display: 'flex', flexDirection: 'column' },\n\t// Pinned while the form scrolls, so the preview stays in view as you edit.\n\tpreviewColumn: {\n\t\tminWidth: '0',\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tposition: 'sticky',\n\t\ttop: '16px',\n\t},\n\tsaveRow: { display: 'flex', alignItems: 'center', gap: '12px', marginTop: '16px' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '8px 0 4px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\tsubtitle: {\n\t\tfontSize: '15px',\n\t\tfontWeight: 600,\n\t\tmargin: '0 0 10px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t},\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '20px' },\n\tstatus: { padding: '24px 0', color: 'var(--fonderie-text-muted,#5c5c5c)', fontSize: '13.5px' },\n\terror: {\n\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)',\n\t\tborderRadius: '6px',\n\t\tpadding: '8px 12px',\n\t\tmargin: '8px 0',\n\t\tfontSize: '13.5px',\n\t},\n\tlist: {\n\t\tlistStyle: 'none',\n\t\tpadding: '0',\n\t\tmargin: '0',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\toverflow: 'hidden',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '16px',\n\t\tpadding: '13px 16px',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily: 'inherit',\n\t},\n\ttype: {\n\t\tfontSize: '13px',\n\t\tfontWeight: 600,\n\t\tflex: '1',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tlocale: { fontSize: '12.5px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-accent-strong,#009767)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-accent-strong,#009767) 13%, transparent)',\n\t},\n\tinactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-text-muted,#5c5c5c) 10%, transparent)',\n\t},\n\tform: {\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tgap: '4px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\tpadding: '6px 20px 20px',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tlabel: { fontSize: '13px', fontWeight: 500, marginTop: '14px', marginBottom: '2px' },\n\tinput: {\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '13.5px',\n\t\tfontFamily: 'inherit',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t},\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '10px',\n\t\tfontSize: '13px',\n\t\tlineHeight: 1.55,\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\tcursor: 'pointer',\n\t},\n\tbuttonDisabled: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\topacity: 0.45,\n\t\tcursor: 'not-allowed',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '12px',\n\t\tpadding: '9px 16px',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '28px',\n\t\tboxSizing: 'border-box',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '12.5px',\n\t\tfontWeight: 500,\n\t\tfontFamily: 'inherit',\n\t\tcursor: 'pointer',\n\t},\n\t// Template list: matches @fonderie/vue-admin-screens' shell look with local\n\t// values — this package sits below the admin screens and cannot import them.\n\tlistContainer: { padding: '32px 40px 64px', maxWidth: '1160px', boxSizing: 'border-box' },\n\tlistTitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '0',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\thint: { fontSize: '13.5px', color: 'var(--fonderie-text-muted,#5c5c5c)', margin: '4px 0 24px' },\n\tdot: { width: '6px', height: '6px', borderRadius: '999px', background: 'currentColor' },\n};\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateEntry,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tcreateAdminT,\n\tformatAdminDate,\n\tgroupTemplatesByType,\n\tmissingTemplateLocales,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { computed, defineComponent, h, ref, watch } from 'vue';\n\nconst PREVIEW_DEBOUNCE_MS = 500;\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\n// One tab per locale of this email, underlined like a document's tabs.\nconst tab: CSSProperties = {\n\theight: '32px',\n\tpadding: '0 10px',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderBottom: '2px solid transparent',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\tfontSize: '13px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst tabSelected: CSSProperties = {\n\t...tab,\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontWeight: 600,\n\tborderBottomColor: 'var(--fonderie-text,#171717)',\n\tcursor: 'default',\n};\nconst tabInactive: CSSProperties = { ...tab, opacity: 0.55, textDecoration: 'line-through' };\nconst tabBar: CSSProperties = {\n\tdisplay: 'flex',\n\talignItems: 'flex-end',\n\tgap: '12px',\n\tborderBottom: '1px solid var(--fonderie-border,#e0e0e0)',\n\tmargin: '4px 0 12px',\n\tpaddingBottom: '6px',\n};\nconst tabs: CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: '4px', marginBottom: '-7px' };\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t\t/**\n\t\t * A built-in email's default-locale row (the list's `system` flag): it can\n\t\t * be edited and rolled back, never deleted — Delete is not offered.\n\t\t */\n\t\tsystem: { type: Boolean, default: false },\n\t\t/** Shows \"+ Add locale\" (emits add-locale). */\n\t\tallowAddLocale: { type: Boolean, default: false },\n\t\t/**\n\t\t * Shows a tab per locale this email exists in (emits select-locale).\n\t\t * Unsaved edits are confirmed before switching away.\n\t\t */\n\t\tlocaleTabs: { type: Boolean, default: false },\n\t\t/** The console language (`locale` is the template's); defaults to English. */\n\t\tuiLocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t\t/** The template was deleted and no longer exists. */\n\t\tdeleted: () => true,\n\t\t/**\n\t\t * Create a translation of this template. `locales` are the ones the app\n\t\t * uses elsewhere that this email lacks — suggest them first.\n\t\t */\n\t\t'add-locale': (_type: string, _context: { locales: string[] }) => true,\n\t\t/** Open another locale of this email. */\n\t\t'select-locale': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.uiLocale)(key, params);\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { templates, saveTemplate, removeTemplate } = useTemplates(props.client);\n\t\t// This email's locales, for the tabs. The list is already fetched for saves.\n\t\tconst siblings = computed(\n\t\t\t() => groupTemplatesByType(templates.value).find((g) => g.type === props.type)?.entries ?? [],\n\t\t);\n\t\tconst isDeleting = ref(false);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<AdminMessageKey | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'templates.editor.sampleNotObject';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'templates.editor.sampleInvalid';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// The preview is always live: it renders once the template loads, then\n\t\t// again PREVIEW_DEBOUNCE_MS after the last edit to the content or the sample\n\t\t// data — debounced, so typing a paragraph costs one request, not one per key.\n\t\tlet previewTimer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([template, subject, html, text, sampleJson], () => {\n\t\t\tif (!template.value) return;\n\t\t\tclearTimeout(previewTimer);\n\t\t\tpreviewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\t// Saving what is already stored would only mint an identical version (the\n\t\t// server treats it as a no-op anyway), so Save waits for a real change.\n\t\tconst dirty = computed(() => {\n\t\t\tconst tpl = template.value;\n\t\t\treturn (\n\t\t\t\t!!tpl &&\n\t\t\t\t(subject.value !== (tpl.subject ?? '') ||\n\t\t\t\t\thtml.value !== (tpl.html ?? '') ||\n\t\t\t\t\ttext.value !== tpl.text ||\n\t\t\t\t\tactive.value !== tpl.active)\n\t\t\t);\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\t// Leaving a locale with unsaved edits asks first: they would be lost.\n\t\tconst leave = () => !dirty.value || window.confirm(t('templates.editor.discardChanges'));\n\n\t\tfunction renderTabBar() {\n\t\t\tif (!props.localeTabs && !props.allowAddLocale) return null;\n\t\t\treturn h('div', { style: tabBar }, [\n\t\t\t\tprops.localeTabs\n\t\t\t\t\t? // Each tab opens another stored row, so this is navigation, not an\n\t\t\t\t\t\t// ARIA tablist: plain buttons, the open one marked aria-current.\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'nav',\n\t\t\t\t\t\t\t{ 'aria-label': t('templates.editor.locales'), style: tabs },\n\t\t\t\t\t\t\tsiblings.value.map((entry) => {\n\t\t\t\t\t\t\t\tconst selected = entry.locale === (props.locale ?? null);\n\t\t\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t'aria-current': selected ? 'true' : undefined,\n\t\t\t\t\t\t\t\t\t\tstyle: selected ? tabSelected : entry.active ? tab : tabInactive,\n\t\t\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\tif (!selected && leave()) emit('select-locale', entry);\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tentry.locale ?? t('templates.defaultChip'),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t\tprops.allowAddLocale\n\t\t\t\t\t? h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: { ...styles.rollbackButton, marginLeft: 'auto' },\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tif (leave())\n\t\t\t\t\t\t\t\t\t\temit('add-locale', props.type, {\n\t\t\t\t\t\t\t\t\t\t\tlocales: missingTemplateLocales(templates.value, props.type),\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tt('templates.editor.addLocale'),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t}\n\n\t\tasync function handleDelete() {\n\t\t\tconst message = props.locale\n\t\t\t\t? t('templates.editor.confirmDeleteLocale', { locale: props.locale, type: props.type })\n\t\t\t\t: t('templates.editor.confirmDelete', { type: props.type });\n\t\t\tif (!window.confirm(message)) return;\n\t\t\tisDeleting.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tawait removeTemplate(props.type, props.locale);\n\t\t\t\temit('deleted');\n\t\t\t} catch (err) {\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisDeleting.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? t('templates.editor.unknownActor')} — ${formatAdminDate(rev.createdAt, props.uiLocale)}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\tt('templates.editor.rollBack'),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, t('templates.editor.loading'));\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\trenderTabBar(),\n\t\t\t\th('p', { style: styles.meta }, [\n\t\t\t\t\th('strong', props.locale ?? t('templates.defaultLocale')),\n\t\t\t\t\t` · v${template.value?.version ?? 1}`,\n\t\t\t\t\tprops.system ? ` · ${t('templates.editor.builtInNote')}` : '',\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, t('templates.subject')),\n\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, t('templates.htmlBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, t('templates.textBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tt('templates.editor.active'),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\tsaveError.value?.reason === 'VERSION_CONFLICT'\n\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, [\n\t\t\t\t\t\t\t\t\t\t`${t('templates.editor.conflict')} `,\n\t\t\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsaveError.value = null;\n\t\t\t\t\t\t\t\t\t\t\t\t\tvoid refresh();\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tt('common.reload'),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t\t: saveError.value\n\t\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\th('div', { style: styles.saveRow }, [\n\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\t\t\tdisabled: isSaving.value || !dirty.value,\n\t\t\t\t\t\t\t\t\t\tstyle: dirty.value ? styles.button : styles.buttonDisabled,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tisSaving.value ? t('common.saving') : t('common.save'),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t!dirty.value && !isSaving.value\n\t\t\t\t\t\t\t\t\t? h('span', { style: styles.meta }, t('templates.editor.noChanges'))\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t!props.system\n\t\t\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled: isDeleting.value,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => void handleDelete(),\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t...styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\t\theight: '36px',\n\t\t\t\t\t\t\t\t\t\t\t\t\tmarginLeft: 'auto',\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderColor:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)',\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tisDeleting.value ? t('common.deleting') : t('common.delete'),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'label',\n\t\t\t\t\t\t\t{ style: styles.label, for: 'template-sample' },\n\t\t\t\t\t\t\tt('templates.editor.sampleData'),\n\t\t\t\t\t\t),\n\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t\tspellcheck: false,\n\t\t\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tsampleError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, t(sampleError.value))\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t]),\n\t\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\t\th('span', { style: styles.label }, t('templates.editor.preview')),\n\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t\t\t\tisPreviewing.value ? t('templates.editor.rendering') : t('templates.editor.live'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\t\ttitle: t('templates.editor.previewTitle'),\n\t\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t\t: h('p', { style: styles.meta }, t('templates.editor.nothingRendered')),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, t('templates.editor.history')),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tITemplateEntry,\n} from '@fonderie/client';\nimport { createAdminT, groupTemplatesByType } from '@fonderie/client';\nimport type { ITemplateGroup } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nconst builtIn: CSSProperties = {\n\tfontSize: '11px',\n\tfontWeight: 500,\n\tpadding: '1px 7px',\n\tborderRadius: '999px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n};\n// One per locale the email exists in. Monospace: they are language tags.\nconst chip: CSSProperties = {\n\theight: '24px',\n\tboxSizing: 'border-box',\n\tpadding: '0 8px',\n\tborderRadius: '6px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tbackground: 'var(--fonderie-surface,#fff)',\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontSize: '12px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst chipInactive: CSSProperties = { ...chip, opacity: 0.5, textDecoration: 'line-through' };\nconst row: CSSProperties = {\n\t...styles.row,\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '8px',\n\tpaddingRight: '16px',\n};\nconst rowButton: CSSProperties = { ...styles.rowButton, width: 'auto', flex: '1', minWidth: '0' };\nconst chips: CSSProperties = {\n\tdisplay: 'flex',\n\tflexWrap: 'wrap',\n\tjustifyContent: 'flex-end',\n\tgap: '6px',\n};\nconst newButton: CSSProperties = {\n\tdisplay: 'inline-flex',\n\talignItems: 'center',\n\theight: '32px',\n\tboxSizing: 'border-box',\n\tborderRadius: '6px',\n\tpadding: '0 12px',\n\tfontSize: '13px',\n\tfontWeight: 500,\n\tfontFamily: 'inherit',\n\tcursor: 'pointer',\n\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\tcolor: 'var(--fonderie-surface,#fff)',\n\tborder: '1px solid var(--fonderie-text,#171717)',\n};\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/** Shows a \"New template\" button (emits create-template). */\n\t\tallowCreate: { type: Boolean, default: false },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/**\n\t\t * The whole row — type AND locale, and whether it is built-in. One row\n\t\t * per email: the row opens the default locale, a locale chip that locale.\n\t\t */\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t\t/** Receives the locales in use, to suggest. */\n\t\t'create-template': (_context: { locales: string[] }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\tfunction renderRow(group: ITemplateGroup) {\n\t\t\tconst primary: ITemplateEntry = group.primary;\n\t\t\treturn h('li', { key: group.type, style: row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', primary),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, group.type),\n\t\t\t\t\t\tgroup.system ? h('span', { style: builtIn }, t('templates.builtInBadge')) : null,\n\t\t\t\t\t\th('span', { style: primary.active ? styles.active : styles.inactive }, [\n\t\t\t\t\t\t\th('span', { style: styles.dot }),\n\t\t\t\t\t\t\tprimary.active ? t('common.status.active') : t('common.status.inactive'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\t// Siblings of the row button, not inside it: a button cannot hold buttons.\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t{ style: chips },\n\t\t\t\t\tgroup.entries.map((entry) => {\n\t\t\t\t\t\tconst name = entry.locale ?? t('templates.defaultChip');\n\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: entry.active ? chip : chipInactive,\n\t\t\t\t\t\t\t\t'aria-label': t('templates.list.openLocale', { type: group.type, locale: name }),\n\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\tonClick: () => emit('select-template', entry),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () =>\n\t\t\th('div', { style: styles.listContainer }, [\n\t\t\t\th(\n\t\t\t\t\t'div',\n\t\t\t\t\t{\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\t\tjustifyContent: 'space-between',\n\t\t\t\t\t\t\tgap: '16px',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('h1', { style: styles.listTitle }, t('templates.list.title')),\n\t\t\t\t\t\tprops.allowCreate\n\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\tstyle: newButton,\n\t\t\t\t\t\t\t\t\t\tonClick: () =>\n\t\t\t\t\t\t\t\t\t\t\temit('create-template', {\n\t\t\t\t\t\t\t\t\t\t\t\tlocales: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t...new Set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemplates.value\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map((tpl) => tpl.locale)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter((l): l is string => !!l),\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tt('templates.list.newTemplate'),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\th('p', { style: styles.hint }, t('templates.list.hint')),\n\t\t\t\tisLoading.value\n\t\t\t\t\t? h('p', { style: styles.status }, t('templates.list.loading'))\n\t\t\t\t\t: error.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, error.value.explanation)\n\t\t\t\t\t\t: h('ul', { style: styles.list }, groupTemplatesByType(templates.value).map(renderRow)),\n\t\t\t]);\n\t},\n});\n"],"mappings":"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","names":["import_client","import_vue","import_client","import_vue_courier_admin","import_vue"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/screens/TemplateCreateScreen.ts","../src/styles.ts","../src/screens/TemplateEditorScreen.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["export { TemplateCreateScreen, TemplateEditorScreen, TemplateListScreen } from './screens';\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tISetTemplateInput,\n} from '@fonderie/client';\nimport { createAdminT, FonderieApiError } from '@fonderie/client';\nimport { useTemplatePreview } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { computed, defineComponent, h, onMounted, ref, watch } from 'vue';\nimport { styles } from '../styles';\n\nconst TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;\nconst LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;\n// Variables the layout injects — never sample values, as in the editor.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\nconst PREVIEW_DEBOUNCE_MS = 500;\nconst notice = {\n\tfontSize: '13px',\n\tcolor: 'var(--fonderie-text,#171717)',\n\tbackground: 'color-mix(in srgb, var(--fonderie-warning,#f5a623) 16%, transparent)',\n\tborderRadius: '6px',\n\tpadding: '8px 12px',\n\tmargin: '12px 0 0',\n};\n\n// Creating is its own screen: the editor loads an existing row, and a new\n// template or locale has none yet. Once saved, the editor takes over.\nexport const TemplateCreateScreen = defineComponent({\n\tname: 'FonderieTemplateCreateScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/**\n\t\t * Given ⇒ add a LOCALE of this existing template: the type is fixed and the\n\t\t * form starts from its default-locale copy. Omitted ⇒ a brand-new template\n\t\t * type (one the app sends that has no stored copy yet).\n\t\t */\n\t\ttype: { type: String, default: undefined },\n\t\t/** Locales already in use, offered as suggestions. */\n\t\tlocales: { type: Array as PropType<string[]>, default: () => [] },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/** What was created, so the caller can open it in the editor. */\n\t\tcreated: (_created: { type: string; locale: string | null }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst addingLocale = props.type !== undefined;\n\t\tconst newType = ref('');\n\t\tconst targetLocale = ref('');\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst error = ref<string | null>(null);\n\t\tconst busy = ref(false);\n\t\t// The default copy this locale started from, to flag fields not yet translated.\n\t\tconst source = ref<{ subject: string; html: string; text: string } | null>(null);\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Each variable renders as its own name, so the preview shows where it\n\t\t// lands. Learned from the server's answer, not re-parsed here.\n\t\tlet variables: string[] = [];\n\t\t// `tr`, not `t`: submit() uses `t` for the template type.\n\t\tconst tr = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\t// A new locale starts from the default copy, so translating is editing.\n\t\tonMounted(() => {\n\t\t\tif (!props.type) return;\n\t\t\tprops.client\n\t\t\t\t.getTemplate(props.type, null)\n\t\t\t\t.then(({ result }) => {\n\t\t\t\t\tsubject.value = result.subject ?? '';\n\t\t\t\t\thtml.value = result.html ?? '';\n\t\t\t\t\ttext.value = result.text;\n\t\t\t\t\tsource.value = {\n\t\t\t\t\t\tsubject: result.subject ?? '',\n\t\t\t\t\t\thtml: result.html ?? '',\n\t\t\t\t\t\ttext: result.text,\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t\t.catch(() => undefined);\n\t\t});\n\n\t\t// Live preview, as in the editor: translating is where it matters most — a\n\t\t// half-translated email looks finished in a textarea and wrong in the render.\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([newType, targetLocale, subject, html, text], () => {\n\t\t\tclearTimeout(timer);\n\t\t\tconst type = addingLocale ? (props.type as string) : newType.value.trim();\n\t\t\tconst l = targetLocale.value.trim();\n\t\t\tif (!TYPE_RE.test(type) || !text.value.trim()) return;\n\t\t\ttimer = setTimeout(async () => {\n\t\t\t\tconst input = {\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t};\n\t\t\t\tconst render = () =>\n\t\t\t\t\trenderPreview(\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\t{ ...input, data: Object.fromEntries(variables.map((v) => [v, v])) },\n\t\t\t\t\t\tLOCALE_RE.test(l) ? l : null,\n\t\t\t\t\t);\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await render();\n\t\t\t\t\tconst used = result.variables.filter((v) => !IMPLICIT.has(v));\n\t\t\t\t\t// A variable not seen before rendered empty: render once more with it.\n\t\t\t\t\tif (used.some((v) => !variables.includes(v))) {\n\t\t\t\t\t\tvariables = used;\n\t\t\t\t\t\tawait render();\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Shown through previewError.\n\t\t\t\t}\n\t\t\t}, PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\tconst untranslated = computed(() => {\n\t\t\tconst src = source.value;\n\t\t\tif (!src) return [];\n\t\t\treturn [\n\t\t\t\tsubject.value && subject.value === src.subject ? tr('templates.subject') : null,\n\t\t\t\thtml.value && html.value === src.html ? tr('templates.htmlBody') : null,\n\t\t\t\ttext.value === src.text ? tr('templates.textBody') : null,\n\t\t\t].filter((f): f is string => f !== null);\n\t\t});\n\n\t\tasync function submit(e: Event) {\n\t\t\te.preventDefault();\n\t\t\terror.value = null;\n\t\t\tconst t = addingLocale ? (props.type as string) : newType.value.trim();\n\t\t\tconst l = targetLocale.value.trim() || null;\n\t\t\tif (!TYPE_RE.test(t)) {\n\t\t\t\terror.value = tr('templates.create.errorType');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (addingLocale && !l) {\n\t\t\t\terror.value = tr('templates.create.errorLocaleRequired');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (l && !LOCALE_RE.test(l)) {\n\t\t\t\terror.value = tr('templates.create.errorLocale');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!text.value.trim()) {\n\t\t\t\terror.value = tr('templates.create.errorText');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbusy.value = true;\n\t\t\ttry {\n\t\t\t\t// Refuse to overwrite: creating an existing row would replace it.\n\t\t\t\tconst exists = await props.client.getTemplate(t, l).then(\n\t\t\t\t\t() => true,\n\t\t\t\t\t(err: unknown) => !(err instanceof FonderieApiError && err.status === 404),\n\t\t\t\t);\n\t\t\t\tif (exists) {\n\t\t\t\t\terror.value = l\n\t\t\t\t\t\t? tr('templates.create.existsLocale', { type: t, locale: l })\n\t\t\t\t\t\t: tr('templates.create.exists', { type: t });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: true };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tawait props.client.setTemplate(t, input, l);\n\t\t\t\temit('created', { type: t, locale: l });\n\t\t\t} catch (err) {\n\t\t\t\terror.value = err instanceof FonderieApiError ? err.explanation : String(err);\n\t\t\t} finally {\n\t\t\t\tbusy.value = false;\n\t\t\t}\n\t\t}\n\n\t\tconst field = (\n\t\t\tid: string,\n\t\t\tlabel: string,\n\t\t\tmodel: typeof subject,\n\t\t\topts: Record<string, unknown> = {},\n\t\t) => [\n\t\t\th('label', { style: styles.label, for: id }, label),\n\t\t\th(opts.textarea ? 'textarea' : 'input', {\n\t\t\t\tid,\n\t\t\t\tstyle: opts.textarea ? { ...styles.textarea, minHeight: opts.minHeight } : styles.input,\n\t\t\t\tvalue: model.value,\n\t\t\t\tautocomplete: 'off',\n\t\t\t\tspellcheck: false,\n\t\t\t\t...(opts.placeholder ? { placeholder: opts.placeholder } : {}),\n\t\t\t\t...(opts.list ? { list: opts.list } : {}),\n\t\t\t\tonInput: (ev: Event) => {\n\t\t\t\t\tmodel.value = (ev.target as HTMLInputElement).value;\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\n\t\treturn () =>\n\t\t\th('div', { style: styles.container }, [\n\t\t\t\th(\n\t\t\t\t\t'h1',\n\t\t\t\t\t{ style: styles.title },\n\t\t\t\t\taddingLocale\n\t\t\t\t\t\t? tr('templates.create.titleLocale', { type: props.type as string })\n\t\t\t\t\t\t: tr('templates.create.titleNew'),\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: { ...styles.meta, lineHeight: 1.5 } },\n\t\t\t\t\taddingLocale ? tr('templates.create.hintLocale') : tr('templates.create.hintNew'),\n\t\t\t\t),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\t\th('form', { style: styles.form, onSubmit: (ev: Event) => void submit(ev) }, [\n\t\t\t\t\t\t...(addingLocale\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: field('new-template-type', tr('templates.create.type'), newType, {\n\t\t\t\t\t\t\t\t\tplaceholder: 'weekly-digest',\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t...field(\n\t\t\t\t\t\t\t'new-template-locale',\n\t\t\t\t\t\t\taddingLocale ? tr('templates.create.locale') : tr('templates.create.localeOptional'),\n\t\t\t\t\t\t\ttargetLocale,\n\t\t\t\t\t\t\t{ placeholder: 'fr', list: 'new-template-locales' },\n\t\t\t\t\t\t),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'datalist',\n\t\t\t\t\t\t\t{ id: 'new-template-locales' },\n\t\t\t\t\t\t\t[...new Set(props.locales)].map((l) => h('option', { key: l, value: l })),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t...field('new-template-subject', tr('templates.subject'), subject),\n\t\t\t\t\t\t...field('new-template-html', tr('templates.htmlBody'), html, {\n\t\t\t\t\t\t\ttextarea: true,\n\t\t\t\t\t\t\tminHeight: '160px',\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t...field('new-template-text', tr('templates.textBody'), text, {\n\t\t\t\t\t\t\ttextarea: true,\n\t\t\t\t\t\t\tminHeight: '100px',\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tuntranslated.value.length > 0\n\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t'p',\n\t\t\t\t\t\t\t\t\t{ style: notice },\n\t\t\t\t\t\t\t\t\ttr('templates.create.untranslated', { fields: untranslated.value.join(', ') }),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\terror.value ? h('p', { style: styles.error, role: 'alert' }, error.value) : null,\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\tdisabled: busy.value,\n\t\t\t\t\t\t\t\tstyle: { ...styles.button, marginTop: '16px' },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbusy.value\n\t\t\t\t\t\t\t\t? tr('templates.create.creating')\n\t\t\t\t\t\t\t\t: addingLocale\n\t\t\t\t\t\t\t\t\t? tr('templates.create.submitLocale')\n\t\t\t\t\t\t\t\t\t: tr('templates.create.submitNew'),\n\t\t\t\t\t\t),\n\t\t\t\t\t]),\n\t\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\t\th('span', { style: styles.label }, tr('templates.editor.preview')),\n\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t\t\t\tisPreviewing.value ? tr('templates.editor.rendering') : tr('templates.editor.live'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin: operator-authored HTML must\n\t\t\t\t\t\t\t\t// never execute in the console's origin.\n\t\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\t\ttitle: tr('templates.editor.previewTitle'),\n\t\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t\t: h('p', { style: styles.meta }, tr('templates.editor.nothingRendered')),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t]);\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '8px 40px 64px', maxWidth: '1400px', boxSizing: 'border-box' },\n\t// Two columns, always: editor left, rendered result right. Stacking the\n\t// preview under a long form hid it below the fold.\n\tsplit: {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',\n\t\tgap: '24px',\n\t\talignItems: 'start',\n\t},\n\tcolumn: { minWidth: '0', display: 'flex', flexDirection: 'column' },\n\t// Pinned while the form scrolls, so the preview stays in view as you edit.\n\tpreviewColumn: {\n\t\tminWidth: '0',\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tposition: 'sticky',\n\t\ttop: '16px',\n\t},\n\tsaveRow: { display: 'flex', alignItems: 'center', gap: '12px', marginTop: '16px' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '8px 0 4px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\tsubtitle: {\n\t\tfontSize: '15px',\n\t\tfontWeight: 600,\n\t\tmargin: '0 0 10px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t},\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '20px' },\n\tstatus: { padding: '24px 0', color: 'var(--fonderie-text-muted,#5c5c5c)', fontSize: '13.5px' },\n\terror: {\n\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)',\n\t\tborderRadius: '6px',\n\t\tpadding: '8px 12px',\n\t\tmargin: '8px 0',\n\t\tfontSize: '13.5px',\n\t},\n\tlist: {\n\t\tlistStyle: 'none',\n\t\tpadding: '0',\n\t\tmargin: '0',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\toverflow: 'hidden',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '16px',\n\t\tpadding: '13px 16px',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily: 'inherit',\n\t},\n\ttype: {\n\t\tfontSize: '13px',\n\t\tfontWeight: 600,\n\t\tflex: '1',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tlocale: { fontSize: '12.5px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-accent-strong,#009767)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-accent-strong,#009767) 13%, transparent)',\n\t},\n\tinactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-text-muted,#5c5c5c) 10%, transparent)',\n\t},\n\tform: {\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tgap: '4px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\tpadding: '6px 20px 20px',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tlabel: { fontSize: '13px', fontWeight: 500, marginTop: '14px', marginBottom: '2px' },\n\tinput: {\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '13.5px',\n\t\tfontFamily: 'inherit',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t},\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '10px',\n\t\tfontSize: '13px',\n\t\tlineHeight: 1.55,\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\tcursor: 'pointer',\n\t},\n\tbuttonDisabled: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\topacity: 0.45,\n\t\tcursor: 'not-allowed',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '12px',\n\t\tpadding: '9px 16px',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '28px',\n\t\tboxSizing: 'border-box',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '12.5px',\n\t\tfontWeight: 500,\n\t\tfontFamily: 'inherit',\n\t\tcursor: 'pointer',\n\t},\n\t// Template list: matches @fonderie/vue-admin-screens' shell look with local\n\t// values — this package sits below the admin screens and cannot import them.\n\tlistContainer: { padding: '32px 40px 64px', maxWidth: '1160px', boxSizing: 'border-box' },\n\tlistTitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '0',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\thint: { fontSize: '13.5px', color: 'var(--fonderie-text-muted,#5c5c5c)', margin: '4px 0 24px' },\n\tdot: { width: '6px', height: '6px', borderRadius: '999px', background: 'currentColor' },\n};\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateEntry,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tcreateAdminT,\n\tformatAdminDate,\n\tgroupTemplatesByType,\n\tmissingTemplateLocales,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { computed, defineComponent, h, ref, watch } from 'vue';\n\nconst PREVIEW_DEBOUNCE_MS = 500;\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\n// One tab per locale of this email, underlined like a document's tabs.\nconst tab: CSSProperties = {\n\theight: '32px',\n\tpadding: '0 10px',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderBottom: '2px solid transparent',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\tfontSize: '13px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst tabSelected: CSSProperties = {\n\t...tab,\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontWeight: 600,\n\tborderBottomColor: 'var(--fonderie-text,#171717)',\n\tcursor: 'default',\n};\nconst tabInactive: CSSProperties = { ...tab, opacity: 0.55, textDecoration: 'line-through' };\nconst tabBar: CSSProperties = {\n\tdisplay: 'flex',\n\talignItems: 'flex-end',\n\tgap: '12px',\n\tborderBottom: '1px solid var(--fonderie-border,#e0e0e0)',\n\tmargin: '4px 0 12px',\n\tpaddingBottom: '6px',\n};\nconst tabs: CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: '4px', marginBottom: '-7px' };\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t\t/**\n\t\t * A built-in email's default-locale row (the list's `system` flag): it can\n\t\t * be edited and rolled back, never deleted — Delete is not offered.\n\t\t */\n\t\tsystem: { type: Boolean, default: false },\n\t\t/** Shows \"+ Add locale\" (emits add-locale). */\n\t\tallowAddLocale: { type: Boolean, default: false },\n\t\t/**\n\t\t * Shows a tab per locale this email exists in (emits select-locale).\n\t\t * Unsaved edits are confirmed before switching away.\n\t\t */\n\t\tlocaleTabs: { type: Boolean, default: false },\n\t\t/** The console language (`locale` is the template's); defaults to English. */\n\t\tuiLocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t\t/** The template was deleted and no longer exists. */\n\t\tdeleted: () => true,\n\t\t/**\n\t\t * Create a translation of this template. `locales` are the ones the app\n\t\t * uses elsewhere that this email lacks — suggest them first.\n\t\t */\n\t\t'add-locale': (_type: string, _context: { locales: string[] }) => true,\n\t\t/** Open another locale of this email. */\n\t\t'select-locale': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.uiLocale)(key, params);\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { templates, saveTemplate, removeTemplate } = useTemplates(props.client);\n\t\t// This email's locales, for the tabs. The list is already fetched for saves.\n\t\tconst siblings = computed(\n\t\t\t() => groupTemplatesByType(templates.value).find((g) => g.type === props.type)?.entries ?? [],\n\t\t);\n\t\tconst isDeleting = ref(false);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<AdminMessageKey | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'templates.editor.sampleNotObject';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'templates.editor.sampleInvalid';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// The preview is always live: it renders once the template loads, then\n\t\t// again PREVIEW_DEBOUNCE_MS after the last edit to the content or the sample\n\t\t// data — debounced, so typing a paragraph costs one request, not one per key.\n\t\tlet previewTimer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([template, subject, html, text, sampleJson], () => {\n\t\t\tif (!template.value) return;\n\t\t\tclearTimeout(previewTimer);\n\t\t\tpreviewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\t// Saving what is already stored would only mint an identical version (the\n\t\t// server treats it as a no-op anyway), so Save waits for a real change.\n\t\tconst dirty = computed(() => {\n\t\t\tconst tpl = template.value;\n\t\t\treturn (\n\t\t\t\t!!tpl &&\n\t\t\t\t(subject.value !== (tpl.subject ?? '') ||\n\t\t\t\t\thtml.value !== (tpl.html ?? '') ||\n\t\t\t\t\ttext.value !== tpl.text ||\n\t\t\t\t\tactive.value !== tpl.active)\n\t\t\t);\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\t// Leaving a locale with unsaved edits asks first: they would be lost.\n\t\tconst leave = () => !dirty.value || window.confirm(t('templates.editor.discardChanges'));\n\n\t\tfunction renderTabBar() {\n\t\t\tif (!props.localeTabs && !props.allowAddLocale) return null;\n\t\t\treturn h('div', { style: tabBar }, [\n\t\t\t\tprops.localeTabs\n\t\t\t\t\t? // Each tab opens another stored row, so this is navigation, not an\n\t\t\t\t\t\t// ARIA tablist: plain buttons, the open one marked aria-current.\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'nav',\n\t\t\t\t\t\t\t{ 'aria-label': t('templates.editor.locales'), style: tabs },\n\t\t\t\t\t\t\tsiblings.value.map((entry) => {\n\t\t\t\t\t\t\t\tconst selected = entry.locale === (props.locale ?? null);\n\t\t\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t'aria-current': selected ? 'true' : undefined,\n\t\t\t\t\t\t\t\t\t\tstyle: selected ? tabSelected : entry.active ? tab : tabInactive,\n\t\t\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\tif (!selected && leave()) emit('select-locale', entry);\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tentry.locale ?? t('templates.defaultChip'),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t\tprops.allowAddLocale\n\t\t\t\t\t? h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: { ...styles.rollbackButton, marginLeft: 'auto' },\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tif (leave())\n\t\t\t\t\t\t\t\t\t\temit('add-locale', props.type, {\n\t\t\t\t\t\t\t\t\t\t\tlocales: missingTemplateLocales(templates.value, props.type),\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tt('templates.editor.addLocale'),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t}\n\n\t\tasync function handleDelete() {\n\t\t\tconst message = props.locale\n\t\t\t\t? t('templates.editor.confirmDeleteLocale', { locale: props.locale, type: props.type })\n\t\t\t\t: t('templates.editor.confirmDelete', { type: props.type });\n\t\t\tif (!window.confirm(message)) return;\n\t\t\tisDeleting.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tawait removeTemplate(props.type, props.locale);\n\t\t\t\temit('deleted');\n\t\t\t} catch (err) {\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisDeleting.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? t('templates.editor.unknownActor')} — ${formatAdminDate(rev.createdAt, props.uiLocale)}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\tt('templates.editor.rollBack'),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, t('templates.editor.loading'));\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\trenderTabBar(),\n\t\t\t\th('p', { style: styles.meta }, [\n\t\t\t\t\th('strong', props.locale ?? t('templates.defaultLocale')),\n\t\t\t\t\t` · v${template.value?.version ?? 1}`,\n\t\t\t\t\tprops.system ? ` · ${t('templates.editor.builtInNote')}` : '',\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, t('templates.subject')),\n\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, t('templates.htmlBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, t('templates.textBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tt('templates.editor.active'),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\tsaveError.value?.reason === 'VERSION_CONFLICT'\n\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, [\n\t\t\t\t\t\t\t\t\t\t`${t('templates.editor.conflict')} `,\n\t\t\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsaveError.value = null;\n\t\t\t\t\t\t\t\t\t\t\t\t\tvoid refresh();\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tt('common.reload'),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t\t: saveError.value\n\t\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\th('div', { style: styles.saveRow }, [\n\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\t\t\tdisabled: isSaving.value || !dirty.value,\n\t\t\t\t\t\t\t\t\t\tstyle: dirty.value ? styles.button : styles.buttonDisabled,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tisSaving.value ? t('common.saving') : t('common.save'),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t!dirty.value && !isSaving.value\n\t\t\t\t\t\t\t\t\t? h('span', { style: styles.meta }, t('templates.editor.noChanges'))\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t!props.system\n\t\t\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled: isDeleting.value,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => void handleDelete(),\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t...styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\t\theight: '36px',\n\t\t\t\t\t\t\t\t\t\t\t\t\tmarginLeft: 'auto',\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderColor:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)',\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tisDeleting.value ? t('common.deleting') : t('common.delete'),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'label',\n\t\t\t\t\t\t\t{ style: styles.label, for: 'template-sample' },\n\t\t\t\t\t\t\tt('templates.editor.sampleData'),\n\t\t\t\t\t\t),\n\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t\tspellcheck: false,\n\t\t\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tsampleError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, t(sampleError.value))\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t]),\n\t\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\t\th('span', { style: styles.label }, t('templates.editor.preview')),\n\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t\t\t\tisPreviewing.value ? t('templates.editor.rendering') : t('templates.editor.live'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\t\ttitle: t('templates.editor.previewTitle'),\n\t\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t\t: h('p', { style: styles.meta }, t('templates.editor.nothingRendered')),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, t('templates.editor.history')),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tITemplateEntry,\n} from '@fonderie/client';\nimport { createAdminT, groupTemplatesByType } from '@fonderie/client';\nimport type { ITemplateGroup } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nconst builtIn: CSSProperties = {\n\tfontSize: '11px',\n\tfontWeight: 500,\n\tpadding: '1px 7px',\n\tborderRadius: '999px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n};\n// One per locale the email exists in. Monospace: they are language tags.\nconst chip: CSSProperties = {\n\theight: '24px',\n\tboxSizing: 'border-box',\n\tpadding: '0 8px',\n\tborderRadius: '6px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tbackground: 'var(--fonderie-surface,#fff)',\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontSize: '12px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst chipInactive: CSSProperties = { ...chip, opacity: 0.5, textDecoration: 'line-through' };\nconst row: CSSProperties = {\n\t...styles.row,\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '8px',\n\tpaddingRight: '16px',\n};\nconst rowButton: CSSProperties = { ...styles.rowButton, width: 'auto', flex: '1', minWidth: '0' };\nconst chips: CSSProperties = {\n\tdisplay: 'flex',\n\tflexWrap: 'wrap',\n\tjustifyContent: 'flex-end',\n\tgap: '6px',\n};\nconst newButton: CSSProperties = {\n\tdisplay: 'inline-flex',\n\talignItems: 'center',\n\theight: '32px',\n\tboxSizing: 'border-box',\n\tborderRadius: '6px',\n\tpadding: '0 12px',\n\tfontSize: '13px',\n\tfontWeight: 500,\n\tfontFamily: 'inherit',\n\tcursor: 'pointer',\n\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\tcolor: 'var(--fonderie-surface,#fff)',\n\tborder: '1px solid var(--fonderie-text,#171717)',\n};\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/** Shows a \"New template\" button (emits create-template). */\n\t\tallowCreate: { type: Boolean, default: false },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/**\n\t\t * The whole row — type AND locale, and whether it is built-in. One row\n\t\t * per email: the row opens the default locale, a locale chip that locale.\n\t\t */\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t\t/** Receives the locales in use, to suggest. */\n\t\t'create-template': (_context: { locales: string[] }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\tfunction renderRow(group: ITemplateGroup) {\n\t\t\tconst primary: ITemplateEntry = group.primary;\n\t\t\treturn h('li', { key: group.type, style: row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', primary),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, group.type),\n\t\t\t\t\t\tgroup.system ? h('span', { style: builtIn }, t('templates.builtInBadge')) : null,\n\t\t\t\t\t\th('span', { style: primary.active ? styles.active : styles.inactive }, [\n\t\t\t\t\t\t\th('span', { style: styles.dot }),\n\t\t\t\t\t\t\tprimary.active ? t('common.status.active') : t('common.status.inactive'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\t// Siblings of the row button, not inside it: a button cannot hold buttons.\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t{ style: chips },\n\t\t\t\t\tgroup.entries.map((entry) => {\n\t\t\t\t\t\tconst name = entry.locale ?? t('templates.defaultChip');\n\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: entry.active ? chip : chipInactive,\n\t\t\t\t\t\t\t\t'aria-label': t('templates.list.openLocale', { type: group.type, locale: name }),\n\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\tonClick: () => emit('select-template', entry),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () =>\n\t\t\th('div', { style: styles.listContainer }, [\n\t\t\t\th(\n\t\t\t\t\t'div',\n\t\t\t\t\t{\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\t\tjustifyContent: 'space-between',\n\t\t\t\t\t\t\tgap: '16px',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('h1', { style: styles.listTitle }, t('templates.list.title')),\n\t\t\t\t\t\tprops.allowCreate\n\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\tstyle: newButton,\n\t\t\t\t\t\t\t\t\t\tonClick: () =>\n\t\t\t\t\t\t\t\t\t\t\temit('create-template', {\n\t\t\t\t\t\t\t\t\t\t\t\tlocales: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t...new Set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemplates.value\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map((tpl) => tpl.locale)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter((l): l is string => !!l),\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tt('templates.list.newTemplate'),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\th('p', { style: styles.hint }, t('templates.list.hint')),\n\t\t\t\tisLoading.value\n\t\t\t\t\t? h('p', { style: styles.status }, t('templates.list.loading'))\n\t\t\t\t\t: error.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, error.value.explanation)\n\t\t\t\t\t\t: h('ul', { style: styles.list }, groupTemplatesByType(templates.value).map(renderRow)),\n\t\t\t]);\n\t},\n});\n"],"mappings":"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","names":["import_client","import_vue_courier_admin","import_vue","PREVIEW_DEBOUNCE_MS","IMPLICIT","import_client","import_vue_courier_admin","import_vue"]}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/screens/TemplateCreateScreen.ts
|
|
2
2
|
import { createAdminT, FonderieApiError } from "@fonderie/client";
|
|
3
|
-
import {
|
|
3
|
+
import { useTemplatePreview } from "@fonderie/vue-courier-admin";
|
|
4
|
+
import { computed, defineComponent, h, onMounted, ref, watch } from "vue";
|
|
4
5
|
|
|
5
6
|
// src/styles.ts
|
|
6
7
|
var styles = {
|
|
@@ -241,6 +242,16 @@ var styles = {
|
|
|
241
242
|
// src/screens/TemplateCreateScreen.ts
|
|
242
243
|
var TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;
|
|
243
244
|
var LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
245
|
+
var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
246
|
+
var PREVIEW_DEBOUNCE_MS = 500;
|
|
247
|
+
var notice = {
|
|
248
|
+
fontSize: "13px",
|
|
249
|
+
color: "var(--fonderie-text,#171717)",
|
|
250
|
+
background: "color-mix(in srgb, var(--fonderie-warning,#f5a623) 16%, transparent)",
|
|
251
|
+
borderRadius: "6px",
|
|
252
|
+
padding: "8px 12px",
|
|
253
|
+
margin: "12px 0 0"
|
|
254
|
+
};
|
|
244
255
|
var TemplateCreateScreen = defineComponent({
|
|
245
256
|
name: "FonderieTemplateCreateScreen",
|
|
246
257
|
props: {
|
|
@@ -269,6 +280,14 @@ var TemplateCreateScreen = defineComponent({
|
|
|
269
280
|
const text = ref("");
|
|
270
281
|
const error = ref(null);
|
|
271
282
|
const busy = ref(false);
|
|
283
|
+
const source = ref(null);
|
|
284
|
+
const {
|
|
285
|
+
preview,
|
|
286
|
+
isPreviewing,
|
|
287
|
+
error: previewError,
|
|
288
|
+
renderPreview
|
|
289
|
+
} = useTemplatePreview(props.client);
|
|
290
|
+
let variables = [];
|
|
272
291
|
const tr = (key, params) => createAdminT(props.locale)(key, params);
|
|
273
292
|
onMounted(() => {
|
|
274
293
|
if (!props.type) return;
|
|
@@ -276,8 +295,50 @@ var TemplateCreateScreen = defineComponent({
|
|
|
276
295
|
subject.value = result.subject ?? "";
|
|
277
296
|
html.value = result.html ?? "";
|
|
278
297
|
text.value = result.text;
|
|
298
|
+
source.value = {
|
|
299
|
+
subject: result.subject ?? "",
|
|
300
|
+
html: result.html ?? "",
|
|
301
|
+
text: result.text
|
|
302
|
+
};
|
|
279
303
|
}).catch(() => void 0);
|
|
280
304
|
});
|
|
305
|
+
let timer;
|
|
306
|
+
watch([newType, targetLocale, subject, html, text], () => {
|
|
307
|
+
clearTimeout(timer);
|
|
308
|
+
const type = addingLocale ? props.type : newType.value.trim();
|
|
309
|
+
const l = targetLocale.value.trim();
|
|
310
|
+
if (!TYPE_RE.test(type) || !text.value.trim()) return;
|
|
311
|
+
timer = setTimeout(async () => {
|
|
312
|
+
const input = {
|
|
313
|
+
text: text.value,
|
|
314
|
+
...subject.value ? { subject: subject.value } : {},
|
|
315
|
+
...html.value ? { html: html.value } : {}
|
|
316
|
+
};
|
|
317
|
+
const render = () => renderPreview(
|
|
318
|
+
type,
|
|
319
|
+
{ ...input, data: Object.fromEntries(variables.map((v) => [v, v])) },
|
|
320
|
+
LOCALE_RE.test(l) ? l : null
|
|
321
|
+
);
|
|
322
|
+
try {
|
|
323
|
+
const result = await render();
|
|
324
|
+
const used = result.variables.filter((v) => !IMPLICIT.has(v));
|
|
325
|
+
if (used.some((v) => !variables.includes(v))) {
|
|
326
|
+
variables = used;
|
|
327
|
+
await render();
|
|
328
|
+
}
|
|
329
|
+
} catch {
|
|
330
|
+
}
|
|
331
|
+
}, PREVIEW_DEBOUNCE_MS);
|
|
332
|
+
});
|
|
333
|
+
const untranslated = computed(() => {
|
|
334
|
+
const src = source.value;
|
|
335
|
+
if (!src) return [];
|
|
336
|
+
return [
|
|
337
|
+
subject.value && subject.value === src.subject ? tr("templates.subject") : null,
|
|
338
|
+
html.value && html.value === src.html ? tr("templates.htmlBody") : null,
|
|
339
|
+
text.value === src.text ? tr("templates.textBody") : null
|
|
340
|
+
].filter((f) => f !== null);
|
|
341
|
+
});
|
|
281
342
|
async function submit(e) {
|
|
282
343
|
e.preventDefault();
|
|
283
344
|
error.value = null;
|
|
@@ -335,7 +396,7 @@ var TemplateCreateScreen = defineComponent({
|
|
|
335
396
|
}
|
|
336
397
|
})
|
|
337
398
|
];
|
|
338
|
-
return () => h("div", { style:
|
|
399
|
+
return () => h("div", { style: styles.container }, [
|
|
339
400
|
h(
|
|
340
401
|
"h1",
|
|
341
402
|
{ style: styles.title },
|
|
@@ -346,35 +407,69 @@ var TemplateCreateScreen = defineComponent({
|
|
|
346
407
|
{ style: { ...styles.meta, lineHeight: 1.5 } },
|
|
347
408
|
addingLocale ? tr("templates.create.hintLocale") : tr("templates.create.hintNew")
|
|
348
409
|
),
|
|
349
|
-
h("
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
"
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
410
|
+
h("div", { style: styles.split }, [
|
|
411
|
+
h("form", { style: styles.form, onSubmit: (ev) => void submit(ev) }, [
|
|
412
|
+
...addingLocale ? [] : field("new-template-type", tr("templates.create.type"), newType, {
|
|
413
|
+
placeholder: "weekly-digest"
|
|
414
|
+
}),
|
|
415
|
+
...field(
|
|
416
|
+
"new-template-locale",
|
|
417
|
+
addingLocale ? tr("templates.create.locale") : tr("templates.create.localeOptional"),
|
|
418
|
+
targetLocale,
|
|
419
|
+
{ placeholder: "fr", list: "new-template-locales" }
|
|
420
|
+
),
|
|
421
|
+
h(
|
|
422
|
+
"datalist",
|
|
423
|
+
{ id: "new-template-locales" },
|
|
424
|
+
[...new Set(props.locales)].map((l) => h("option", { key: l, value: l }))
|
|
425
|
+
),
|
|
426
|
+
...field("new-template-subject", tr("templates.subject"), subject),
|
|
427
|
+
...field("new-template-html", tr("templates.htmlBody"), html, {
|
|
428
|
+
textarea: true,
|
|
429
|
+
minHeight: "160px"
|
|
430
|
+
}),
|
|
431
|
+
...field("new-template-text", tr("templates.textBody"), text, {
|
|
432
|
+
textarea: true,
|
|
433
|
+
minHeight: "100px"
|
|
434
|
+
}),
|
|
435
|
+
untranslated.value.length > 0 ? h(
|
|
436
|
+
"p",
|
|
437
|
+
{ style: notice },
|
|
438
|
+
tr("templates.create.untranslated", { fields: untranslated.value.join(", ") })
|
|
439
|
+
) : null,
|
|
440
|
+
error.value ? h("p", { style: styles.error, role: "alert" }, error.value) : null,
|
|
441
|
+
h(
|
|
442
|
+
"button",
|
|
443
|
+
{
|
|
444
|
+
type: "submit",
|
|
445
|
+
disabled: busy.value,
|
|
446
|
+
style: { ...styles.button, marginTop: "16px" }
|
|
447
|
+
},
|
|
448
|
+
busy.value ? tr("templates.create.creating") : addingLocale ? tr("templates.create.submitLocale") : tr("templates.create.submitNew")
|
|
449
|
+
)
|
|
450
|
+
]),
|
|
451
|
+
h("div", { style: styles.previewColumn }, [
|
|
452
|
+
h("div", { style: styles.previewHeader }, [
|
|
453
|
+
h("span", { style: styles.label }, tr("templates.editor.preview")),
|
|
454
|
+
h(
|
|
455
|
+
"span",
|
|
456
|
+
{ style: styles.meta },
|
|
457
|
+
isPreviewing.value ? tr("templates.editor.rendering") : tr("templates.editor.live")
|
|
458
|
+
)
|
|
459
|
+
]),
|
|
460
|
+
previewError.value ? h("p", { style: styles.error, role: "alert" }, previewError.value.explanation) : null,
|
|
461
|
+
preview.value?.subject ? h("p", { style: styles.previewSubject }, preview.value.subject) : null,
|
|
462
|
+
preview.value?.html ? (
|
|
463
|
+
// sandbox= — no scripts, no same-origin: operator-authored HTML must
|
|
464
|
+
// never execute in the console's origin.
|
|
465
|
+
h("iframe", {
|
|
466
|
+
title: tr("templates.editor.previewTitle"),
|
|
467
|
+
style: styles.previewFrame,
|
|
468
|
+
sandbox: "",
|
|
469
|
+
srcdoc: preview.value.html
|
|
470
|
+
})
|
|
471
|
+
) : preview.value ? h("pre", { style: styles.previewText }, preview.value.text) : h("p", { style: styles.meta }, tr("templates.editor.nothingRendered"))
|
|
472
|
+
])
|
|
378
473
|
])
|
|
379
474
|
]);
|
|
380
475
|
}
|
|
@@ -389,13 +484,13 @@ import {
|
|
|
389
484
|
} from "@fonderie/client";
|
|
390
485
|
import {
|
|
391
486
|
useTemplate,
|
|
392
|
-
useTemplatePreview,
|
|
487
|
+
useTemplatePreview as useTemplatePreview2,
|
|
393
488
|
useTemplateRevisions,
|
|
394
489
|
useTemplates
|
|
395
490
|
} from "@fonderie/vue-courier-admin";
|
|
396
|
-
import { computed, defineComponent as defineComponent2, h as h2, ref as ref2, watch } from "vue";
|
|
397
|
-
var
|
|
398
|
-
var
|
|
491
|
+
import { computed as computed2, defineComponent as defineComponent2, h as h2, ref as ref2, watch as watch2 } from "vue";
|
|
492
|
+
var PREVIEW_DEBOUNCE_MS2 = 500;
|
|
493
|
+
var IMPLICIT2 = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
399
494
|
var tab = {
|
|
400
495
|
height: "32px",
|
|
401
496
|
padding: "0 10px",
|
|
@@ -465,7 +560,7 @@ var TemplateEditorScreen = defineComponent2({
|
|
|
465
560
|
props.locale
|
|
466
561
|
);
|
|
467
562
|
const { templates, saveTemplate, removeTemplate } = useTemplates(props.client);
|
|
468
|
-
const siblings =
|
|
563
|
+
const siblings = computed2(
|
|
469
564
|
() => groupTemplatesByType(templates.value).find((g) => g.type === props.type)?.entries ?? []
|
|
470
565
|
);
|
|
471
566
|
const isDeleting = ref2(false);
|
|
@@ -476,7 +571,7 @@ var TemplateEditorScreen = defineComponent2({
|
|
|
476
571
|
const html = ref2("");
|
|
477
572
|
const text = ref2("");
|
|
478
573
|
const active = ref2(true);
|
|
479
|
-
|
|
574
|
+
watch2(template, (tpl) => {
|
|
480
575
|
if (!tpl) return;
|
|
481
576
|
subject.value = tpl.subject ?? "";
|
|
482
577
|
html.value = tpl.html ?? "";
|
|
@@ -488,7 +583,7 @@ var TemplateEditorScreen = defineComponent2({
|
|
|
488
583
|
isPreviewing,
|
|
489
584
|
error: previewError,
|
|
490
585
|
renderPreview
|
|
491
|
-
} =
|
|
586
|
+
} = useTemplatePreview2(props.client);
|
|
492
587
|
const sampleJson = ref2("{}");
|
|
493
588
|
const sampleError = ref2(null);
|
|
494
589
|
async function run() {
|
|
@@ -515,7 +610,7 @@ var TemplateEditorScreen = defineComponent2({
|
|
|
515
610
|
},
|
|
516
611
|
props.locale
|
|
517
612
|
);
|
|
518
|
-
const missing = result.variables.filter((v) => !
|
|
613
|
+
const missing = result.variables.filter((v) => !IMPLICIT2.has(v) && !(v in data));
|
|
519
614
|
if (missing.length > 0) {
|
|
520
615
|
sampleJson.value = JSON.stringify(
|
|
521
616
|
{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },
|
|
@@ -525,12 +620,12 @@ var TemplateEditorScreen = defineComponent2({
|
|
|
525
620
|
}
|
|
526
621
|
}
|
|
527
622
|
let previewTimer;
|
|
528
|
-
|
|
623
|
+
watch2([template, subject, html, text, sampleJson], () => {
|
|
529
624
|
if (!template.value) return;
|
|
530
625
|
clearTimeout(previewTimer);
|
|
531
|
-
previewTimer = setTimeout(() => void run(),
|
|
626
|
+
previewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS2);
|
|
532
627
|
});
|
|
533
|
-
const dirty =
|
|
628
|
+
const dirty = computed2(() => {
|
|
534
629
|
const tpl = template.value;
|
|
535
630
|
return !!tpl && (subject.value !== (tpl.subject ?? "") || html.value !== (tpl.html ?? "") || text.value !== tpl.text || active.value !== tpl.active);
|
|
536
631
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/screens/TemplateCreateScreen.ts","../src/styles.ts","../src/screens/TemplateEditorScreen.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tISetTemplateInput,\n} from '@fonderie/client';\nimport { createAdminT, FonderieApiError } from '@fonderie/client';\nimport type { PropType } from 'vue';\nimport { defineComponent, h, onMounted, ref } from 'vue';\nimport { styles } from '../styles';\n\nconst TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;\nconst LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;\n\n// Creating is its own screen: the editor loads an existing row, and a new\n// template or locale has none yet. Once saved, the editor takes over.\nexport const TemplateCreateScreen = defineComponent({\n\tname: 'FonderieTemplateCreateScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/**\n\t\t * Given ⇒ add a LOCALE of this existing template: the type is fixed and the\n\t\t * form starts from its default-locale copy. Omitted ⇒ a brand-new template\n\t\t * type (one the app sends that has no stored copy yet).\n\t\t */\n\t\ttype: { type: String, default: undefined },\n\t\t/** Locales already in use, offered as suggestions. */\n\t\tlocales: { type: Array as PropType<string[]>, default: () => [] },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/** What was created, so the caller can open it in the editor. */\n\t\tcreated: (_created: { type: string; locale: string | null }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst addingLocale = props.type !== undefined;\n\t\tconst newType = ref('');\n\t\tconst targetLocale = ref('');\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst error = ref<string | null>(null);\n\t\tconst busy = ref(false);\n\t\t// `tr`, not `t`: submit() uses `t` for the template type.\n\t\tconst tr = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\t// A new locale starts from the default copy, so translating is editing.\n\t\tonMounted(() => {\n\t\t\tif (!props.type) return;\n\t\t\tprops.client\n\t\t\t\t.getTemplate(props.type, null)\n\t\t\t\t.then(({ result }) => {\n\t\t\t\t\tsubject.value = result.subject ?? '';\n\t\t\t\t\thtml.value = result.html ?? '';\n\t\t\t\t\ttext.value = result.text;\n\t\t\t\t})\n\t\t\t\t.catch(() => undefined);\n\t\t});\n\n\t\tasync function submit(e: Event) {\n\t\t\te.preventDefault();\n\t\t\terror.value = null;\n\t\t\tconst t = addingLocale ? (props.type as string) : newType.value.trim();\n\t\t\tconst l = targetLocale.value.trim() || null;\n\t\t\tif (!TYPE_RE.test(t)) {\n\t\t\t\terror.value = tr('templates.create.errorType');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (addingLocale && !l) {\n\t\t\t\terror.value = tr('templates.create.errorLocaleRequired');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (l && !LOCALE_RE.test(l)) {\n\t\t\t\terror.value = tr('templates.create.errorLocale');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!text.value.trim()) {\n\t\t\t\terror.value = tr('templates.create.errorText');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbusy.value = true;\n\t\t\ttry {\n\t\t\t\t// Refuse to overwrite: creating an existing row would replace it.\n\t\t\t\tconst exists = await props.client.getTemplate(t, l).then(\n\t\t\t\t\t() => true,\n\t\t\t\t\t(err: unknown) => !(err instanceof FonderieApiError && err.status === 404),\n\t\t\t\t);\n\t\t\t\tif (exists) {\n\t\t\t\t\terror.value = l\n\t\t\t\t\t\t? tr('templates.create.existsLocale', { type: t, locale: l })\n\t\t\t\t\t\t: tr('templates.create.exists', { type: t });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: true };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tawait props.client.setTemplate(t, input, l);\n\t\t\t\temit('created', { type: t, locale: l });\n\t\t\t} catch (err) {\n\t\t\t\terror.value = err instanceof FonderieApiError ? err.explanation : String(err);\n\t\t\t} finally {\n\t\t\t\tbusy.value = false;\n\t\t\t}\n\t\t}\n\n\t\tconst field = (\n\t\t\tid: string,\n\t\t\tlabel: string,\n\t\t\tmodel: typeof subject,\n\t\t\topts: Record<string, unknown> = {},\n\t\t) => [\n\t\t\th('label', { style: styles.label, for: id }, label),\n\t\t\th(opts.textarea ? 'textarea' : 'input', {\n\t\t\t\tid,\n\t\t\t\tstyle: opts.textarea ? { ...styles.textarea, minHeight: opts.minHeight } : styles.input,\n\t\t\t\tvalue: model.value,\n\t\t\t\tautocomplete: 'off',\n\t\t\t\tspellcheck: false,\n\t\t\t\t...(opts.placeholder ? { placeholder: opts.placeholder } : {}),\n\t\t\t\t...(opts.list ? { list: opts.list } : {}),\n\t\t\t\tonInput: (ev: Event) => {\n\t\t\t\t\tmodel.value = (ev.target as HTMLInputElement).value;\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\n\t\treturn () =>\n\t\t\th('div', { style: { ...styles.container, maxWidth: '760px' } }, [\n\t\t\t\th(\n\t\t\t\t\t'h1',\n\t\t\t\t\t{ style: styles.title },\n\t\t\t\t\taddingLocale\n\t\t\t\t\t\t? tr('templates.create.titleLocale', { type: props.type as string })\n\t\t\t\t\t\t: tr('templates.create.titleNew'),\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: { ...styles.meta, lineHeight: 1.5 } },\n\t\t\t\t\taddingLocale\n\t\t\t\t\t\t? tr('templates.create.hintLocale')\n\t\t\t\t\t\t: tr('templates.create.hintNew'),\n\t\t\t\t),\n\t\t\t\th('form', { style: styles.form, onSubmit: (ev: Event) => void submit(ev) }, [\n\t\t\t\t\t...(addingLocale\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: field('new-template-type', tr('templates.create.type'), newType, { placeholder: 'weekly-digest' })),\n\t\t\t\t\t...field(\n\t\t\t\t\t\t'new-template-locale',\n\t\t\t\t\t\taddingLocale ? tr('templates.create.locale') : tr('templates.create.localeOptional'),\n\t\t\t\t\t\ttargetLocale,\n\t\t\t\t\t\t{ placeholder: 'fr', list: 'new-template-locales' },\n\t\t\t\t\t),\n\t\t\t\t\th(\n\t\t\t\t\t\t'datalist',\n\t\t\t\t\t\t{ id: 'new-template-locales' },\n\t\t\t\t\t\t[...new Set(props.locales)].map((l) => h('option', { key: l, value: l })),\n\t\t\t\t\t),\n\t\t\t\t\t...field('new-template-subject', tr('templates.subject'), subject),\n\t\t\t\t\t...field('new-template-html', tr('templates.htmlBody'), html, { textarea: true, minHeight: '160px' }),\n\t\t\t\t\t...field('new-template-text', tr('templates.textBody'), text, {\n\t\t\t\t\t\ttextarea: true,\n\t\t\t\t\t\tminHeight: '100px',\n\t\t\t\t\t}),\n\t\t\t\t\terror.value ? h('p', { style: styles.error, role: 'alert' }, error.value) : null,\n\t\t\t\t\th(\n\t\t\t\t\t\t'button',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\tdisabled: busy.value,\n\t\t\t\t\t\t\tstyle: { ...styles.button, marginTop: '16px' },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbusy.value\n\t\t\t\t\t\t\t? tr('templates.create.creating')\n\t\t\t\t\t\t\t: addingLocale\n\t\t\t\t\t\t\t\t? tr('templates.create.submitLocale')\n\t\t\t\t\t\t\t\t: tr('templates.create.submitNew'),\n\t\t\t\t\t),\n\t\t\t\t]),\n\t\t\t]);\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '8px 40px 64px', maxWidth: '1400px', boxSizing: 'border-box' },\n\t// Two columns, always: editor left, rendered result right. Stacking the\n\t// preview under a long form hid it below the fold.\n\tsplit: {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',\n\t\tgap: '24px',\n\t\talignItems: 'start',\n\t},\n\tcolumn: { minWidth: '0', display: 'flex', flexDirection: 'column' },\n\t// Pinned while the form scrolls, so the preview stays in view as you edit.\n\tpreviewColumn: {\n\t\tminWidth: '0',\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tposition: 'sticky',\n\t\ttop: '16px',\n\t},\n\tsaveRow: { display: 'flex', alignItems: 'center', gap: '12px', marginTop: '16px' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '8px 0 4px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\tsubtitle: {\n\t\tfontSize: '15px',\n\t\tfontWeight: 600,\n\t\tmargin: '0 0 10px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t},\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '20px' },\n\tstatus: { padding: '24px 0', color: 'var(--fonderie-text-muted,#5c5c5c)', fontSize: '13.5px' },\n\terror: {\n\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)',\n\t\tborderRadius: '6px',\n\t\tpadding: '8px 12px',\n\t\tmargin: '8px 0',\n\t\tfontSize: '13.5px',\n\t},\n\tlist: {\n\t\tlistStyle: 'none',\n\t\tpadding: '0',\n\t\tmargin: '0',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\toverflow: 'hidden',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '16px',\n\t\tpadding: '13px 16px',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily: 'inherit',\n\t},\n\ttype: {\n\t\tfontSize: '13px',\n\t\tfontWeight: 600,\n\t\tflex: '1',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tlocale: { fontSize: '12.5px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-accent-strong,#009767)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-accent-strong,#009767) 13%, transparent)',\n\t},\n\tinactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-text-muted,#5c5c5c) 10%, transparent)',\n\t},\n\tform: {\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tgap: '4px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\tpadding: '6px 20px 20px',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tlabel: { fontSize: '13px', fontWeight: 500, marginTop: '14px', marginBottom: '2px' },\n\tinput: {\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '13.5px',\n\t\tfontFamily: 'inherit',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t},\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '10px',\n\t\tfontSize: '13px',\n\t\tlineHeight: 1.55,\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\tcursor: 'pointer',\n\t},\n\tbuttonDisabled: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\topacity: 0.45,\n\t\tcursor: 'not-allowed',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '12px',\n\t\tpadding: '9px 16px',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '28px',\n\t\tboxSizing: 'border-box',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '12.5px',\n\t\tfontWeight: 500,\n\t\tfontFamily: 'inherit',\n\t\tcursor: 'pointer',\n\t},\n\t// Template list: matches @fonderie/vue-admin-screens' shell look with local\n\t// values — this package sits below the admin screens and cannot import them.\n\tlistContainer: { padding: '32px 40px 64px', maxWidth: '1160px', boxSizing: 'border-box' },\n\tlistTitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '0',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\thint: { fontSize: '13.5px', color: 'var(--fonderie-text-muted,#5c5c5c)', margin: '4px 0 24px' },\n\tdot: { width: '6px', height: '6px', borderRadius: '999px', background: 'currentColor' },\n};\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateEntry,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tcreateAdminT,\n\tformatAdminDate,\n\tgroupTemplatesByType,\n\tmissingTemplateLocales,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { computed, defineComponent, h, ref, watch } from 'vue';\n\nconst PREVIEW_DEBOUNCE_MS = 500;\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\n// One tab per locale of this email, underlined like a document's tabs.\nconst tab: CSSProperties = {\n\theight: '32px',\n\tpadding: '0 10px',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderBottom: '2px solid transparent',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\tfontSize: '13px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst tabSelected: CSSProperties = {\n\t...tab,\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontWeight: 600,\n\tborderBottomColor: 'var(--fonderie-text,#171717)',\n\tcursor: 'default',\n};\nconst tabInactive: CSSProperties = { ...tab, opacity: 0.55, textDecoration: 'line-through' };\nconst tabBar: CSSProperties = {\n\tdisplay: 'flex',\n\talignItems: 'flex-end',\n\tgap: '12px',\n\tborderBottom: '1px solid var(--fonderie-border,#e0e0e0)',\n\tmargin: '4px 0 12px',\n\tpaddingBottom: '6px',\n};\nconst tabs: CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: '4px', marginBottom: '-7px' };\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t\t/**\n\t\t * A built-in email's default-locale row (the list's `system` flag): it can\n\t\t * be edited and rolled back, never deleted — Delete is not offered.\n\t\t */\n\t\tsystem: { type: Boolean, default: false },\n\t\t/** Shows \"+ Add locale\" (emits add-locale). */\n\t\tallowAddLocale: { type: Boolean, default: false },\n\t\t/**\n\t\t * Shows a tab per locale this email exists in (emits select-locale).\n\t\t * Unsaved edits are confirmed before switching away.\n\t\t */\n\t\tlocaleTabs: { type: Boolean, default: false },\n\t\t/** The console language (`locale` is the template's); defaults to English. */\n\t\tuiLocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t\t/** The template was deleted and no longer exists. */\n\t\tdeleted: () => true,\n\t\t/**\n\t\t * Create a translation of this template. `locales` are the ones the app\n\t\t * uses elsewhere that this email lacks — suggest them first.\n\t\t */\n\t\t'add-locale': (_type: string, _context: { locales: string[] }) => true,\n\t\t/** Open another locale of this email. */\n\t\t'select-locale': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.uiLocale)(key, params);\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { templates, saveTemplate, removeTemplate } = useTemplates(props.client);\n\t\t// This email's locales, for the tabs. The list is already fetched for saves.\n\t\tconst siblings = computed(\n\t\t\t() => groupTemplatesByType(templates.value).find((g) => g.type === props.type)?.entries ?? [],\n\t\t);\n\t\tconst isDeleting = ref(false);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<AdminMessageKey | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'templates.editor.sampleNotObject';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'templates.editor.sampleInvalid';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// The preview is always live: it renders once the template loads, then\n\t\t// again PREVIEW_DEBOUNCE_MS after the last edit to the content or the sample\n\t\t// data — debounced, so typing a paragraph costs one request, not one per key.\n\t\tlet previewTimer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([template, subject, html, text, sampleJson], () => {\n\t\t\tif (!template.value) return;\n\t\t\tclearTimeout(previewTimer);\n\t\t\tpreviewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\t// Saving what is already stored would only mint an identical version (the\n\t\t// server treats it as a no-op anyway), so Save waits for a real change.\n\t\tconst dirty = computed(() => {\n\t\t\tconst tpl = template.value;\n\t\t\treturn (\n\t\t\t\t!!tpl &&\n\t\t\t\t(subject.value !== (tpl.subject ?? '') ||\n\t\t\t\t\thtml.value !== (tpl.html ?? '') ||\n\t\t\t\t\ttext.value !== tpl.text ||\n\t\t\t\t\tactive.value !== tpl.active)\n\t\t\t);\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\t// Leaving a locale with unsaved edits asks first: they would be lost.\n\t\tconst leave = () => !dirty.value || window.confirm(t('templates.editor.discardChanges'));\n\n\t\tfunction renderTabBar() {\n\t\t\tif (!props.localeTabs && !props.allowAddLocale) return null;\n\t\t\treturn h('div', { style: tabBar }, [\n\t\t\t\tprops.localeTabs\n\t\t\t\t\t? // Each tab opens another stored row, so this is navigation, not an\n\t\t\t\t\t\t// ARIA tablist: plain buttons, the open one marked aria-current.\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'nav',\n\t\t\t\t\t\t\t{ 'aria-label': t('templates.editor.locales'), style: tabs },\n\t\t\t\t\t\t\tsiblings.value.map((entry) => {\n\t\t\t\t\t\t\t\tconst selected = entry.locale === (props.locale ?? null);\n\t\t\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t'aria-current': selected ? 'true' : undefined,\n\t\t\t\t\t\t\t\t\t\tstyle: selected ? tabSelected : entry.active ? tab : tabInactive,\n\t\t\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\tif (!selected && leave()) emit('select-locale', entry);\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tentry.locale ?? t('templates.defaultChip'),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t\tprops.allowAddLocale\n\t\t\t\t\t? h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: { ...styles.rollbackButton, marginLeft: 'auto' },\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tif (leave())\n\t\t\t\t\t\t\t\t\t\temit('add-locale', props.type, {\n\t\t\t\t\t\t\t\t\t\t\tlocales: missingTemplateLocales(templates.value, props.type),\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tt('templates.editor.addLocale'),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t}\n\n\t\tasync function handleDelete() {\n\t\t\tconst message = props.locale\n\t\t\t\t? t('templates.editor.confirmDeleteLocale', { locale: props.locale, type: props.type })\n\t\t\t\t: t('templates.editor.confirmDelete', { type: props.type });\n\t\t\tif (!window.confirm(message)) return;\n\t\t\tisDeleting.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tawait removeTemplate(props.type, props.locale);\n\t\t\t\temit('deleted');\n\t\t\t} catch (err) {\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisDeleting.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? t('templates.editor.unknownActor')} — ${formatAdminDate(rev.createdAt, props.uiLocale)}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\tt('templates.editor.rollBack'),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, t('templates.editor.loading'));\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\trenderTabBar(),\n\t\t\t\th('p', { style: styles.meta }, [\n\t\t\t\t\th('strong', props.locale ?? t('templates.defaultLocale')),\n\t\t\t\t\t` · v${template.value?.version ?? 1}`,\n\t\t\t\t\tprops.system ? ` · ${t('templates.editor.builtInNote')}` : '',\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, t('templates.subject')),\n\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, t('templates.htmlBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, t('templates.textBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tt('templates.editor.active'),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\tsaveError.value?.reason === 'VERSION_CONFLICT'\n\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, [\n\t\t\t\t\t\t\t\t\t\t`${t('templates.editor.conflict')} `,\n\t\t\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsaveError.value = null;\n\t\t\t\t\t\t\t\t\t\t\t\t\tvoid refresh();\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tt('common.reload'),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t\t: saveError.value\n\t\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\th('div', { style: styles.saveRow }, [\n\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\t\t\tdisabled: isSaving.value || !dirty.value,\n\t\t\t\t\t\t\t\t\t\tstyle: dirty.value ? styles.button : styles.buttonDisabled,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tisSaving.value ? t('common.saving') : t('common.save'),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t!dirty.value && !isSaving.value\n\t\t\t\t\t\t\t\t\t? h('span', { style: styles.meta }, t('templates.editor.noChanges'))\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t!props.system\n\t\t\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled: isDeleting.value,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => void handleDelete(),\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t...styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\t\theight: '36px',\n\t\t\t\t\t\t\t\t\t\t\t\t\tmarginLeft: 'auto',\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderColor:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)',\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tisDeleting.value ? t('common.deleting') : t('common.delete'),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'label',\n\t\t\t\t\t\t\t{ style: styles.label, for: 'template-sample' },\n\t\t\t\t\t\t\tt('templates.editor.sampleData'),\n\t\t\t\t\t\t),\n\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t\tspellcheck: false,\n\t\t\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tsampleError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, t(sampleError.value))\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t]),\n\t\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\t\th('span', { style: styles.label }, t('templates.editor.preview')),\n\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t\t\t\tisPreviewing.value ? t('templates.editor.rendering') : t('templates.editor.live'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\t\ttitle: t('templates.editor.previewTitle'),\n\t\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t\t: h('p', { style: styles.meta }, t('templates.editor.nothingRendered')),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, t('templates.editor.history')),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tITemplateEntry,\n} from '@fonderie/client';\nimport { createAdminT, groupTemplatesByType } from '@fonderie/client';\nimport type { ITemplateGroup } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nconst builtIn: CSSProperties = {\n\tfontSize: '11px',\n\tfontWeight: 500,\n\tpadding: '1px 7px',\n\tborderRadius: '999px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n};\n// One per locale the email exists in. Monospace: they are language tags.\nconst chip: CSSProperties = {\n\theight: '24px',\n\tboxSizing: 'border-box',\n\tpadding: '0 8px',\n\tborderRadius: '6px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tbackground: 'var(--fonderie-surface,#fff)',\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontSize: '12px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst chipInactive: CSSProperties = { ...chip, opacity: 0.5, textDecoration: 'line-through' };\nconst row: CSSProperties = {\n\t...styles.row,\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '8px',\n\tpaddingRight: '16px',\n};\nconst rowButton: CSSProperties = { ...styles.rowButton, width: 'auto', flex: '1', minWidth: '0' };\nconst chips: CSSProperties = {\n\tdisplay: 'flex',\n\tflexWrap: 'wrap',\n\tjustifyContent: 'flex-end',\n\tgap: '6px',\n};\nconst newButton: CSSProperties = {\n\tdisplay: 'inline-flex',\n\talignItems: 'center',\n\theight: '32px',\n\tboxSizing: 'border-box',\n\tborderRadius: '6px',\n\tpadding: '0 12px',\n\tfontSize: '13px',\n\tfontWeight: 500,\n\tfontFamily: 'inherit',\n\tcursor: 'pointer',\n\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\tcolor: 'var(--fonderie-surface,#fff)',\n\tborder: '1px solid var(--fonderie-text,#171717)',\n};\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/** Shows a \"New template\" button (emits create-template). */\n\t\tallowCreate: { type: Boolean, default: false },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/**\n\t\t * The whole row — type AND locale, and whether it is built-in. One row\n\t\t * per email: the row opens the default locale, a locale chip that locale.\n\t\t */\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t\t/** Receives the locales in use, to suggest. */\n\t\t'create-template': (_context: { locales: string[] }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\tfunction renderRow(group: ITemplateGroup) {\n\t\t\tconst primary: ITemplateEntry = group.primary;\n\t\t\treturn h('li', { key: group.type, style: row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', primary),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, group.type),\n\t\t\t\t\t\tgroup.system ? h('span', { style: builtIn }, t('templates.builtInBadge')) : null,\n\t\t\t\t\t\th('span', { style: primary.active ? styles.active : styles.inactive }, [\n\t\t\t\t\t\t\th('span', { style: styles.dot }),\n\t\t\t\t\t\t\tprimary.active ? t('common.status.active') : t('common.status.inactive'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\t// Siblings of the row button, not inside it: a button cannot hold buttons.\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t{ style: chips },\n\t\t\t\t\tgroup.entries.map((entry) => {\n\t\t\t\t\t\tconst name = entry.locale ?? t('templates.defaultChip');\n\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: entry.active ? chip : chipInactive,\n\t\t\t\t\t\t\t\t'aria-label': t('templates.list.openLocale', { type: group.type, locale: name }),\n\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\tonClick: () => emit('select-template', entry),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () =>\n\t\t\th('div', { style: styles.listContainer }, [\n\t\t\t\th(\n\t\t\t\t\t'div',\n\t\t\t\t\t{\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\t\tjustifyContent: 'space-between',\n\t\t\t\t\t\t\tgap: '16px',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('h1', { style: styles.listTitle }, t('templates.list.title')),\n\t\t\t\t\t\tprops.allowCreate\n\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\tstyle: newButton,\n\t\t\t\t\t\t\t\t\t\tonClick: () =>\n\t\t\t\t\t\t\t\t\t\t\temit('create-template', {\n\t\t\t\t\t\t\t\t\t\t\t\tlocales: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t...new Set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemplates.value\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map((tpl) => tpl.locale)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter((l): l is string => !!l),\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tt('templates.list.newTemplate'),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\th('p', { style: styles.hint }, t('templates.list.hint')),\n\t\t\t\tisLoading.value\n\t\t\t\t\t? h('p', { style: styles.status }, t('templates.list.loading'))\n\t\t\t\t\t: error.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, error.value.explanation)\n\t\t\t\t\t\t: h('ul', { style: styles.list }, groupTemplatesByType(templates.value).map(renderRow)),\n\t\t\t]);\n\t},\n});\n"],"mappings":";AAOA,SAAS,cAAc,wBAAwB;AAE/C,SAAS,iBAAiB,GAAG,WAAW,WAAW;;;ACP5C,IAAM,SAAwC;AAAA,EACpD,WAAW,EAAE,SAAS,iBAAiB,UAAU,UAAU,WAAW,aAAa;AAAA;AAAA;AAAA,EAGnF,OAAO;AAAA,IACN,SAAS;AAAA,IACT,qBAAqB;AAAA,IACrB,KAAK;AAAA,IACL,YAAY;AAAA,EACb;AAAA,EACA,QAAQ,EAAE,UAAU,KAAK,SAAS,QAAQ,eAAe,SAAS;AAAA;AAAA,EAElE,eAAe;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAU;AAAA,IACV,KAAK;AAAA,EACN;AAAA,EACA,SAAS,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,QAAQ,WAAW,OAAO;AAAA,EACjF,eAAe;AAAA,IACd,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,WAAW;AAAA,EACZ;AAAA,EACA,gBAAgB,EAAE,UAAU,QAAQ,YAAY,OAAO,QAAQ,QAAQ;AAAA,EACvE,cAAc;AAAA,IACb,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,WAAW;AAAA,EACZ;AAAA,EACA,aAAa;AAAA,IACZ,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YACC;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,YAAY;AAAA,EACb;AAAA,EACA,UAAU;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,eAAe;AAAA,EAChB;AAAA,EACA,MAAM,EAAE,UAAU,QAAQ,OAAO,sCAAsC,cAAc,OAAO;AAAA,EAC5F,QAAQ,EAAE,SAAS,UAAU,OAAO,sCAAsC,UAAU,SAAS;AAAA,EAC7F,OAAO;AAAA,IACN,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,UAAU;AAAA,EACX;AAAA,EACA,MAAM;AAAA,IACL,WAAW;AAAA,IACX,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA,EACZ;AAAA,EACA,KAAK,EAAE,cAAc,iDAAiD;AAAA,EACtE,WAAW;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,YAAY;AAAA,EACb;AAAA,EACA,MAAM;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,YACC;AAAA,EACF;AAAA,EACA,QAAQ,EAAE,UAAU,UAAU,OAAO,qCAAqC;AAAA,EAC1E,QAAQ;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,YAAY;AAAA,EACb;AAAA,EACA,UAAU;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,YAAY;AAAA,EACb;AAAA,EACA,MAAM;AAAA,IACL,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,WAAW;AAAA,EACZ;AAAA,EACA,OAAO,EAAE,UAAU,QAAQ,YAAY,KAAK,WAAW,QAAQ,cAAc,MAAM;AAAA,EACnF,OAAO;AAAA,IACN,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,OAAO;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACT,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,YACC;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACd,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,WAAW;AAAA,IACX,UAAU;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,QAAQ;AAAA,EACT;AAAA,EACA,gBAAgB;AAAA,IACf,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,SAAS;AAAA,IACT,QAAQ;AAAA,EACT;AAAA,EACA,WAAW,EAAE,WAAW,OAAO;AAAA,EAC/B,aAAa;AAAA,IACZ,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,SAAS;AAAA,IACT,cAAc;AAAA,IACd,UAAU;AAAA,EACX;AAAA,EACA,gBAAgB;AAAA,IACf,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,QAAQ;AAAA,EACT;AAAA;AAAA;AAAA,EAGA,eAAe,EAAE,SAAS,kBAAkB,UAAU,UAAU,WAAW,aAAa;AAAA,EACxF,WAAW;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,YAAY;AAAA,EACb;AAAA,EACA,MAAM,EAAE,UAAU,UAAU,OAAO,sCAAsC,QAAQ,aAAa;AAAA,EAC9F,KAAK,EAAE,OAAO,OAAO,QAAQ,OAAO,cAAc,SAAS,YAAY,eAAe;AACvF;;;ADlOA,IAAM,UAAU;AAChB,IAAM,YAAY;AAIX,IAAM,uBAAuB,gBAAgB;AAAA,EACnD,MAAM;AAAA,EACN,OAAO;AAAA,IACN,QAAQ,EAAE,MAAM,QAAwC,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMvE,MAAM,EAAE,MAAM,QAAQ,SAAS,OAAU;AAAA;AAAA,IAEzC,SAAS,EAAE,MAAM,OAA6B,SAAS,MAAM,CAAC,EAAE;AAAA;AAAA,IAEhE,QAAQ,EAAE,MAAM,QAAiC,SAAS,OAAU;AAAA,EACrE;AAAA,EACA,OAAO;AAAA;AAAA,IAEN,SAAS,CAAC,aAAsD;AAAA,EACjE;AAAA,EACA,MAAM,OAAO,EAAE,KAAK,GAAG;AACtB,UAAM,eAAe,MAAM,SAAS;AACpC,UAAM,UAAU,IAAI,EAAE;AACtB,UAAM,eAAe,IAAI,EAAE;AAC3B,UAAM,UAAU,IAAI,EAAE;AACtB,UAAM,OAAO,IAAI,EAAE;AACnB,UAAM,OAAO,IAAI,EAAE;AACnB,UAAM,QAAQ,IAAmB,IAAI;AACrC,UAAM,OAAO,IAAI,KAAK;AAEtB,UAAM,KAAK,CAAC,KAAsB,WACjC,aAAa,MAAM,MAAM,EAAE,KAAK,MAAM;AAGvC,cAAU,MAAM;AACf,UAAI,CAAC,MAAM,KAAM;AACjB,YAAM,OACJ,YAAY,MAAM,MAAM,IAAI,EAC5B,KAAK,CAAC,EAAE,OAAO,MAAM;AACrB,gBAAQ,QAAQ,OAAO,WAAW;AAClC,aAAK,QAAQ,OAAO,QAAQ;AAC5B,aAAK,QAAQ,OAAO;AAAA,MACrB,CAAC,EACA,MAAM,MAAM,MAAS;AAAA,IACxB,CAAC;AAED,mBAAe,OAAO,GAAU;AAC/B,QAAE,eAAe;AACjB,YAAM,QAAQ;AACd,YAAM,IAAI,eAAgB,MAAM,OAAkB,QAAQ,MAAM,KAAK;AACrE,YAAM,IAAI,aAAa,MAAM,KAAK,KAAK;AACvC,UAAI,CAAC,QAAQ,KAAK,CAAC,GAAG;AACrB,cAAM,QAAQ,GAAG,4BAA4B;AAC7C;AAAA,MACD;AACA,UAAI,gBAAgB,CAAC,GAAG;AACvB,cAAM,QAAQ,GAAG,sCAAsC;AACvD;AAAA,MACD;AACA,UAAI,KAAK,CAAC,UAAU,KAAK,CAAC,GAAG;AAC5B,cAAM,QAAQ,GAAG,8BAA8B;AAC/C;AAAA,MACD;AACA,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACvB,cAAM,QAAQ,GAAG,4BAA4B;AAC7C;AAAA,MACD;AACA,WAAK,QAAQ;AACb,UAAI;AAEH,cAAM,SAAS,MAAM,MAAM,OAAO,YAAY,GAAG,CAAC,EAAE;AAAA,UACnD,MAAM;AAAA,UACN,CAAC,QAAiB,EAAE,eAAe,oBAAoB,IAAI,WAAW;AAAA,QACvE;AACA,YAAI,QAAQ;AACX,gBAAM,QAAQ,IACX,GAAG,iCAAiC,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC,IAC1D,GAAG,2BAA2B,EAAE,MAAM,EAAE,CAAC;AAC5C;AAAA,QACD;AACA,cAAM,QAA2B,EAAE,MAAM,KAAK,OAAO,QAAQ,KAAK;AAClE,YAAI,QAAQ,MAAO,OAAM,UAAU,QAAQ;AAC3C,YAAI,KAAK,MAAO,OAAM,OAAO,KAAK;AAClC,cAAM,MAAM,OAAO,YAAY,GAAG,OAAO,CAAC;AAC1C,aAAK,WAAW,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;AAAA,MACvC,SAAS,KAAK;AACb,cAAM,QAAQ,eAAe,mBAAmB,IAAI,cAAc,OAAO,GAAG;AAAA,MAC7E,UAAE;AACD,aAAK,QAAQ;AAAA,MACd;AAAA,IACD;AAEA,UAAM,QAAQ,CACb,IACA,OACA,OACA,OAAgC,CAAC,MAC7B;AAAA,MACJ,EAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,GAAG,GAAG,KAAK;AAAA,MAClD,EAAE,KAAK,WAAW,aAAa,SAAS;AAAA,QACvC;AAAA,QACA,OAAO,KAAK,WAAW,EAAE,GAAG,OAAO,UAAU,WAAW,KAAK,UAAU,IAAI,OAAO;AAAA,QAClF,OAAO,MAAM;AAAA,QACb,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,QAC5D,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,QACvC,SAAS,CAAC,OAAc;AACvB,gBAAM,QAAS,GAAG,OAA4B;AAAA,QAC/C;AAAA,MACD,CAAC;AAAA,IACF;AAEA,WAAO,MACN,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,WAAW,UAAU,QAAQ,EAAE,GAAG;AAAA,MAC/D;AAAA,QACC;AAAA,QACA,EAAE,OAAO,OAAO,MAAM;AAAA,QACtB,eACG,GAAG,gCAAgC,EAAE,MAAM,MAAM,KAAe,CAAC,IACjE,GAAG,2BAA2B;AAAA,MAClC;AAAA,MACA;AAAA,QACC;AAAA,QACA,EAAE,OAAO,EAAE,GAAG,OAAO,MAAM,YAAY,IAAI,EAAE;AAAA,QAC7C,eACG,GAAG,6BAA6B,IAChC,GAAG,0BAA0B;AAAA,MACjC;AAAA,MACA,EAAE,QAAQ,EAAE,OAAO,OAAO,MAAM,UAAU,CAAC,OAAc,KAAK,OAAO,EAAE,EAAE,GAAG;AAAA,QAC3E,GAAI,eACD,CAAC,IACD,MAAM,qBAAqB,GAAG,uBAAuB,GAAG,SAAS,EAAE,aAAa,gBAAgB,CAAC;AAAA,QACpG,GAAG;AAAA,UACF;AAAA,UACA,eAAe,GAAG,yBAAyB,IAAI,GAAG,iCAAiC;AAAA,UACnF;AAAA,UACA,EAAE,aAAa,MAAM,MAAM,uBAAuB;AAAA,QACnD;AAAA,QACA;AAAA,UACC;AAAA,UACA,EAAE,IAAI,uBAAuB;AAAA,UAC7B,CAAC,GAAG,IAAI,IAAI,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,GAAG,OAAO,EAAE,CAAC,CAAC;AAAA,QACzE;AAAA,QACA,GAAG,MAAM,wBAAwB,GAAG,mBAAmB,GAAG,OAAO;AAAA,QACjE,GAAG,MAAM,qBAAqB,GAAG,oBAAoB,GAAG,MAAM,EAAE,UAAU,MAAM,WAAW,QAAQ,CAAC;AAAA,QACpG,GAAG,MAAM,qBAAqB,GAAG,oBAAoB,GAAG,MAAM;AAAA,UAC7D,UAAU;AAAA,UACV,WAAW;AAAA,QACZ,CAAC;AAAA,QACD,MAAM,QAAQ,EAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,MAAM,KAAK,IAAI;AAAA,QAC5E;AAAA,UACC;AAAA,UACA;AAAA,YACC,MAAM;AAAA,YACN,UAAU,KAAK;AAAA,YACf,OAAO,EAAE,GAAG,OAAO,QAAQ,WAAW,OAAO;AAAA,UAC9C;AAAA,UACA,KAAK,QACF,GAAG,2BAA2B,IAC9B,eACC,GAAG,+BAA+B,IAClC,GAAG,4BAA4B;AAAA,QACpC;AAAA,MACD,CAAC;AAAA,IACF,CAAC;AAAA,EACH;AACD,CAAC;;;AE7KD;AAAA,EACC,gBAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAEP,SAAS,UAAU,mBAAAC,kBAAiB,KAAAC,IAAG,OAAAC,MAAK,aAAa;AAEzD,IAAM,sBAAsB;AAK5B,IAAM,WAAW,oBAAI,IAAI,CAAC,WAAW,aAAa,WAAW,CAAC;AAG9D,IAAM,MAAqB;AAAA,EAC1B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,OAAO;AAAA,EACP,UAAU;AAAA,EACV,YACC;AAAA,EACD,QAAQ;AACT;AACA,IAAM,cAA6B;AAAA,EAClC,GAAG;AAAA,EACH,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,QAAQ;AACT;AACA,IAAM,cAA6B,EAAE,GAAG,KAAK,SAAS,MAAM,gBAAgB,eAAe;AAC3F,IAAM,SAAwB;AAAA,EAC7B,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,eAAe;AAChB;AACA,IAAM,OAAsB,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,OAAO,cAAc,OAAO;AAE3F,IAAM,uBAAuBC,iBAAgB;AAAA,EACnD,MAAM;AAAA,EACN,OAAO;AAAA,IACN,QAAQ,EAAE,MAAM,QAAwC,UAAU,KAAK;AAAA,IACvE,MAAM,EAAE,MAAM,QAAQ,UAAU,KAAK;AAAA,IACrC,QAAQ,EAAE,MAAM,QAAmC,SAAS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,IAKjE,QAAQ,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA;AAAA,IAExC,gBAAgB,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKhD,YAAY,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA;AAAA,IAE5C,UAAU,EAAE,MAAM,QAAiC,SAAS,OAAU;AAAA,EACvE;AAAA,EACA,OAAO;AAAA,IACN,OAAO,MAAM;AAAA;AAAA,IAEb,SAAS,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKf,cAAc,CAAC,OAAe,aAAoC;AAAA;AAAA,IAElE,iBAAiB,CAAC,cAA8B;AAAA,EACjD;AAAA,EACA,MAAM,OAAO,EAAE,KAAK,GAAG;AACtB,UAAM,IAAI,CAAC,KAAsB,WAChCC,cAAa,MAAM,QAAQ,EAAE,KAAK,MAAM;AACzC,UAAM,EAAE,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,MAC/C,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACP;AAKA,UAAM,EAAE,WAAW,cAAc,eAAe,IAAI,aAAa,MAAM,MAAM;AAE7E,UAAM,WAAW;AAAA,MAChB,MAAM,qBAAqB,UAAU,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI,GAAG,WAAW,CAAC;AAAA,IAC7F;AACA,UAAM,aAAaC,KAAI,KAAK;AAC5B,UAAM,EAAE,WAAW,SAAS,IAAI,qBAAqB,MAAM,QAAQ,MAAM,MAAM,MAAM,MAAM;AAC3F,UAAM,WAAWA,KAAI,KAAK;AAC1B,UAAM,YAAYA,KAA6B,IAAI;AAEnD,UAAM,UAAUA,KAAI,EAAE;AACtB,UAAM,OAAOA,KAAI,EAAE;AACnB,UAAM,OAAOA,KAAI,EAAE;AACnB,UAAM,SAASA,KAAI,IAAI;AAEvB,UAAM,UAAU,CAAC,QAAQ;AACxB,UAAI,CAAC,IAAK;AACV,cAAQ,QAAQ,IAAI,WAAW;AAC/B,WAAK,QAAQ,IAAI,QAAQ;AACzB,WAAK,QAAQ,IAAI;AACjB,aAAO,QAAQ,IAAI;AAAA,IACpB,CAAC;AAED,UAAM;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACD,IAAI,mBAAmB,MAAM,MAAM;AAGnC,UAAM,aAAaA,KAAI,IAAI;AAC3B,UAAM,cAAcA,KAA4B,IAAI;AAEpD,mBAAe,MAAM;AACpB,UAAI,OAAgC,CAAC;AACrC,UAAI;AACH,cAAM,SAAkB,KAAK,MAAM,WAAW,SAAS,IAAI;AAC3D,YAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AACnE,sBAAY,QAAQ;AACpB;AAAA,QACD;AACA,eAAO;AACP,oBAAY,QAAQ;AAAA,MACrB,QAAQ;AACP,oBAAY,QAAQ;AACpB;AAAA,MACD;AACA,YAAM,SAAS,MAAM;AAAA,QACpB,MAAM;AAAA,QACN;AAAA,UACC,MAAM,KAAK;AAAA,UACX;AAAA,UACA,GAAI,QAAQ,QAAQ,EAAE,SAAS,QAAQ,MAAM,IAAI,CAAC;AAAA,UAClD,GAAI,KAAK,QAAQ,EAAE,MAAM,KAAK,MAAM,IAAI,CAAC;AAAA,QAC1C;AAAA,QACA,MAAM;AAAA,MACP;AAIA,YAAM,UAAU,OAAO,UAAU,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK;AAC/E,UAAI,QAAQ,SAAS,GAAG;AACvB,mBAAW,QAAQ,KAAK;AAAA,UACvB,EAAE,GAAG,MAAM,GAAG,OAAO,YAAY,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAAA,UAC7D;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAKA,QAAI;AACJ,UAAM,CAAC,UAAU,SAAS,MAAM,MAAM,UAAU,GAAG,MAAM;AACxD,UAAI,CAAC,SAAS,MAAO;AACrB,mBAAa,YAAY;AACzB,qBAAe,WAAW,MAAM,KAAK,IAAI,GAAG,mBAAmB;AAAA,IAChE,CAAC;AAID,UAAM,QAAQ,SAAS,MAAM;AAC5B,YAAM,MAAM,SAAS;AACrB,aACC,CAAC,CAAC,QACD,QAAQ,WAAW,IAAI,WAAW,OAClC,KAAK,WAAW,IAAI,QAAQ,OAC5B,KAAK,UAAU,IAAI,QACnB,OAAO,UAAU,IAAI;AAAA,IAExB,CAAC;AAED,mBAAe,aAAa,OAAc;AACzC,YAAM,eAAe;AACrB,eAAS,QAAQ;AACjB,gBAAU,QAAQ;AAClB,UAAI;AACH,cAAM,QAA2B,EAAE,MAAM,KAAK,OAAO,QAAQ,OAAO,MAAM;AAC1E,YAAI,QAAQ,MAAO,OAAM,UAAU,QAAQ;AAC3C,YAAI,KAAK,MAAO,OAAM,OAAO,KAAK;AAClC,YAAI,SAAS,OAAO,YAAY,OAAW,OAAM,YAAY,SAAS,MAAM;AAC5E,cAAM,aAAa,MAAM,MAAM,OAAO,MAAM,MAAM;AAGlD,cAAM,QAAQ;AACd,aAAK,OAAO;AAAA,MACb,SAAS,KAAK;AAEb,kBAAU,QAAQ;AAAA,MACnB,UAAE;AACD,iBAAS,QAAQ;AAAA,MAClB;AAAA,IACD;AAGA,UAAM,QAAQ,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,EAAE,iCAAiC,CAAC;AAEvF,aAAS,eAAe;AACvB,UAAI,CAAC,MAAM,cAAc,CAAC,MAAM,eAAgB,QAAO;AACvD,aAAOC,GAAE,OAAO,EAAE,OAAO,OAAO,GAAG;AAAA,QAClC,MAAM;AAAA;AAAA;AAAA,UAGJA;AAAA,YACC;AAAA,YACA,EAAE,cAAc,EAAE,0BAA0B,GAAG,OAAO,KAAK;AAAA,YAC3D,SAAS,MAAM,IAAI,CAAC,UAAU;AAC7B,oBAAM,WAAW,MAAM,YAAY,MAAM,UAAU;AACnD,qBAAOA;AAAA,gBACN;AAAA,gBACA;AAAA,kBACC,KAAK,MAAM,UAAU;AAAA,kBACrB,MAAM;AAAA,kBACN,gBAAgB,WAAW,SAAS;AAAA,kBACpC,OAAO,WAAW,cAAc,MAAM,SAAS,MAAM;AAAA,kBACrD,OAAO,MAAM,SAAS,SAAY,EAAE,wBAAwB;AAAA,kBAC5D,SAAS,MAAM;AACd,wBAAI,CAAC,YAAY,MAAM,EAAG,MAAK,iBAAiB,KAAK;AAAA,kBACtD;AAAA,gBACD;AAAA,gBACA,MAAM,UAAU,EAAE,uBAAuB;AAAA,cAC1C;AAAA,YACD,CAAC;AAAA,UACF;AAAA,YACC;AAAA,QACH,MAAM,iBACHA;AAAA,UACA;AAAA,UACA;AAAA,YACC,MAAM;AAAA,YACN,OAAO,EAAE,GAAG,OAAO,gBAAgB,YAAY,OAAO;AAAA,YACtD,SAAS,MAAM;AACd,kBAAI,MAAM;AACT,qBAAK,cAAc,MAAM,MAAM;AAAA,kBAC9B,SAAS,uBAAuB,UAAU,OAAO,MAAM,IAAI;AAAA,gBAC5D,CAAC;AAAA,YACH;AAAA,UACD;AAAA,UACA,EAAE,4BAA4B;AAAA,QAC/B,IACC;AAAA,MACJ,CAAC;AAAA,IACF;AAEA,mBAAe,eAAe;AAC7B,YAAM,UAAU,MAAM,SACnB,EAAE,wCAAwC,EAAE,QAAQ,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,IACpF,EAAE,kCAAkC,EAAE,MAAM,MAAM,KAAK,CAAC;AAC3D,UAAI,CAAC,OAAO,QAAQ,OAAO,EAAG;AAC9B,iBAAW,QAAQ;AACnB,gBAAU,QAAQ;AAClB,UAAI;AACH,cAAM,eAAe,MAAM,MAAM,MAAM,MAAM;AAC7C,aAAK,SAAS;AAAA,MACf,SAAS,KAAK;AACb,kBAAU,QAAQ;AAAA,MACnB,UAAE;AACD,mBAAW,QAAQ;AAAA,MACpB;AAAA,IACD;AAEA,aAAS,eAAe,KAAwB;AAC/C,aAAOA,GAAE,MAAM,EAAE,KAAK,IAAI,SAAS,OAAO,OAAO,YAAY,GAAG;AAAA,QAC/DA;AAAA,UACC;AAAA,UACA,IAAI,IAAI,OAAO,WAAM,IAAI,SAAS,EAAE,+BAA+B,CAAC,WAAM,gBAAgB,IAAI,WAAW,MAAM,QAAQ,CAAC;AAAA,QACzH;AAAA,QACAA;AAAA,UACC;AAAA,UACA,EAAE,MAAM,UAAU,OAAO,OAAO,gBAAgB,SAAS,MAAM,SAAS,IAAI,OAAO,EAAE;AAAA,UACrF,EAAE,2BAA2B;AAAA,QAC9B;AAAA,MACD,CAAC;AAAA,IACF;AAEA,WAAO,MAAM;AACZ,UAAI,UAAU,MAAO,QAAOA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE,0BAA0B,CAAC;AAC1F,UAAI,MAAM;AACT,eAAOA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,MAAM,MAAM,WAAW;AAE9E,aAAOA,GAAE,OAAO,EAAE,OAAO,OAAO,UAAU,GAAG;AAAA,QAC5CA,GAAE,MAAM,EAAE,OAAO,OAAO,MAAM,GAAG,MAAM,IAAI;AAAA,QAC3C,aAAa;AAAA,QACbA,GAAE,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG;AAAA,UAC9BA,GAAE,UAAU,MAAM,UAAU,EAAE,yBAAyB,CAAC;AAAA,UACxD,UAAO,SAAS,OAAO,WAAW,CAAC;AAAA,UACnC,MAAM,SAAS,SAAM,EAAE,8BAA8B,CAAC,KAAK;AAAA,QAC5D,CAAC;AAAA,QACDA,GAAE,OAAO,EAAE,OAAO,OAAO,MAAM,GAAG;AAAA,UACjCA,GAAE,OAAO,EAAE,OAAO,OAAO,OAAO,GAAG;AAAA,YAClCA,GAAE,QAAQ,EAAE,OAAO,OAAO,MAAM,UAAU,aAAa,GAAG;AAAA,cACzDA,GAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,mBAAmB,GAAG,EAAE,mBAAmB,CAAC;AAAA,cACnFA,GAAE,SAAS;AAAA,gBACV,IAAI;AAAA,gBACJ,OAAO,OAAO;AAAA,gBACd,OAAO,QAAQ;AAAA,gBACf,SAAS,CAAC,MAAa;AACtB,0BAAQ,QAAS,EAAE,OAA4B;AAAA,gBAChD;AAAA,cACD,CAAC;AAAA,cACDA,GAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,gBAAgB,GAAG,EAAE,oBAAoB,CAAC;AAAA,cACjFA,GAAE,YAAY;AAAA,gBACb,IAAI;AAAA,gBACJ,OAAO,OAAO;AAAA,gBACd,MAAM;AAAA,gBACN,OAAO,KAAK;AAAA,gBACZ,SAAS,CAAC,MAAa;AACtB,uBAAK,QAAS,EAAE,OAA+B;AAAA,gBAChD;AAAA,cACD,CAAC;AAAA,cACDA,GAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,gBAAgB,GAAG,EAAE,oBAAoB,CAAC;AAAA,cACjFA,GAAE,YAAY;AAAA,gBACb,IAAI;AAAA,gBACJ,OAAO,OAAO;AAAA,gBACd,MAAM;AAAA,gBACN,UAAU;AAAA,gBACV,OAAO,KAAK;AAAA,gBACZ,SAAS,CAAC,MAAa;AACtB,uBAAK,QAAS,EAAE,OAA+B;AAAA,gBAChD;AAAA,cACD,CAAC;AAAA,cACDA,GAAE,SAAS,EAAE,OAAO,OAAO,cAAc,GAAG;AAAA,gBAC3CA,GAAE,SAAS;AAAA,kBACV,MAAM;AAAA,kBACN,SAAS,OAAO;AAAA,kBAChB,UAAU,CAAC,MAAa;AACvB,2BAAO,QAAS,EAAE,OAA4B;AAAA,kBAC/C;AAAA,gBACD,CAAC;AAAA,gBACD,EAAE,yBAAyB;AAAA,cAC5B,CAAC;AAAA,cACD,UAAU,OAAO,WAAW,qBACzBA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG;AAAA,gBAC/C,GAAG,EAAE,2BAA2B,CAAC;AAAA,gBACjCA;AAAA,kBACC;AAAA,kBACA;AAAA,oBACC,MAAM;AAAA,oBACN,OAAO,OAAO;AAAA,oBACd,SAAS,MAAM;AACd,gCAAU,QAAQ;AAClB,2BAAK,QAAQ;AAAA,oBACd;AAAA,kBACD;AAAA,kBACA,EAAE,eAAe;AAAA,gBAClB;AAAA,cACD,CAAC,IACA,UAAU,QACTA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,UAAU,MAAM,WAAW,IAC1E;AAAA,cACJA,GAAE,OAAO,EAAE,OAAO,OAAO,QAAQ,GAAG;AAAA,gBACnCA;AAAA,kBACC;AAAA,kBACA;AAAA,oBACC,MAAM;AAAA,oBACN,UAAU,SAAS,SAAS,CAAC,MAAM;AAAA,oBACnC,OAAO,MAAM,QAAQ,OAAO,SAAS,OAAO;AAAA,kBAC7C;AAAA,kBACA,SAAS,QAAQ,EAAE,eAAe,IAAI,EAAE,aAAa;AAAA,gBACtD;AAAA,gBACA,CAAC,MAAM,SAAS,CAAC,SAAS,QACvBA,GAAE,QAAQ,EAAE,OAAO,OAAO,KAAK,GAAG,EAAE,4BAA4B,CAAC,IACjE;AAAA,gBACH,CAAC,MAAM,SACJA;AAAA,kBACA;AAAA,kBACA;AAAA,oBACC,MAAM;AAAA,oBACN,UAAU,WAAW;AAAA,oBACrB,SAAS,MAAM,KAAK,aAAa;AAAA,oBACjC,OAAO;AAAA,sBACN,GAAG,OAAO;AAAA,sBACV,QAAQ;AAAA,sBACR,YAAY;AAAA,sBACZ,OAAO;AAAA,sBACP,aACC;AAAA,oBACF;AAAA,kBACD;AAAA,kBACA,WAAW,QAAQ,EAAE,iBAAiB,IAAI,EAAE,eAAe;AAAA,gBAC5D,IACC;AAAA,cACJ,CAAC;AAAA,YACF,CAAC;AAAA,YACDA;AAAA,cACC;AAAA,cACA,EAAE,OAAO,OAAO,OAAO,KAAK,kBAAkB;AAAA,cAC9C,EAAE,6BAA6B;AAAA,YAChC;AAAA,YACAA,GAAE,YAAY;AAAA,cACb,IAAI;AAAA,cACJ,OAAO,OAAO;AAAA,cACd,MAAM;AAAA,cACN,YAAY;AAAA,cACZ,OAAO,WAAW;AAAA,cAClB,SAAS,CAAC,MAAa;AACtB,2BAAW,QAAS,EAAE,OAA+B;AAAA,cACtD;AAAA,YACD,CAAC;AAAA,YACD,YAAY,QACTA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,EAAE,YAAY,KAAK,CAAC,IACnE;AAAA,UACJ,CAAC;AAAA,UACDA,GAAE,OAAO,EAAE,OAAO,OAAO,cAAc,GAAG;AAAA,YACzCA,GAAE,OAAO,EAAE,OAAO,OAAO,cAAc,GAAG;AAAA,cACzCA,GAAE,QAAQ,EAAE,OAAO,OAAO,MAAM,GAAG,EAAE,0BAA0B,CAAC;AAAA,cAChEA;AAAA,gBACC;AAAA,gBACA,EAAE,OAAO,OAAO,KAAK;AAAA,gBACrB,aAAa,QAAQ,EAAE,4BAA4B,IAAI,EAAE,uBAAuB;AAAA,cACjF;AAAA,YACD,CAAC;AAAA,YACD,aAAa,QACVA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,aAAa,MAAM,WAAW,IAC7E;AAAA,YACH,QAAQ,OAAO,UACZA,GAAE,KAAK,EAAE,OAAO,OAAO,eAAe,GAAG,QAAQ,MAAM,OAAO,IAC9D;AAAA,YACH,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA,cAIbA,GAAE,UAAU;AAAA,gBACX,OAAO,EAAE,+BAA+B;AAAA,gBACxC,OAAO,OAAO;AAAA,gBACd,SAAS;AAAA,gBACT,QAAQ,QAAQ,MAAM;AAAA,cACvB,CAAC;AAAA,gBACA,QAAQ,QACPA,GAAE,OAAO,EAAE,OAAO,OAAO,YAAY,GAAG,QAAQ,MAAM,IAAI,IAC1DA,GAAE,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,EAAE,kCAAkC,CAAC;AAAA,UACzE,CAAC;AAAA,QACF,CAAC;AAAA,QACD,UAAU,MAAM,SAAS,IACtBA,GAAE,OAAO,EAAE,OAAO,OAAO,UAAU,GAAG;AAAA,UACtCA,GAAE,MAAM,EAAE,OAAO,OAAO,SAAS,GAAG,EAAE,0BAA0B,CAAC;AAAA,UACjEA,GAAE,MAAM,EAAE,OAAO,OAAO,KAAK,GAAG,UAAU,MAAM,IAAI,cAAc,CAAC;AAAA,QACpE,CAAC,IACA;AAAA,MACJ,CAAC;AAAA,IACF;AAAA,EACD;AACD,CAAC;;;ACjdD,SAAS,gBAAAC,eAAc,wBAAAC,6BAA4B;AAEnD,SAAS,gBAAAC,qBAAoB;AAE7B,SAAS,mBAAAC,kBAAiB,KAAAC,UAAS;AAGnC,IAAM,UAAyB;AAAA,EAC9B,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,OAAO;AACR;AAEA,IAAM,OAAsB;AAAA,EAC3B,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,YACC;AAAA,EACD,QAAQ;AACT;AACA,IAAM,eAA8B,EAAE,GAAG,MAAM,SAAS,KAAK,gBAAgB,eAAe;AAC5F,IAAM,MAAqB;AAAA,EAC1B,GAAG,OAAO;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,cAAc;AACf;AACA,IAAM,YAA2B,EAAE,GAAG,OAAO,WAAW,OAAO,QAAQ,MAAM,KAAK,UAAU,IAAI;AAChG,IAAM,QAAuB;AAAA,EAC5B,SAAS;AAAA,EACT,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,KAAK;AACN;AACA,IAAM,YAA2B;AAAA,EAChC,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,QAAQ;AACT;AAEO,IAAM,qBAAqBC,iBAAgB;AAAA,EACjD,MAAM;AAAA,EACN,OAAO;AAAA,IACN,QAAQ,EAAE,MAAM,QAAwC,UAAU,KAAK;AAAA;AAAA,IAEvE,aAAa,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA;AAAA,IAE7C,QAAQ,EAAE,MAAM,QAAiC,SAAS,OAAU;AAAA,EACrE;AAAA,EACA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKN,mBAAmB,CAAC,cAA8B;AAAA;AAAA,IAElD,mBAAmB,CAAC,aAAoC;AAAA,EACzD;AAAA,EACA,MAAM,OAAO,EAAE,KAAK,GAAG;AACtB,UAAM,EAAE,WAAW,WAAW,MAAM,IAAIC,cAAa,MAAM,MAAM;AACjE,UAAM,IAAI,CAAC,KAAsB,WAChCC,cAAa,MAAM,MAAM,EAAE,KAAK,MAAM;AAEvC,aAAS,UAAU,OAAuB;AACzC,YAAM,UAA0B,MAAM;AACtC,aAAOC,GAAE,MAAM,EAAE,KAAK,MAAM,MAAM,OAAO,IAAI,GAAG;AAAA,QAC/CA;AAAA,UACC;AAAA,UACA;AAAA,YACC,MAAM;AAAA,YACN,OAAO;AAAA,YACP,SAAS,MAAM,KAAK,mBAAmB,OAAO;AAAA,UAC/C;AAAA,UACA;AAAA,YACCA,GAAE,QAAQ,EAAE,OAAO,OAAO,KAAK,GAAG,MAAM,IAAI;AAAA,YAC5C,MAAM,SAASA,GAAE,QAAQ,EAAE,OAAO,QAAQ,GAAG,EAAE,wBAAwB,CAAC,IAAI;AAAA,YAC5EA,GAAE,QAAQ,EAAE,OAAO,QAAQ,SAAS,OAAO,SAAS,OAAO,SAAS,GAAG;AAAA,cACtEA,GAAE,QAAQ,EAAE,OAAO,OAAO,IAAI,CAAC;AAAA,cAC/B,QAAQ,SAAS,EAAE,sBAAsB,IAAI,EAAE,wBAAwB;AAAA,YACxE,CAAC;AAAA,UACF;AAAA,QACD;AAAA;AAAA,QAEAA;AAAA,UACC;AAAA,UACA,EAAE,OAAO,MAAM;AAAA,UACf,MAAM,QAAQ,IAAI,CAAC,UAAU;AAC5B,kBAAM,OAAO,MAAM,UAAU,EAAE,uBAAuB;AACtD,mBAAOA;AAAA,cACN;AAAA,cACA;AAAA,gBACC,KAAK,MAAM,UAAU;AAAA,gBACrB,MAAM;AAAA,gBACN,OAAO,MAAM,SAAS,OAAO;AAAA,gBAC7B,cAAc,EAAE,6BAA6B,EAAE,MAAM,MAAM,MAAM,QAAQ,KAAK,CAAC;AAAA,gBAC/E,OAAO,MAAM,SAAS,SAAY,EAAE,wBAAwB;AAAA,gBAC5D,SAAS,MAAM,KAAK,mBAAmB,KAAK;AAAA,cAC7C;AAAA,cACA;AAAA,YACD;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD,CAAC;AAAA,IACF;AAEA,WAAO,MACNA,GAAE,OAAO,EAAE,OAAO,OAAO,cAAc,GAAG;AAAA,MACzCA;AAAA,QACC;AAAA,QACA;AAAA,UACC,OAAO;AAAA,YACN,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,gBAAgB;AAAA,YAChB,KAAK;AAAA,UACN;AAAA,QACD;AAAA,QACA;AAAA,UACCA,GAAE,MAAM,EAAE,OAAO,OAAO,UAAU,GAAG,EAAE,sBAAsB,CAAC;AAAA,UAC9D,MAAM,cACHA;AAAA,YACA;AAAA,YACA;AAAA,cACC,MAAM;AAAA,cACN,OAAO;AAAA,cACP,SAAS,MACR,KAAK,mBAAmB;AAAA,gBACvB,SAAS;AAAA,kBACR,GAAG,IAAI;AAAA,oBACN,UAAU,MACR,IAAI,CAAC,QAAQ,IAAI,MAAM,EACvB,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AAAA,kBACjC;AAAA,gBACD;AAAA,cACD,CAAC;AAAA,YACH;AAAA,YACA,EAAE,4BAA4B;AAAA,UAC/B,IACC;AAAA,QACJ;AAAA,MACD;AAAA,MACAA,GAAE,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,EAAE,qBAAqB,CAAC;AAAA,MACvD,UAAU,QACPA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE,wBAAwB,CAAC,IAC5D,MAAM,QACLA,GAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,MAAM,MAAM,WAAW,IACtEA,GAAE,MAAM,EAAE,OAAO,OAAO,KAAK,GAAGC,sBAAqB,UAAU,KAAK,EAAE,IAAI,SAAS,CAAC;AAAA,IACzF,CAAC;AAAA,EACH;AACD,CAAC;","names":["createAdminT","defineComponent","h","ref","defineComponent","createAdminT","ref","h","createAdminT","groupTemplatesByType","useTemplates","defineComponent","h","defineComponent","useTemplates","createAdminT","h","groupTemplatesByType"]}
|
|
1
|
+
{"version":3,"sources":["../src/screens/TemplateCreateScreen.ts","../src/styles.ts","../src/screens/TemplateEditorScreen.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tISetTemplateInput,\n} from '@fonderie/client';\nimport { createAdminT, FonderieApiError } from '@fonderie/client';\nimport { useTemplatePreview } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { computed, defineComponent, h, onMounted, ref, watch } from 'vue';\nimport { styles } from '../styles';\n\nconst TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;\nconst LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;\n// Variables the layout injects — never sample values, as in the editor.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\nconst PREVIEW_DEBOUNCE_MS = 500;\nconst notice = {\n\tfontSize: '13px',\n\tcolor: 'var(--fonderie-text,#171717)',\n\tbackground: 'color-mix(in srgb, var(--fonderie-warning,#f5a623) 16%, transparent)',\n\tborderRadius: '6px',\n\tpadding: '8px 12px',\n\tmargin: '12px 0 0',\n};\n\n// Creating is its own screen: the editor loads an existing row, and a new\n// template or locale has none yet. Once saved, the editor takes over.\nexport const TemplateCreateScreen = defineComponent({\n\tname: 'FonderieTemplateCreateScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/**\n\t\t * Given ⇒ add a LOCALE of this existing template: the type is fixed and the\n\t\t * form starts from its default-locale copy. Omitted ⇒ a brand-new template\n\t\t * type (one the app sends that has no stored copy yet).\n\t\t */\n\t\ttype: { type: String, default: undefined },\n\t\t/** Locales already in use, offered as suggestions. */\n\t\tlocales: { type: Array as PropType<string[]>, default: () => [] },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/** What was created, so the caller can open it in the editor. */\n\t\tcreated: (_created: { type: string; locale: string | null }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst addingLocale = props.type !== undefined;\n\t\tconst newType = ref('');\n\t\tconst targetLocale = ref('');\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst error = ref<string | null>(null);\n\t\tconst busy = ref(false);\n\t\t// The default copy this locale started from, to flag fields not yet translated.\n\t\tconst source = ref<{ subject: string; html: string; text: string } | null>(null);\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Each variable renders as its own name, so the preview shows where it\n\t\t// lands. Learned from the server's answer, not re-parsed here.\n\t\tlet variables: string[] = [];\n\t\t// `tr`, not `t`: submit() uses `t` for the template type.\n\t\tconst tr = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\t// A new locale starts from the default copy, so translating is editing.\n\t\tonMounted(() => {\n\t\t\tif (!props.type) return;\n\t\t\tprops.client\n\t\t\t\t.getTemplate(props.type, null)\n\t\t\t\t.then(({ result }) => {\n\t\t\t\t\tsubject.value = result.subject ?? '';\n\t\t\t\t\thtml.value = result.html ?? '';\n\t\t\t\t\ttext.value = result.text;\n\t\t\t\t\tsource.value = {\n\t\t\t\t\t\tsubject: result.subject ?? '',\n\t\t\t\t\t\thtml: result.html ?? '',\n\t\t\t\t\t\ttext: result.text,\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t\t.catch(() => undefined);\n\t\t});\n\n\t\t// Live preview, as in the editor: translating is where it matters most — a\n\t\t// half-translated email looks finished in a textarea and wrong in the render.\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([newType, targetLocale, subject, html, text], () => {\n\t\t\tclearTimeout(timer);\n\t\t\tconst type = addingLocale ? (props.type as string) : newType.value.trim();\n\t\t\tconst l = targetLocale.value.trim();\n\t\t\tif (!TYPE_RE.test(type) || !text.value.trim()) return;\n\t\t\ttimer = setTimeout(async () => {\n\t\t\t\tconst input = {\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t};\n\t\t\t\tconst render = () =>\n\t\t\t\t\trenderPreview(\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\t{ ...input, data: Object.fromEntries(variables.map((v) => [v, v])) },\n\t\t\t\t\t\tLOCALE_RE.test(l) ? l : null,\n\t\t\t\t\t);\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await render();\n\t\t\t\t\tconst used = result.variables.filter((v) => !IMPLICIT.has(v));\n\t\t\t\t\t// A variable not seen before rendered empty: render once more with it.\n\t\t\t\t\tif (used.some((v) => !variables.includes(v))) {\n\t\t\t\t\t\tvariables = used;\n\t\t\t\t\t\tawait render();\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Shown through previewError.\n\t\t\t\t}\n\t\t\t}, PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\tconst untranslated = computed(() => {\n\t\t\tconst src = source.value;\n\t\t\tif (!src) return [];\n\t\t\treturn [\n\t\t\t\tsubject.value && subject.value === src.subject ? tr('templates.subject') : null,\n\t\t\t\thtml.value && html.value === src.html ? tr('templates.htmlBody') : null,\n\t\t\t\ttext.value === src.text ? tr('templates.textBody') : null,\n\t\t\t].filter((f): f is string => f !== null);\n\t\t});\n\n\t\tasync function submit(e: Event) {\n\t\t\te.preventDefault();\n\t\t\terror.value = null;\n\t\t\tconst t = addingLocale ? (props.type as string) : newType.value.trim();\n\t\t\tconst l = targetLocale.value.trim() || null;\n\t\t\tif (!TYPE_RE.test(t)) {\n\t\t\t\terror.value = tr('templates.create.errorType');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (addingLocale && !l) {\n\t\t\t\terror.value = tr('templates.create.errorLocaleRequired');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (l && !LOCALE_RE.test(l)) {\n\t\t\t\terror.value = tr('templates.create.errorLocale');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!text.value.trim()) {\n\t\t\t\terror.value = tr('templates.create.errorText');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbusy.value = true;\n\t\t\ttry {\n\t\t\t\t// Refuse to overwrite: creating an existing row would replace it.\n\t\t\t\tconst exists = await props.client.getTemplate(t, l).then(\n\t\t\t\t\t() => true,\n\t\t\t\t\t(err: unknown) => !(err instanceof FonderieApiError && err.status === 404),\n\t\t\t\t);\n\t\t\t\tif (exists) {\n\t\t\t\t\terror.value = l\n\t\t\t\t\t\t? tr('templates.create.existsLocale', { type: t, locale: l })\n\t\t\t\t\t\t: tr('templates.create.exists', { type: t });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: true };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tawait props.client.setTemplate(t, input, l);\n\t\t\t\temit('created', { type: t, locale: l });\n\t\t\t} catch (err) {\n\t\t\t\terror.value = err instanceof FonderieApiError ? err.explanation : String(err);\n\t\t\t} finally {\n\t\t\t\tbusy.value = false;\n\t\t\t}\n\t\t}\n\n\t\tconst field = (\n\t\t\tid: string,\n\t\t\tlabel: string,\n\t\t\tmodel: typeof subject,\n\t\t\topts: Record<string, unknown> = {},\n\t\t) => [\n\t\t\th('label', { style: styles.label, for: id }, label),\n\t\t\th(opts.textarea ? 'textarea' : 'input', {\n\t\t\t\tid,\n\t\t\t\tstyle: opts.textarea ? { ...styles.textarea, minHeight: opts.minHeight } : styles.input,\n\t\t\t\tvalue: model.value,\n\t\t\t\tautocomplete: 'off',\n\t\t\t\tspellcheck: false,\n\t\t\t\t...(opts.placeholder ? { placeholder: opts.placeholder } : {}),\n\t\t\t\t...(opts.list ? { list: opts.list } : {}),\n\t\t\t\tonInput: (ev: Event) => {\n\t\t\t\t\tmodel.value = (ev.target as HTMLInputElement).value;\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\n\t\treturn () =>\n\t\t\th('div', { style: styles.container }, [\n\t\t\t\th(\n\t\t\t\t\t'h1',\n\t\t\t\t\t{ style: styles.title },\n\t\t\t\t\taddingLocale\n\t\t\t\t\t\t? tr('templates.create.titleLocale', { type: props.type as string })\n\t\t\t\t\t\t: tr('templates.create.titleNew'),\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: { ...styles.meta, lineHeight: 1.5 } },\n\t\t\t\t\taddingLocale ? tr('templates.create.hintLocale') : tr('templates.create.hintNew'),\n\t\t\t\t),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\t\th('form', { style: styles.form, onSubmit: (ev: Event) => void submit(ev) }, [\n\t\t\t\t\t\t...(addingLocale\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: field('new-template-type', tr('templates.create.type'), newType, {\n\t\t\t\t\t\t\t\t\tplaceholder: 'weekly-digest',\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t...field(\n\t\t\t\t\t\t\t'new-template-locale',\n\t\t\t\t\t\t\taddingLocale ? tr('templates.create.locale') : tr('templates.create.localeOptional'),\n\t\t\t\t\t\t\ttargetLocale,\n\t\t\t\t\t\t\t{ placeholder: 'fr', list: 'new-template-locales' },\n\t\t\t\t\t\t),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'datalist',\n\t\t\t\t\t\t\t{ id: 'new-template-locales' },\n\t\t\t\t\t\t\t[...new Set(props.locales)].map((l) => h('option', { key: l, value: l })),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t...field('new-template-subject', tr('templates.subject'), subject),\n\t\t\t\t\t\t...field('new-template-html', tr('templates.htmlBody'), html, {\n\t\t\t\t\t\t\ttextarea: true,\n\t\t\t\t\t\t\tminHeight: '160px',\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t...field('new-template-text', tr('templates.textBody'), text, {\n\t\t\t\t\t\t\ttextarea: true,\n\t\t\t\t\t\t\tminHeight: '100px',\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tuntranslated.value.length > 0\n\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t'p',\n\t\t\t\t\t\t\t\t\t{ style: notice },\n\t\t\t\t\t\t\t\t\ttr('templates.create.untranslated', { fields: untranslated.value.join(', ') }),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\terror.value ? h('p', { style: styles.error, role: 'alert' }, error.value) : null,\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\tdisabled: busy.value,\n\t\t\t\t\t\t\t\tstyle: { ...styles.button, marginTop: '16px' },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbusy.value\n\t\t\t\t\t\t\t\t? tr('templates.create.creating')\n\t\t\t\t\t\t\t\t: addingLocale\n\t\t\t\t\t\t\t\t\t? tr('templates.create.submitLocale')\n\t\t\t\t\t\t\t\t\t: tr('templates.create.submitNew'),\n\t\t\t\t\t\t),\n\t\t\t\t\t]),\n\t\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\t\th('span', { style: styles.label }, tr('templates.editor.preview')),\n\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t\t\t\tisPreviewing.value ? tr('templates.editor.rendering') : tr('templates.editor.live'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin: operator-authored HTML must\n\t\t\t\t\t\t\t\t// never execute in the console's origin.\n\t\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\t\ttitle: tr('templates.editor.previewTitle'),\n\t\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t\t: h('p', { style: styles.meta }, tr('templates.editor.nothingRendered')),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t]);\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '8px 40px 64px', maxWidth: '1400px', boxSizing: 'border-box' },\n\t// Two columns, always: editor left, rendered result right. Stacking the\n\t// preview under a long form hid it below the fold.\n\tsplit: {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',\n\t\tgap: '24px',\n\t\talignItems: 'start',\n\t},\n\tcolumn: { minWidth: '0', display: 'flex', flexDirection: 'column' },\n\t// Pinned while the form scrolls, so the preview stays in view as you edit.\n\tpreviewColumn: {\n\t\tminWidth: '0',\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tposition: 'sticky',\n\t\ttop: '16px',\n\t},\n\tsaveRow: { display: 'flex', alignItems: 'center', gap: '12px', marginTop: '16px' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '8px 0 4px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\tsubtitle: {\n\t\tfontSize: '15px',\n\t\tfontWeight: 600,\n\t\tmargin: '0 0 10px',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t},\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '20px' },\n\tstatus: { padding: '24px 0', color: 'var(--fonderie-text-muted,#5c5c5c)', fontSize: '13.5px' },\n\terror: {\n\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)',\n\t\tborderRadius: '6px',\n\t\tpadding: '8px 12px',\n\t\tmargin: '8px 0',\n\t\tfontSize: '13.5px',\n\t},\n\tlist: {\n\t\tlistStyle: 'none',\n\t\tpadding: '0',\n\t\tmargin: '0',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\toverflow: 'hidden',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '16px',\n\t\tpadding: '13px 16px',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily: 'inherit',\n\t},\n\ttype: {\n\t\tfontSize: '13px',\n\t\tfontWeight: 600,\n\t\tflex: '1',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tlocale: { fontSize: '12.5px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-accent-strong,#009767)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-accent-strong,#009767) 13%, transparent)',\n\t},\n\tinactive: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\tgap: '6px',\n\t\tborderRadius: '999px',\n\t\tpadding: '2px 9px 2px 8px',\n\t\tfontSize: '12px',\n\t\tfontWeight: 600,\n\t\tlineHeight: 1.5,\n\t\tminWidth: '64px',\n\t\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\t\tbackground: 'color-mix(in srgb, var(--fonderie-text-muted,#5c5c5c) 10%, transparent)',\n\t},\n\tform: {\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\tgap: '4px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: 'var(--fonderie-radius-lg,8px)',\n\t\tpadding: '6px 20px 20px',\n\t\tboxShadow: 'var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))',\n\t},\n\tlabel: { fontSize: '13px', fontWeight: 500, marginTop: '14px', marginBottom: '2px' },\n\tinput: {\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '13.5px',\n\t\tfontFamily: 'inherit',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t},\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '10px',\n\t\tfontSize: '13px',\n\t\tlineHeight: 1.55,\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tfontFamily:\n\t\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\tcursor: 'pointer',\n\t},\n\tbuttonDisabled: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '36px',\n\t\tboxSizing: 'border-box',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '0 16px',\n\t\tborderRadius: '6px',\n\t\tborder: '1px solid var(--fonderie-text,#171717)',\n\t\tfontSize: '13.5px',\n\t\tfontWeight: 600,\n\t\tfontFamily: 'inherit',\n\t\talignSelf: 'flex-start',\n\t\topacity: 0.45,\n\t\tcursor: 'not-allowed',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tgap: '12px',\n\t\tpadding: '9px 16px',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tdisplay: 'inline-flex',\n\t\talignItems: 'center',\n\t\theight: '28px',\n\t\tboxSizing: 'border-box',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t\tcolor: 'var(--fonderie-text,#171717)',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '6px',\n\t\tpadding: '0 10px',\n\t\tfontSize: '12.5px',\n\t\tfontWeight: 500,\n\t\tfontFamily: 'inherit',\n\t\tcursor: 'pointer',\n\t},\n\t// Template list: matches @fonderie/vue-admin-screens' shell look with local\n\t// values — this package sits below the admin screens and cannot import them.\n\tlistContainer: { padding: '32px 40px 64px', maxWidth: '1160px', boxSizing: 'border-box' },\n\tlistTitle: {\n\t\tfontSize: '22px',\n\t\tfontWeight: 600,\n\t\tmargin: '0',\n\t\tletterSpacing: 'var(--fonderie-tracking-display,-0.05em)',\n\t\tlineHeight: 1.25,\n\t},\n\thint: { fontSize: '13.5px', color: 'var(--fonderie-text-muted,#5c5c5c)', margin: '4px 0 24px' },\n\tdot: { width: '6px', height: '6px', borderRadius: '999px', background: 'currentColor' },\n};\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateEntry,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tcreateAdminT,\n\tformatAdminDate,\n\tgroupTemplatesByType,\n\tmissingTemplateLocales,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { computed, defineComponent, h, ref, watch } from 'vue';\n\nconst PREVIEW_DEBOUNCE_MS = 500;\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\n// One tab per locale of this email, underlined like a document's tabs.\nconst tab: CSSProperties = {\n\theight: '32px',\n\tpadding: '0 10px',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderBottom: '2px solid transparent',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\tfontSize: '13px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst tabSelected: CSSProperties = {\n\t...tab,\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontWeight: 600,\n\tborderBottomColor: 'var(--fonderie-text,#171717)',\n\tcursor: 'default',\n};\nconst tabInactive: CSSProperties = { ...tab, opacity: 0.55, textDecoration: 'line-through' };\nconst tabBar: CSSProperties = {\n\tdisplay: 'flex',\n\talignItems: 'flex-end',\n\tgap: '12px',\n\tborderBottom: '1px solid var(--fonderie-border,#e0e0e0)',\n\tmargin: '4px 0 12px',\n\tpaddingBottom: '6px',\n};\nconst tabs: CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: '4px', marginBottom: '-7px' };\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t\t/**\n\t\t * A built-in email's default-locale row (the list's `system` flag): it can\n\t\t * be edited and rolled back, never deleted — Delete is not offered.\n\t\t */\n\t\tsystem: { type: Boolean, default: false },\n\t\t/** Shows \"+ Add locale\" (emits add-locale). */\n\t\tallowAddLocale: { type: Boolean, default: false },\n\t\t/**\n\t\t * Shows a tab per locale this email exists in (emits select-locale).\n\t\t * Unsaved edits are confirmed before switching away.\n\t\t */\n\t\tlocaleTabs: { type: Boolean, default: false },\n\t\t/** The console language (`locale` is the template's); defaults to English. */\n\t\tuiLocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t\t/** The template was deleted and no longer exists. */\n\t\tdeleted: () => true,\n\t\t/**\n\t\t * Create a translation of this template. `locales` are the ones the app\n\t\t * uses elsewhere that this email lacks — suggest them first.\n\t\t */\n\t\t'add-locale': (_type: string, _context: { locales: string[] }) => true,\n\t\t/** Open another locale of this email. */\n\t\t'select-locale': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.uiLocale)(key, params);\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { templates, saveTemplate, removeTemplate } = useTemplates(props.client);\n\t\t// This email's locales, for the tabs. The list is already fetched for saves.\n\t\tconst siblings = computed(\n\t\t\t() => groupTemplatesByType(templates.value).find((g) => g.type === props.type)?.entries ?? [],\n\t\t);\n\t\tconst isDeleting = ref(false);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<AdminMessageKey | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'templates.editor.sampleNotObject';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'templates.editor.sampleInvalid';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// The preview is always live: it renders once the template loads, then\n\t\t// again PREVIEW_DEBOUNCE_MS after the last edit to the content or the sample\n\t\t// data — debounced, so typing a paragraph costs one request, not one per key.\n\t\tlet previewTimer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([template, subject, html, text, sampleJson], () => {\n\t\t\tif (!template.value) return;\n\t\t\tclearTimeout(previewTimer);\n\t\t\tpreviewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\t// Saving what is already stored would only mint an identical version (the\n\t\t// server treats it as a no-op anyway), so Save waits for a real change.\n\t\tconst dirty = computed(() => {\n\t\t\tconst tpl = template.value;\n\t\t\treturn (\n\t\t\t\t!!tpl &&\n\t\t\t\t(subject.value !== (tpl.subject ?? '') ||\n\t\t\t\t\thtml.value !== (tpl.html ?? '') ||\n\t\t\t\t\ttext.value !== tpl.text ||\n\t\t\t\t\tactive.value !== tpl.active)\n\t\t\t);\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\t// Leaving a locale with unsaved edits asks first: they would be lost.\n\t\tconst leave = () => !dirty.value || window.confirm(t('templates.editor.discardChanges'));\n\n\t\tfunction renderTabBar() {\n\t\t\tif (!props.localeTabs && !props.allowAddLocale) return null;\n\t\t\treturn h('div', { style: tabBar }, [\n\t\t\t\tprops.localeTabs\n\t\t\t\t\t? // Each tab opens another stored row, so this is navigation, not an\n\t\t\t\t\t\t// ARIA tablist: plain buttons, the open one marked aria-current.\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'nav',\n\t\t\t\t\t\t\t{ 'aria-label': t('templates.editor.locales'), style: tabs },\n\t\t\t\t\t\t\tsiblings.value.map((entry) => {\n\t\t\t\t\t\t\t\tconst selected = entry.locale === (props.locale ?? null);\n\t\t\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t'aria-current': selected ? 'true' : undefined,\n\t\t\t\t\t\t\t\t\t\tstyle: selected ? tabSelected : entry.active ? tab : tabInactive,\n\t\t\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\tif (!selected && leave()) emit('select-locale', entry);\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tentry.locale ?? t('templates.defaultChip'),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t\tprops.allowAddLocale\n\t\t\t\t\t? h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: { ...styles.rollbackButton, marginLeft: 'auto' },\n\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\tif (leave())\n\t\t\t\t\t\t\t\t\t\temit('add-locale', props.type, {\n\t\t\t\t\t\t\t\t\t\t\tlocales: missingTemplateLocales(templates.value, props.type),\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tt('templates.editor.addLocale'),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t}\n\n\t\tasync function handleDelete() {\n\t\t\tconst message = props.locale\n\t\t\t\t? t('templates.editor.confirmDeleteLocale', { locale: props.locale, type: props.type })\n\t\t\t\t: t('templates.editor.confirmDelete', { type: props.type });\n\t\t\tif (!window.confirm(message)) return;\n\t\t\tisDeleting.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tawait removeTemplate(props.type, props.locale);\n\t\t\t\temit('deleted');\n\t\t\t} catch (err) {\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisDeleting.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? t('templates.editor.unknownActor')} — ${formatAdminDate(rev.createdAt, props.uiLocale)}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\tt('templates.editor.rollBack'),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, t('templates.editor.loading'));\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\trenderTabBar(),\n\t\t\t\th('p', { style: styles.meta }, [\n\t\t\t\t\th('strong', props.locale ?? t('templates.defaultLocale')),\n\t\t\t\t\t` · v${template.value?.version ?? 1}`,\n\t\t\t\t\tprops.system ? ` · ${t('templates.editor.builtInNote')}` : '',\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, t('templates.subject')),\n\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, t('templates.htmlBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, t('templates.textBody')),\n\t\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tt('templates.editor.active'),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\tsaveError.value?.reason === 'VERSION_CONFLICT'\n\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, [\n\t\t\t\t\t\t\t\t\t\t`${t('templates.editor.conflict')} `,\n\t\t\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsaveError.value = null;\n\t\t\t\t\t\t\t\t\t\t\t\t\tvoid refresh();\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tt('common.reload'),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t\t: saveError.value\n\t\t\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\th('div', { style: styles.saveRow }, [\n\t\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\t\t\tdisabled: isSaving.value || !dirty.value,\n\t\t\t\t\t\t\t\t\t\tstyle: dirty.value ? styles.button : styles.buttonDisabled,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tisSaving.value ? t('common.saving') : t('common.save'),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t!dirty.value && !isSaving.value\n\t\t\t\t\t\t\t\t\t? h('span', { style: styles.meta }, t('templates.editor.noChanges'))\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t!props.system\n\t\t\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled: isDeleting.value,\n\t\t\t\t\t\t\t\t\t\t\t\tonClick: () => void handleDelete(),\n\t\t\t\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t...styles.rollbackButton,\n\t\t\t\t\t\t\t\t\t\t\t\t\theight: '36px',\n\t\t\t\t\t\t\t\t\t\t\t\t\tmarginLeft: 'auto',\n\t\t\t\t\t\t\t\t\t\t\t\t\tcolor: 'var(--fonderie-danger,#e00)',\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderColor:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)',\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tisDeleting.value ? t('common.deleting') : t('common.delete'),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'label',\n\t\t\t\t\t\t\t{ style: styles.label, for: 'template-sample' },\n\t\t\t\t\t\t\tt('templates.editor.sampleData'),\n\t\t\t\t\t\t),\n\t\t\t\t\t\th('textarea', {\n\t\t\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t\tspellcheck: false,\n\t\t\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tsampleError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, t(sampleError.value))\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t]),\n\t\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\t\th('span', { style: styles.label }, t('templates.editor.preview')),\n\t\t\t\t\t\t\th(\n\t\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t\t\t\tisPreviewing.value ? t('templates.editor.rendering') : t('templates.editor.live'),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t]),\n\t\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\t\ttitle: t('templates.editor.previewTitle'),\n\t\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t\t: h('p', { style: styles.meta }, t('templates.editor.nothingRendered')),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, t('templates.editor.history')),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type {\n\tAdminLocale,\n\tAdminMessageKey,\n\tAdminMessageParams,\n\tCourierAdminClient,\n\tITemplateEntry,\n} from '@fonderie/client';\nimport { createAdminT, groupTemplatesByType } from '@fonderie/client';\nimport type { ITemplateGroup } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { CSSProperties, PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nconst builtIn: CSSProperties = {\n\tfontSize: '11px',\n\tfontWeight: 500,\n\tpadding: '1px 7px',\n\tborderRadius: '999px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n};\n// One per locale the email exists in. Monospace: they are language tags.\nconst chip: CSSProperties = {\n\theight: '24px',\n\tboxSizing: 'border-box',\n\tpadding: '0 8px',\n\tborderRadius: '6px',\n\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\tbackground: 'var(--fonderie-surface,#fff)',\n\tcolor: 'var(--fonderie-text,#171717)',\n\tfontSize: '12px',\n\tfontFamily:\n\t\t'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\tcursor: 'pointer',\n};\nconst chipInactive: CSSProperties = { ...chip, opacity: 0.5, textDecoration: 'line-through' };\nconst row: CSSProperties = {\n\t...styles.row,\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '8px',\n\tpaddingRight: '16px',\n};\nconst rowButton: CSSProperties = { ...styles.rowButton, width: 'auto', flex: '1', minWidth: '0' };\nconst chips: CSSProperties = {\n\tdisplay: 'flex',\n\tflexWrap: 'wrap',\n\tjustifyContent: 'flex-end',\n\tgap: '6px',\n};\nconst newButton: CSSProperties = {\n\tdisplay: 'inline-flex',\n\talignItems: 'center',\n\theight: '32px',\n\tboxSizing: 'border-box',\n\tborderRadius: '6px',\n\tpadding: '0 12px',\n\tfontSize: '13px',\n\tfontWeight: 500,\n\tfontFamily: 'inherit',\n\tcursor: 'pointer',\n\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\tcolor: 'var(--fonderie-surface,#fff)',\n\tborder: '1px solid var(--fonderie-text,#171717)',\n};\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\t/** Shows a \"New template\" button (emits create-template). */\n\t\tallowCreate: { type: Boolean, default: false },\n\t\t/** The console language; defaults to English. */\n\t\tlocale: { type: String as PropType<AdminLocale>, default: undefined },\n\t},\n\temits: {\n\t\t/**\n\t\t * The whole row — type AND locale, and whether it is built-in. One row\n\t\t * per email: the row opens the default locale, a locale chip that locale.\n\t\t */\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t\t/** Receives the locales in use, to suggest. */\n\t\t'create-template': (_context: { locales: string[] }) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\t\tconst t = (key: AdminMessageKey, params?: AdminMessageParams) =>\n\t\t\tcreateAdminT(props.locale)(key, params);\n\n\t\tfunction renderRow(group: ITemplateGroup) {\n\t\t\tconst primary: ITemplateEntry = group.primary;\n\t\t\treturn h('li', { key: group.type, style: row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', primary),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, group.type),\n\t\t\t\t\t\tgroup.system ? h('span', { style: builtIn }, t('templates.builtInBadge')) : null,\n\t\t\t\t\t\th('span', { style: primary.active ? styles.active : styles.inactive }, [\n\t\t\t\t\t\t\th('span', { style: styles.dot }),\n\t\t\t\t\t\t\tprimary.active ? t('common.status.active') : t('common.status.inactive'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\t// Siblings of the row button, not inside it: a button cannot hold buttons.\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t{ style: chips },\n\t\t\t\t\tgroup.entries.map((entry) => {\n\t\t\t\t\t\tconst name = entry.locale ?? t('templates.defaultChip');\n\t\t\t\t\t\treturn h(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: entry.locale ?? '',\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: entry.active ? chip : chipInactive,\n\t\t\t\t\t\t\t\t'aria-label': t('templates.list.openLocale', { type: group.type, locale: name }),\n\t\t\t\t\t\t\t\ttitle: entry.active ? undefined : t('common.status.inactive'),\n\t\t\t\t\t\t\t\tonClick: () => emit('select-template', entry),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () =>\n\t\t\th('div', { style: styles.listContainer }, [\n\t\t\t\th(\n\t\t\t\t\t'div',\n\t\t\t\t\t{\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\t\tjustifyContent: 'space-between',\n\t\t\t\t\t\t\tgap: '16px',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('h1', { style: styles.listTitle }, t('templates.list.title')),\n\t\t\t\t\t\tprops.allowCreate\n\t\t\t\t\t\t\t? h(\n\t\t\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\t\tstyle: newButton,\n\t\t\t\t\t\t\t\t\t\tonClick: () =>\n\t\t\t\t\t\t\t\t\t\t\temit('create-template', {\n\t\t\t\t\t\t\t\t\t\t\t\tlocales: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t...new Set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemplates.value\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map((tpl) => tpl.locale)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter((l): l is string => !!l),\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tt('templates.list.newTemplate'),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t\th('p', { style: styles.hint }, t('templates.list.hint')),\n\t\t\t\tisLoading.value\n\t\t\t\t\t? h('p', { style: styles.status }, t('templates.list.loading'))\n\t\t\t\t\t: error.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, error.value.explanation)\n\t\t\t\t\t\t: h('ul', { style: styles.list }, groupTemplatesByType(templates.value).map(renderRow)),\n\t\t\t]);\n\t},\n});\n"],"mappings":"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","names":["createAdminT","useTemplatePreview","computed","defineComponent","h","ref","watch","PREVIEW_DEBOUNCE_MS","IMPLICIT","defineComponent","createAdminT","computed","ref","watch","useTemplatePreview","h","createAdminT","groupTemplatesByType","useTemplates","defineComponent","h","defineComponent","useTemplates","createAdminT","h","groupTemplatesByType"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonderie/vue-courier-admin-screens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Pre-built Vue screens for the Fonderie courier admin API — template list, template editor with revision history and rollback.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fonderiejs",
|