@fonderie/vue-courier-admin-screens 0.7.0 → 0.9.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 +220 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -8
- package/dist/index.d.ts +71 -8
- package/dist/index.js +226 -85
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -280,7 +280,9 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
280
280
|
*/
|
|
281
281
|
type: { type: String, default: void 0 },
|
|
282
282
|
/** Locales already in use, offered as suggestions. */
|
|
283
|
-
locales: { type: Array, default: () => [] }
|
|
283
|
+
locales: { type: Array, default: () => [] },
|
|
284
|
+
/** The console language; defaults to English. */
|
|
285
|
+
locale: { type: String, default: void 0 }
|
|
284
286
|
},
|
|
285
287
|
emits: {
|
|
286
288
|
/** What was created, so the caller can open it in the editor. */
|
|
@@ -289,12 +291,13 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
289
291
|
setup(props, { emit }) {
|
|
290
292
|
const addingLocale = props.type !== void 0;
|
|
291
293
|
const newType = (0, import_vue.ref)("");
|
|
292
|
-
const
|
|
294
|
+
const targetLocale = (0, import_vue.ref)("");
|
|
293
295
|
const subject = (0, import_vue.ref)("");
|
|
294
296
|
const html = (0, import_vue.ref)("");
|
|
295
297
|
const text = (0, import_vue.ref)("");
|
|
296
298
|
const error = (0, import_vue.ref)(null);
|
|
297
299
|
const busy = (0, import_vue.ref)(false);
|
|
300
|
+
const tr = (key, params) => (0, import_client.createAdminT)(props.locale)(key, params);
|
|
298
301
|
(0, import_vue.onMounted)(() => {
|
|
299
302
|
if (!props.type) return;
|
|
300
303
|
props.client.getTemplate(props.type, null).then(({ result }) => {
|
|
@@ -307,21 +310,21 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
307
310
|
e.preventDefault();
|
|
308
311
|
error.value = null;
|
|
309
312
|
const t = addingLocale ? props.type : newType.value.trim();
|
|
310
|
-
const l =
|
|
313
|
+
const l = targetLocale.value.trim() || null;
|
|
311
314
|
if (!TYPE_RE.test(t)) {
|
|
312
|
-
error.value = "
|
|
315
|
+
error.value = tr("templates.create.errorType");
|
|
313
316
|
return;
|
|
314
317
|
}
|
|
315
318
|
if (addingLocale && !l) {
|
|
316
|
-
error.value = "
|
|
319
|
+
error.value = tr("templates.create.errorLocaleRequired");
|
|
317
320
|
return;
|
|
318
321
|
}
|
|
319
322
|
if (l && !LOCALE_RE.test(l)) {
|
|
320
|
-
error.value = "
|
|
323
|
+
error.value = tr("templates.create.errorLocale");
|
|
321
324
|
return;
|
|
322
325
|
}
|
|
323
326
|
if (!text.value.trim()) {
|
|
324
|
-
error.value = "
|
|
327
|
+
error.value = tr("templates.create.errorText");
|
|
325
328
|
return;
|
|
326
329
|
}
|
|
327
330
|
busy.value = true;
|
|
@@ -331,7 +334,7 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
331
334
|
(err) => !(err instanceof import_client.FonderieApiError && err.status === 404)
|
|
332
335
|
);
|
|
333
336
|
if (exists) {
|
|
334
|
-
error.value =
|
|
337
|
+
error.value = l ? tr("templates.create.existsLocale", { type: t, locale: l }) : tr("templates.create.exists", { type: t });
|
|
335
338
|
return;
|
|
336
339
|
}
|
|
337
340
|
const input = { text: text.value, active: true };
|
|
@@ -364,19 +367,19 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
364
367
|
(0, import_vue.h)(
|
|
365
368
|
"h1",
|
|
366
369
|
{ style: styles.title },
|
|
367
|
-
addingLocale ?
|
|
370
|
+
addingLocale ? tr("templates.create.titleLocale", { type: props.type }) : tr("templates.create.titleNew")
|
|
368
371
|
),
|
|
369
372
|
(0, import_vue.h)(
|
|
370
373
|
"p",
|
|
371
374
|
{ style: { ...styles.meta, lineHeight: 1.5 } },
|
|
372
|
-
addingLocale ? "
|
|
375
|
+
addingLocale ? tr("templates.create.hintLocale") : tr("templates.create.hintNew")
|
|
373
376
|
),
|
|
374
377
|
(0, import_vue.h)("form", { style: styles.form, onSubmit: (ev) => void submit(ev) }, [
|
|
375
|
-
...addingLocale ? [] : field("new-template-type", "
|
|
378
|
+
...addingLocale ? [] : field("new-template-type", tr("templates.create.type"), newType, { placeholder: "weekly-digest" }),
|
|
376
379
|
...field(
|
|
377
380
|
"new-template-locale",
|
|
378
|
-
addingLocale ? "
|
|
379
|
-
|
|
381
|
+
addingLocale ? tr("templates.create.locale") : tr("templates.create.localeOptional"),
|
|
382
|
+
targetLocale,
|
|
380
383
|
{ placeholder: "fr", list: "new-template-locales" }
|
|
381
384
|
),
|
|
382
385
|
(0, import_vue.h)(
|
|
@@ -384,9 +387,9 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
384
387
|
{ id: "new-template-locales" },
|
|
385
388
|
[...new Set(props.locales)].map((l) => (0, import_vue.h)("option", { key: l, value: l }))
|
|
386
389
|
),
|
|
387
|
-
...field("new-template-subject", "
|
|
388
|
-
...field("new-template-html", "
|
|
389
|
-
...field("new-template-text", "
|
|
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, {
|
|
390
393
|
textarea: true,
|
|
391
394
|
minHeight: "100px"
|
|
392
395
|
}),
|
|
@@ -398,7 +401,7 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
398
401
|
disabled: busy.value,
|
|
399
402
|
style: { ...styles.button, marginTop: "16px" }
|
|
400
403
|
},
|
|
401
|
-
busy.value ? "
|
|
404
|
+
busy.value ? tr("templates.create.creating") : addingLocale ? tr("templates.create.submitLocale") : tr("templates.create.submitNew")
|
|
402
405
|
)
|
|
403
406
|
])
|
|
404
407
|
]);
|
|
@@ -406,10 +409,39 @@ var TemplateCreateScreen = (0, import_vue.defineComponent)({
|
|
|
406
409
|
});
|
|
407
410
|
|
|
408
411
|
// src/screens/TemplateEditorScreen.ts
|
|
412
|
+
var import_client2 = require("@fonderie/client");
|
|
409
413
|
var import_vue_courier_admin = require("@fonderie/vue-courier-admin");
|
|
410
414
|
var import_vue2 = require("vue");
|
|
411
415
|
var PREVIEW_DEBOUNCE_MS = 500;
|
|
412
416
|
var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
417
|
+
var tab = {
|
|
418
|
+
height: "32px",
|
|
419
|
+
padding: "0 10px",
|
|
420
|
+
background: "none",
|
|
421
|
+
border: "none",
|
|
422
|
+
borderBottom: "2px solid transparent",
|
|
423
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
424
|
+
fontSize: "13px",
|
|
425
|
+
fontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)',
|
|
426
|
+
cursor: "pointer"
|
|
427
|
+
};
|
|
428
|
+
var tabSelected = {
|
|
429
|
+
...tab,
|
|
430
|
+
color: "var(--fonderie-text,#171717)",
|
|
431
|
+
fontWeight: 600,
|
|
432
|
+
borderBottomColor: "var(--fonderie-text,#171717)",
|
|
433
|
+
cursor: "default"
|
|
434
|
+
};
|
|
435
|
+
var tabInactive = { ...tab, opacity: 0.55, textDecoration: "line-through" };
|
|
436
|
+
var tabBar = {
|
|
437
|
+
display: "flex",
|
|
438
|
+
alignItems: "flex-end",
|
|
439
|
+
gap: "12px",
|
|
440
|
+
borderBottom: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
441
|
+
margin: "4px 0 12px",
|
|
442
|
+
paddingBottom: "6px"
|
|
443
|
+
};
|
|
444
|
+
var tabs = { display: "flex", flexWrap: "wrap", gap: "4px", marginBottom: "-7px" };
|
|
413
445
|
var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
414
446
|
name: "FonderieTemplateEditorScreen",
|
|
415
447
|
props: {
|
|
@@ -421,23 +453,39 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
421
453
|
* be edited and rolled back, never deleted — Delete is not offered.
|
|
422
454
|
*/
|
|
423
455
|
system: { type: Boolean, default: false },
|
|
424
|
-
/** Shows "+ Add locale"
|
|
425
|
-
allowAddLocale: { type: Boolean, default: false }
|
|
456
|
+
/** Shows "+ Add locale" (emits add-locale). */
|
|
457
|
+
allowAddLocale: { type: Boolean, default: false },
|
|
458
|
+
/**
|
|
459
|
+
* Shows a tab per locale this email exists in (emits select-locale).
|
|
460
|
+
* Unsaved edits are confirmed before switching away.
|
|
461
|
+
*/
|
|
462
|
+
localeTabs: { type: Boolean, default: false },
|
|
463
|
+
/** The console language (`locale` is the template's); defaults to English. */
|
|
464
|
+
uiLocale: { type: String, default: void 0 }
|
|
426
465
|
},
|
|
427
466
|
emits: {
|
|
428
467
|
saved: () => true,
|
|
429
468
|
/** The template was deleted and no longer exists. */
|
|
430
469
|
deleted: () => true,
|
|
431
|
-
/**
|
|
432
|
-
|
|
470
|
+
/**
|
|
471
|
+
* Create a translation of this template. `locales` are the ones the app
|
|
472
|
+
* uses elsewhere that this email lacks — suggest them first.
|
|
473
|
+
*/
|
|
474
|
+
"add-locale": (_type, _context) => true,
|
|
475
|
+
/** Open another locale of this email. */
|
|
476
|
+
"select-locale": (_template) => true
|
|
433
477
|
},
|
|
434
478
|
setup(props, { emit }) {
|
|
479
|
+
const t = (key, params) => (0, import_client2.createAdminT)(props.uiLocale)(key, params);
|
|
435
480
|
const { template, isLoading, error, refresh } = (0, import_vue_courier_admin.useTemplate)(
|
|
436
481
|
props.client,
|
|
437
482
|
props.type,
|
|
438
483
|
props.locale
|
|
439
484
|
);
|
|
440
|
-
const { saveTemplate, removeTemplate } = (0, import_vue_courier_admin.useTemplates)(props.client);
|
|
485
|
+
const { templates, saveTemplate, removeTemplate } = (0, import_vue_courier_admin.useTemplates)(props.client);
|
|
486
|
+
const siblings = (0, import_vue2.computed)(
|
|
487
|
+
() => (0, import_client2.groupTemplatesByType)(templates.value).find((g) => g.type === props.type)?.entries ?? []
|
|
488
|
+
);
|
|
441
489
|
const isDeleting = (0, import_vue2.ref)(false);
|
|
442
490
|
const { revisions, rollback } = (0, import_vue_courier_admin.useTemplateRevisions)(props.client, props.type, props.locale);
|
|
443
491
|
const isSaving = (0, import_vue2.ref)(false);
|
|
@@ -466,13 +514,13 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
466
514
|
try {
|
|
467
515
|
const parsed = JSON.parse(sampleJson.value || "{}");
|
|
468
516
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
469
|
-
sampleError.value = "
|
|
517
|
+
sampleError.value = "templates.editor.sampleNotObject";
|
|
470
518
|
return;
|
|
471
519
|
}
|
|
472
520
|
data = parsed;
|
|
473
521
|
sampleError.value = null;
|
|
474
522
|
} catch {
|
|
475
|
-
sampleError.value = "
|
|
523
|
+
sampleError.value = "templates.editor.sampleInvalid";
|
|
476
524
|
return;
|
|
477
525
|
}
|
|
478
526
|
const result = await renderPreview(
|
|
@@ -522,10 +570,54 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
522
570
|
isSaving.value = false;
|
|
523
571
|
}
|
|
524
572
|
}
|
|
573
|
+
const leave = () => !dirty.value || window.confirm(t("templates.editor.discardChanges"));
|
|
574
|
+
function renderTabBar() {
|
|
575
|
+
if (!props.localeTabs && !props.allowAddLocale) return null;
|
|
576
|
+
return (0, import_vue2.h)("div", { style: tabBar }, [
|
|
577
|
+
props.localeTabs ? (
|
|
578
|
+
// Each tab opens another stored row, so this is navigation, not an
|
|
579
|
+
// ARIA tablist: plain buttons, the open one marked aria-current.
|
|
580
|
+
(0, import_vue2.h)(
|
|
581
|
+
"nav",
|
|
582
|
+
{ "aria-label": t("templates.editor.locales"), style: tabs },
|
|
583
|
+
siblings.value.map((entry) => {
|
|
584
|
+
const selected = entry.locale === (props.locale ?? null);
|
|
585
|
+
return (0, import_vue2.h)(
|
|
586
|
+
"button",
|
|
587
|
+
{
|
|
588
|
+
key: entry.locale ?? "",
|
|
589
|
+
type: "button",
|
|
590
|
+
"aria-current": selected ? "true" : void 0,
|
|
591
|
+
style: selected ? tabSelected : entry.active ? tab : tabInactive,
|
|
592
|
+
title: entry.active ? void 0 : t("common.status.inactive"),
|
|
593
|
+
onClick: () => {
|
|
594
|
+
if (!selected && leave()) emit("select-locale", entry);
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
entry.locale ?? t("templates.defaultChip")
|
|
598
|
+
);
|
|
599
|
+
})
|
|
600
|
+
)
|
|
601
|
+
) : null,
|
|
602
|
+
props.allowAddLocale ? (0, import_vue2.h)(
|
|
603
|
+
"button",
|
|
604
|
+
{
|
|
605
|
+
type: "button",
|
|
606
|
+
style: { ...styles.rollbackButton, marginLeft: "auto" },
|
|
607
|
+
onClick: () => {
|
|
608
|
+
if (leave())
|
|
609
|
+
emit("add-locale", props.type, {
|
|
610
|
+
locales: (0, import_client2.missingTemplateLocales)(templates.value, props.type)
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
t("templates.editor.addLocale")
|
|
615
|
+
) : null
|
|
616
|
+
]);
|
|
617
|
+
}
|
|
525
618
|
async function handleDelete() {
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
if (!window.confirm(`Delete ${which}?${fallback}`)) return;
|
|
619
|
+
const message = props.locale ? t("templates.editor.confirmDeleteLocale", { locale: props.locale, type: props.type }) : t("templates.editor.confirmDelete", { type: props.type });
|
|
620
|
+
if (!window.confirm(message)) return;
|
|
529
621
|
isDeleting.value = true;
|
|
530
622
|
saveError.value = null;
|
|
531
623
|
try {
|
|
@@ -541,45 +633,31 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
541
633
|
return (0, import_vue2.h)("li", { key: rev.version, style: styles.revisionRow }, [
|
|
542
634
|
(0, import_vue2.h)(
|
|
543
635
|
"span",
|
|
544
|
-
`v${rev.version} \u2014 ${rev.actor ?? "
|
|
636
|
+
`v${rev.version} \u2014 ${rev.actor ?? t("templates.editor.unknownActor")} \u2014 ${(0, import_client2.formatAdminDate)(rev.createdAt, props.uiLocale)}`
|
|
545
637
|
),
|
|
546
638
|
(0, import_vue2.h)(
|
|
547
639
|
"button",
|
|
548
640
|
{ type: "button", style: styles.rollbackButton, onClick: () => rollback(rev.version) },
|
|
549
|
-
"
|
|
641
|
+
t("templates.editor.rollBack")
|
|
550
642
|
)
|
|
551
643
|
]);
|
|
552
644
|
}
|
|
553
645
|
return () => {
|
|
554
|
-
if (isLoading.value) return (0, import_vue2.h)("p", { style: styles.status }, "
|
|
646
|
+
if (isLoading.value) return (0, import_vue2.h)("p", { style: styles.status }, t("templates.editor.loading"));
|
|
555
647
|
if (error.value)
|
|
556
648
|
return (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, error.value.explanation);
|
|
557
649
|
return (0, import_vue2.h)("div", { style: styles.container }, [
|
|
558
|
-
(0, import_vue2.h)(
|
|
559
|
-
|
|
560
|
-
{ style: { display: "flex", alignItems: "center", gap: "12px", flexWrap: "wrap" } },
|
|
561
|
-
[
|
|
562
|
-
(0, import_vue2.h)("h1", { style: styles.title }, props.type),
|
|
563
|
-
props.allowAddLocale && !props.locale ? (0, import_vue2.h)(
|
|
564
|
-
"button",
|
|
565
|
-
{
|
|
566
|
-
type: "button",
|
|
567
|
-
style: { ...styles.rollbackButton, marginLeft: "auto" },
|
|
568
|
-
onClick: () => emit("add-locale", props.type)
|
|
569
|
-
},
|
|
570
|
-
"+ Add locale"
|
|
571
|
-
) : null
|
|
572
|
-
]
|
|
573
|
-
),
|
|
650
|
+
(0, import_vue2.h)("h1", { style: styles.title }, props.type),
|
|
651
|
+
renderTabBar(),
|
|
574
652
|
(0, import_vue2.h)("p", { style: styles.meta }, [
|
|
575
|
-
(0, import_vue2.h)("strong", props.locale ?? "
|
|
653
|
+
(0, import_vue2.h)("strong", props.locale ?? t("templates.defaultLocale")),
|
|
576
654
|
` \xB7 v${template.value?.version ?? 1}`,
|
|
577
|
-
props.system ?
|
|
655
|
+
props.system ? ` \xB7 ${t("templates.editor.builtInNote")}` : ""
|
|
578
656
|
]),
|
|
579
657
|
(0, import_vue2.h)("div", { style: styles.split }, [
|
|
580
658
|
(0, import_vue2.h)("div", { style: styles.column }, [
|
|
581
659
|
(0, import_vue2.h)("form", { style: styles.form, onSubmit: handleSubmit }, [
|
|
582
|
-
(0, import_vue2.h)("label", { style: styles.label, for: "template-subject" }, "
|
|
660
|
+
(0, import_vue2.h)("label", { style: styles.label, for: "template-subject" }, t("templates.subject")),
|
|
583
661
|
(0, import_vue2.h)("input", {
|
|
584
662
|
id: "template-subject",
|
|
585
663
|
style: styles.input,
|
|
@@ -588,7 +666,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
588
666
|
subject.value = e.target.value;
|
|
589
667
|
}
|
|
590
668
|
}),
|
|
591
|
-
(0, import_vue2.h)("label", { style: styles.label, for: "template-html" }, "
|
|
669
|
+
(0, import_vue2.h)("label", { style: styles.label, for: "template-html" }, t("templates.htmlBody")),
|
|
592
670
|
(0, import_vue2.h)("textarea", {
|
|
593
671
|
id: "template-html",
|
|
594
672
|
style: styles.textarea,
|
|
@@ -598,7 +676,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
598
676
|
html.value = e.target.value;
|
|
599
677
|
}
|
|
600
678
|
}),
|
|
601
|
-
(0, import_vue2.h)("label", { style: styles.label, for: "template-text" }, "
|
|
679
|
+
(0, import_vue2.h)("label", { style: styles.label, for: "template-text" }, t("templates.textBody")),
|
|
602
680
|
(0, import_vue2.h)("textarea", {
|
|
603
681
|
id: "template-text",
|
|
604
682
|
style: styles.textarea,
|
|
@@ -617,10 +695,10 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
617
695
|
active.value = e.target.checked;
|
|
618
696
|
}
|
|
619
697
|
}),
|
|
620
|
-
"
|
|
698
|
+
t("templates.editor.active")
|
|
621
699
|
]),
|
|
622
700
|
saveError.value?.reason === "VERSION_CONFLICT" ? (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, [
|
|
623
|
-
"
|
|
701
|
+
`${t("templates.editor.conflict")} `,
|
|
624
702
|
(0, import_vue2.h)(
|
|
625
703
|
"button",
|
|
626
704
|
{
|
|
@@ -631,7 +709,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
631
709
|
void refresh();
|
|
632
710
|
}
|
|
633
711
|
},
|
|
634
|
-
"
|
|
712
|
+
t("common.reload")
|
|
635
713
|
)
|
|
636
714
|
]) : saveError.value ? (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, saveError.value.explanation) : null,
|
|
637
715
|
(0, import_vue2.h)("div", { style: styles.saveRow }, [
|
|
@@ -642,9 +720,9 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
642
720
|
disabled: isSaving.value || !dirty.value,
|
|
643
721
|
style: dirty.value ? styles.button : styles.buttonDisabled
|
|
644
722
|
},
|
|
645
|
-
isSaving.value ? "
|
|
723
|
+
isSaving.value ? t("common.saving") : t("common.save")
|
|
646
724
|
),
|
|
647
|
-
!dirty.value && !isSaving.value ? (0, import_vue2.h)("span", { style: styles.meta }, "
|
|
725
|
+
!dirty.value && !isSaving.value ? (0, import_vue2.h)("span", { style: styles.meta }, t("templates.editor.noChanges")) : null,
|
|
648
726
|
!props.system ? (0, import_vue2.h)(
|
|
649
727
|
"button",
|
|
650
728
|
{
|
|
@@ -659,11 +737,15 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
659
737
|
borderColor: "color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)"
|
|
660
738
|
}
|
|
661
739
|
},
|
|
662
|
-
isDeleting.value ? "
|
|
740
|
+
isDeleting.value ? t("common.deleting") : t("common.delete")
|
|
663
741
|
) : null
|
|
664
742
|
])
|
|
665
743
|
]),
|
|
666
|
-
(0, import_vue2.h)(
|
|
744
|
+
(0, import_vue2.h)(
|
|
745
|
+
"label",
|
|
746
|
+
{ style: styles.label, for: "template-sample" },
|
|
747
|
+
t("templates.editor.sampleData")
|
|
748
|
+
),
|
|
667
749
|
(0, import_vue2.h)("textarea", {
|
|
668
750
|
id: "template-sample",
|
|
669
751
|
style: styles.textarea,
|
|
@@ -674,12 +756,16 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
674
756
|
sampleJson.value = e.target.value;
|
|
675
757
|
}
|
|
676
758
|
}),
|
|
677
|
-
sampleError.value ? (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, sampleError.value) : null
|
|
759
|
+
sampleError.value ? (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, t(sampleError.value)) : null
|
|
678
760
|
]),
|
|
679
761
|
(0, import_vue2.h)("div", { style: styles.previewColumn }, [
|
|
680
762
|
(0, import_vue2.h)("div", { style: styles.previewHeader }, [
|
|
681
|
-
(0, import_vue2.h)("span", { style: styles.label }, "
|
|
682
|
-
(0, import_vue2.h)(
|
|
763
|
+
(0, import_vue2.h)("span", { style: styles.label }, t("templates.editor.preview")),
|
|
764
|
+
(0, import_vue2.h)(
|
|
765
|
+
"span",
|
|
766
|
+
{ style: styles.meta },
|
|
767
|
+
isPreviewing.value ? t("templates.editor.rendering") : t("templates.editor.live")
|
|
768
|
+
)
|
|
683
769
|
]),
|
|
684
770
|
previewError.value ? (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, previewError.value.explanation) : null,
|
|
685
771
|
preview.value?.subject ? (0, import_vue2.h)("p", { style: styles.previewSubject }, preview.value.subject) : null,
|
|
@@ -688,16 +774,16 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
688
774
|
// must never execute in the dashboard's origin, where the admin
|
|
689
775
|
// token lives.
|
|
690
776
|
(0, import_vue2.h)("iframe", {
|
|
691
|
-
title: "
|
|
777
|
+
title: t("templates.editor.previewTitle"),
|
|
692
778
|
style: styles.previewFrame,
|
|
693
779
|
sandbox: "",
|
|
694
780
|
srcdoc: preview.value.html
|
|
695
781
|
})
|
|
696
|
-
) : preview.value ? (0, import_vue2.h)("pre", { style: styles.previewText }, preview.value.text) : (0, import_vue2.h)("p", { style: styles.meta }, "
|
|
782
|
+
) : preview.value ? (0, import_vue2.h)("pre", { style: styles.previewText }, preview.value.text) : (0, import_vue2.h)("p", { style: styles.meta }, t("templates.editor.nothingRendered"))
|
|
697
783
|
])
|
|
698
784
|
]),
|
|
699
785
|
revisions.value.length > 0 ? (0, import_vue2.h)("div", { style: styles.revisions }, [
|
|
700
|
-
(0, import_vue2.h)("h2", { style: styles.subtitle }, "
|
|
786
|
+
(0, import_vue2.h)("h2", { style: styles.subtitle }, t("templates.editor.history")),
|
|
701
787
|
(0, import_vue2.h)("ul", { style: styles.list }, revisions.value.map(renderRevision))
|
|
702
788
|
]) : null
|
|
703
789
|
]);
|
|
@@ -706,6 +792,7 @@ var TemplateEditorScreen = (0, import_vue2.defineComponent)({
|
|
|
706
792
|
});
|
|
707
793
|
|
|
708
794
|
// src/screens/TemplateListScreen.ts
|
|
795
|
+
var import_client3 = require("@fonderie/client");
|
|
709
796
|
var import_vue_courier_admin2 = require("@fonderie/vue-courier-admin");
|
|
710
797
|
var import_vue3 = require("vue");
|
|
711
798
|
var builtIn = {
|
|
@@ -716,6 +803,33 @@ var builtIn = {
|
|
|
716
803
|
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
717
804
|
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
718
805
|
};
|
|
806
|
+
var chip = {
|
|
807
|
+
height: "24px",
|
|
808
|
+
boxSizing: "border-box",
|
|
809
|
+
padding: "0 8px",
|
|
810
|
+
borderRadius: "6px",
|
|
811
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
812
|
+
background: "var(--fonderie-surface,#fff)",
|
|
813
|
+
color: "var(--fonderie-text,#171717)",
|
|
814
|
+
fontSize: "12px",
|
|
815
|
+
fontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)',
|
|
816
|
+
cursor: "pointer"
|
|
817
|
+
};
|
|
818
|
+
var chipInactive = { ...chip, opacity: 0.5, textDecoration: "line-through" };
|
|
819
|
+
var row = {
|
|
820
|
+
...styles.row,
|
|
821
|
+
display: "flex",
|
|
822
|
+
alignItems: "center",
|
|
823
|
+
gap: "8px",
|
|
824
|
+
paddingRight: "16px"
|
|
825
|
+
};
|
|
826
|
+
var rowButton = { ...styles.rowButton, width: "auto", flex: "1", minWidth: "0" };
|
|
827
|
+
var chips = {
|
|
828
|
+
display: "flex",
|
|
829
|
+
flexWrap: "wrap",
|
|
830
|
+
justifyContent: "flex-end",
|
|
831
|
+
gap: "6px"
|
|
832
|
+
};
|
|
719
833
|
var newButton = {
|
|
720
834
|
display: "inline-flex",
|
|
721
835
|
alignItems: "center",
|
|
@@ -736,34 +850,60 @@ var TemplateListScreen = (0, import_vue3.defineComponent)({
|
|
|
736
850
|
props: {
|
|
737
851
|
client: { type: Object, required: true },
|
|
738
852
|
/** Shows a "New template" button (emits create-template). */
|
|
739
|
-
allowCreate: { type: Boolean, default: false }
|
|
853
|
+
allowCreate: { type: Boolean, default: false },
|
|
854
|
+
/** The console language; defaults to English. */
|
|
855
|
+
locale: { type: String, default: void 0 }
|
|
740
856
|
},
|
|
741
857
|
emits: {
|
|
742
|
-
/**
|
|
858
|
+
/**
|
|
859
|
+
* The whole row — type AND locale, and whether it is built-in. One row
|
|
860
|
+
* per email: the row opens the default locale, a locale chip that locale.
|
|
861
|
+
*/
|
|
743
862
|
"select-template": (_template) => true,
|
|
744
863
|
/** Receives the locales in use, to suggest. */
|
|
745
864
|
"create-template": (_context) => true
|
|
746
865
|
},
|
|
747
866
|
setup(props, { emit }) {
|
|
748
867
|
const { templates, isLoading, error } = (0, import_vue_courier_admin2.useTemplates)(props.client);
|
|
749
|
-
|
|
750
|
-
|
|
868
|
+
const t = (key, params) => (0, import_client3.createAdminT)(props.locale)(key, params);
|
|
869
|
+
function renderRow(group) {
|
|
870
|
+
const primary = group.primary;
|
|
871
|
+
return (0, import_vue3.h)("li", { key: group.type, style: row }, [
|
|
751
872
|
(0, import_vue3.h)(
|
|
752
873
|
"button",
|
|
753
874
|
{
|
|
754
875
|
type: "button",
|
|
755
|
-
style:
|
|
756
|
-
onClick: () => emit("select-template",
|
|
876
|
+
style: rowButton,
|
|
877
|
+
onClick: () => emit("select-template", primary)
|
|
757
878
|
},
|
|
758
879
|
[
|
|
759
|
-
(0, import_vue3.h)("span", { style: styles.type },
|
|
760
|
-
(0, import_vue3.h)("span", { style:
|
|
761
|
-
|
|
762
|
-
(0, import_vue3.h)("span", { style: template.active ? styles.active : styles.inactive }, [
|
|
880
|
+
(0, import_vue3.h)("span", { style: styles.type }, group.type),
|
|
881
|
+
group.system ? (0, import_vue3.h)("span", { style: builtIn }, t("templates.builtInBadge")) : null,
|
|
882
|
+
(0, import_vue3.h)("span", { style: primary.active ? styles.active : styles.inactive }, [
|
|
763
883
|
(0, import_vue3.h)("span", { style: styles.dot }),
|
|
764
|
-
|
|
884
|
+
primary.active ? t("common.status.active") : t("common.status.inactive")
|
|
765
885
|
])
|
|
766
886
|
]
|
|
887
|
+
),
|
|
888
|
+
// Siblings of the row button, not inside it: a button cannot hold buttons.
|
|
889
|
+
(0, import_vue3.h)(
|
|
890
|
+
"span",
|
|
891
|
+
{ style: chips },
|
|
892
|
+
group.entries.map((entry) => {
|
|
893
|
+
const name = entry.locale ?? t("templates.defaultChip");
|
|
894
|
+
return (0, import_vue3.h)(
|
|
895
|
+
"button",
|
|
896
|
+
{
|
|
897
|
+
key: entry.locale ?? "",
|
|
898
|
+
type: "button",
|
|
899
|
+
style: entry.active ? chip : chipInactive,
|
|
900
|
+
"aria-label": t("templates.list.openLocale", { type: group.type, locale: name }),
|
|
901
|
+
title: entry.active ? void 0 : t("common.status.inactive"),
|
|
902
|
+
onClick: () => emit("select-template", entry)
|
|
903
|
+
},
|
|
904
|
+
name
|
|
905
|
+
);
|
|
906
|
+
})
|
|
767
907
|
)
|
|
768
908
|
]);
|
|
769
909
|
}
|
|
@@ -779,7 +919,7 @@ var TemplateListScreen = (0, import_vue3.defineComponent)({
|
|
|
779
919
|
}
|
|
780
920
|
},
|
|
781
921
|
[
|
|
782
|
-
(0, import_vue3.h)("h1", { style: styles.listTitle }, "
|
|
922
|
+
(0, import_vue3.h)("h1", { style: styles.listTitle }, t("templates.list.title")),
|
|
783
923
|
props.allowCreate ? (0, import_vue3.h)(
|
|
784
924
|
"button",
|
|
785
925
|
{
|
|
@@ -788,21 +928,17 @@ var TemplateListScreen = (0, import_vue3.defineComponent)({
|
|
|
788
928
|
onClick: () => emit("create-template", {
|
|
789
929
|
locales: [
|
|
790
930
|
...new Set(
|
|
791
|
-
templates.value.map((
|
|
931
|
+
templates.value.map((tpl) => tpl.locale).filter((l) => !!l)
|
|
792
932
|
)
|
|
793
933
|
]
|
|
794
934
|
})
|
|
795
935
|
},
|
|
796
|
-
"
|
|
936
|
+
t("templates.list.newTemplate")
|
|
797
937
|
) : null
|
|
798
938
|
]
|
|
799
939
|
),
|
|
800
|
-
(0, import_vue3.h)(
|
|
801
|
-
|
|
802
|
-
{ style: styles.hint },
|
|
803
|
-
"Every email the app sends. Open one to edit its copy and preview it live."
|
|
804
|
-
),
|
|
805
|
-
isLoading.value ? (0, import_vue3.h)("p", { style: styles.status }, "Loading templates\u2026") : error.value ? (0, import_vue3.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : (0, import_vue3.h)("ul", { style: styles.list }, templates.value.map(renderRow))
|
|
940
|
+
(0, import_vue3.h)("p", { style: styles.hint }, t("templates.list.hint")),
|
|
941
|
+
isLoading.value ? (0, import_vue3.h)("p", { style: styles.status }, t("templates.list.loading")) : error.value ? (0, import_vue3.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : (0, import_vue3.h)("ul", { style: styles.list }, (0, import_client3.groupTemplatesByType)(templates.value).map(renderRow))
|
|
806
942
|
]);
|
|
807
943
|
}
|
|
808
944
|
});
|