@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 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: { ...styles.container, maxWidth: "760px" } }, [
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)("form", { style: styles.form, onSubmit: (ev) => void submit(ev) }, [
378
- ...addingLocale ? [] : field("new-template-type", tr("templates.create.type"), newType, { placeholder: "weekly-digest" }),
379
- ...field(
380
- "new-template-locale",
381
- addingLocale ? tr("templates.create.locale") : tr("templates.create.localeOptional"),
382
- targetLocale,
383
- { placeholder: "fr", list: "new-template-locales" }
384
- ),
385
- (0, import_vue.h)(
386
- "datalist",
387
- { id: "new-template-locales" },
388
- [...new Set(props.locales)].map((l) => (0, import_vue.h)("option", { key: l, value: l }))
389
- ),
390
- ...field("new-template-subject", tr("templates.subject"), subject),
391
- ...field("new-template-html", tr("templates.htmlBody"), html, { textarea: true, minHeight: "160px" }),
392
- ...field("new-template-text", tr("templates.textBody"), text, {
393
- textarea: true,
394
- minHeight: "100px"
395
- }),
396
- error.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, error.value) : null,
397
- (0, import_vue.h)(
398
- "button",
399
- {
400
- type: "submit",
401
- disabled: busy.value,
402
- style: { ...styles.button, marginTop: "16px" }
403
- },
404
- busy.value ? tr("templates.create.creating") : addingLocale ? tr("templates.create.submitLocale") : tr("templates.create.submitNew")
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 import_vue_courier_admin = require("@fonderie/vue-courier-admin");
508
+ var import_vue_courier_admin2 = require("@fonderie/vue-courier-admin");
414
509
  var import_vue2 = require("vue");
415
- var PREVIEW_DEBOUNCE_MS = 500;
416
- var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
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, import_vue_courier_admin.useTemplate)(
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, import_vue_courier_admin.useTemplates)(props.client);
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, import_vue_courier_admin.useTemplateRevisions)(props.client, props.type, props.locale);
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, import_vue_courier_admin.useTemplatePreview)(props.client);
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) => !IMPLICIT.has(v) && !(v in data));
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(), PREVIEW_DEBOUNCE_MS);
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 import_vue_courier_admin2 = require("@fonderie/vue-courier-admin");
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, import_vue_courier_admin2.useTemplates)(props.client);
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;
@@ -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 { defineComponent, h, onMounted, ref } from "vue";
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: { ...styles.container, maxWidth: "760px" } }, [
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("form", { style: styles.form, onSubmit: (ev) => void submit(ev) }, [
350
- ...addingLocale ? [] : field("new-template-type", tr("templates.create.type"), newType, { placeholder: "weekly-digest" }),
351
- ...field(
352
- "new-template-locale",
353
- addingLocale ? tr("templates.create.locale") : tr("templates.create.localeOptional"),
354
- targetLocale,
355
- { placeholder: "fr", list: "new-template-locales" }
356
- ),
357
- h(
358
- "datalist",
359
- { id: "new-template-locales" },
360
- [...new Set(props.locales)].map((l) => h("option", { key: l, value: l }))
361
- ),
362
- ...field("new-template-subject", tr("templates.subject"), subject),
363
- ...field("new-template-html", tr("templates.htmlBody"), html, { textarea: true, minHeight: "160px" }),
364
- ...field("new-template-text", tr("templates.textBody"), text, {
365
- textarea: true,
366
- minHeight: "100px"
367
- }),
368
- error.value ? h("p", { style: styles.error, role: "alert" }, error.value) : null,
369
- h(
370
- "button",
371
- {
372
- type: "submit",
373
- disabled: busy.value,
374
- style: { ...styles.button, marginTop: "16px" }
375
- },
376
- busy.value ? tr("templates.create.creating") : addingLocale ? tr("templates.create.submitLocale") : tr("templates.create.submitNew")
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 PREVIEW_DEBOUNCE_MS = 500;
398
- var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
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 = computed(
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
- watch(template, (tpl) => {
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
- } = useTemplatePreview(props.client);
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) => !IMPLICIT.has(v) && !(v in data));
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
- watch([template, subject, html, text, sampleJson], () => {
623
+ watch2([template, subject, html, text, sampleJson], () => {
529
624
  if (!template.value) return;
530
625
  clearTimeout(previewTimer);
531
- previewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);
626
+ previewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS2);
532
627
  });
533
- const dirty = computed(() => {
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":"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","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.9.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",