@fonderie/react-courier-admin-screens 0.10.0 → 0.11.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 +204 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -21
- package/dist/index.d.ts +30 -21
- package/dist/index.js +214 -87
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createAdminT,
|
|
4
4
|
formatAdminDate,
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
suggestTemplateLocales,
|
|
6
|
+
templateLanguages
|
|
7
7
|
} from "@fonderie/client";
|
|
8
8
|
import {
|
|
9
|
+
useBuiltInTemplate,
|
|
9
10
|
useTemplate,
|
|
11
|
+
useTemplateCatalog,
|
|
10
12
|
useTemplatePreview,
|
|
13
|
+
useTemplateResolution,
|
|
11
14
|
useTemplateRevisions,
|
|
12
15
|
useTemplates
|
|
13
16
|
} from "@fonderie/react-courier-admin";
|
|
@@ -28,8 +31,16 @@ function TemplateEditorScreen({
|
|
|
28
31
|
}) {
|
|
29
32
|
const t = useMemo(() => createAdminT(uiLocale), [uiLocale]);
|
|
30
33
|
const { template, isLoading, error, refresh } = useTemplate(client, type, locale);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
34
|
+
const notSaved = error?.status === 404;
|
|
35
|
+
const { builtIn, isLoading: builtInLoading } = useBuiltInTemplate(client, type, locale);
|
|
36
|
+
const { catalog, refresh: refreshCatalog } = useTemplateCatalog(client);
|
|
37
|
+
const defaultLocale = catalog?.defaultLocale ?? "en-US";
|
|
38
|
+
const email = catalog?.emails.find((e) => e.type === type);
|
|
39
|
+
const languages = email ? templateLanguages(email, defaultLocale) : [];
|
|
40
|
+
const source = template ?? (notSaved ? builtIn : null);
|
|
41
|
+
const { resolution, resolve } = useTemplateResolution(client);
|
|
42
|
+
const [probe, setProbe] = useState("");
|
|
43
|
+
const { saveTemplate, removeTemplate } = useTemplates(client);
|
|
33
44
|
const [isDeleting, setIsDeleting] = useState(false);
|
|
34
45
|
const { revisions, rollback } = useTemplateRevisions(client, type, locale);
|
|
35
46
|
const [isSaving, setIsSaving] = useState(false);
|
|
@@ -42,12 +53,15 @@ function TemplateEditorScreen({
|
|
|
42
53
|
const [sampleJson, setSampleJson] = useState("{}");
|
|
43
54
|
const [sampleError, setSampleError] = useState(null);
|
|
44
55
|
useEffect(() => {
|
|
45
|
-
if (!
|
|
46
|
-
setSubject(
|
|
47
|
-
setHtml(
|
|
48
|
-
setText(
|
|
49
|
-
setActive(template.active);
|
|
50
|
-
}, [template]);
|
|
56
|
+
if (!source) return;
|
|
57
|
+
setSubject(source.subject ?? "");
|
|
58
|
+
setHtml(source.html ?? "");
|
|
59
|
+
setText(source.text);
|
|
60
|
+
setActive(template ? template.active : true);
|
|
61
|
+
}, [source, template]);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
void resolve(type, locale ?? defaultLocale);
|
|
64
|
+
}, [resolve, type, locale, defaultLocale]);
|
|
51
65
|
const run = useCallback(async () => {
|
|
52
66
|
let data = {};
|
|
53
67
|
try {
|
|
@@ -75,13 +89,15 @@ function TemplateEditorScreen({
|
|
|
75
89
|
}, [renderPreview, type, text, subject, html, locale, sampleJson, t]);
|
|
76
90
|
const runRef = useRef(run);
|
|
77
91
|
runRef.current = run;
|
|
78
|
-
const loadedType =
|
|
92
|
+
const loadedType = source ? `${type}:${locale ?? ""}` : null;
|
|
79
93
|
useEffect(() => {
|
|
80
94
|
if (!loadedType) return;
|
|
81
95
|
const timer = setTimeout(() => void runRef.current(), PREVIEW_DEBOUNCE_MS);
|
|
82
96
|
return () => clearTimeout(timer);
|
|
83
97
|
}, [loadedType, subject, html, text, sampleJson]);
|
|
84
|
-
const dirty = !!template && (subject !== (template.subject ?? "") || html !== (template.html ?? "") || text !== template.text || active !== template.active);
|
|
98
|
+
const dirty = notSaved && !!builtIn || !!template && (subject !== (template.subject ?? "") || html !== (template.html ?? "") || text !== template.text || active !== template.active);
|
|
99
|
+
const protectedRow = !locale && (email?.system ?? system);
|
|
100
|
+
const shipsHere = locale ? languages.some((l) => l.locale === locale && l.builtIn) : !!email?.builtIn.default;
|
|
85
101
|
const handleSubmit = async (event) => {
|
|
86
102
|
event.preventDefault();
|
|
87
103
|
setIsSaving(true);
|
|
@@ -92,7 +108,7 @@ function TemplateEditorScreen({
|
|
|
92
108
|
if (html) input.html = html;
|
|
93
109
|
if (template?.version !== void 0) input.ifVersion = template.version;
|
|
94
110
|
await saveTemplate(type, input, locale);
|
|
95
|
-
await refresh();
|
|
111
|
+
await Promise.all([refresh(), refreshCatalog()]);
|
|
96
112
|
onSaved?.();
|
|
97
113
|
} catch (err) {
|
|
98
114
|
setSaveError(err);
|
|
@@ -100,9 +116,32 @@ function TemplateEditorScreen({
|
|
|
100
116
|
setIsSaving(false);
|
|
101
117
|
}
|
|
102
118
|
};
|
|
103
|
-
const switchTo = (
|
|
104
|
-
if (dirty && !window.confirm(t("templates.editor.discardChanges")))
|
|
105
|
-
|
|
119
|
+
const switchTo = (next) => {
|
|
120
|
+
if (dirty && !(notSaved && !!builtIn) && !window.confirm(t("templates.editor.discardChanges")))
|
|
121
|
+
return;
|
|
122
|
+
onSelectLocale?.(next);
|
|
123
|
+
};
|
|
124
|
+
const handleReset = async () => {
|
|
125
|
+
if (!builtIn || !window.confirm(t("templates.editor.confirmReset", { locale: locale ?? defaultLocale })))
|
|
126
|
+
return;
|
|
127
|
+
setIsDeleting(true);
|
|
128
|
+
setSaveError(null);
|
|
129
|
+
try {
|
|
130
|
+
if (locale) {
|
|
131
|
+
await removeTemplate(type, locale);
|
|
132
|
+
} else {
|
|
133
|
+
const input = { text: builtIn.text, active };
|
|
134
|
+
if (builtIn.subject) input.subject = builtIn.subject;
|
|
135
|
+
if (builtIn.html) input.html = builtIn.html;
|
|
136
|
+
if (template?.version !== void 0) input.ifVersion = template.version;
|
|
137
|
+
await saveTemplate(type, input, null);
|
|
138
|
+
}
|
|
139
|
+
await Promise.all([refresh(), refreshCatalog()]);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
setSaveError(err);
|
|
142
|
+
} finally {
|
|
143
|
+
setIsDeleting(false);
|
|
144
|
+
}
|
|
106
145
|
};
|
|
107
146
|
const handleDelete = async () => {
|
|
108
147
|
const message = locale ? t("templates.editor.confirmDeleteLocale", { type, locale }) : t("templates.editor.confirmDelete", { type });
|
|
@@ -118,8 +157,9 @@ function TemplateEditorScreen({
|
|
|
118
157
|
setIsDeleting(false);
|
|
119
158
|
}
|
|
120
159
|
};
|
|
121
|
-
if (isLoading
|
|
122
|
-
|
|
160
|
+
if (isLoading || notSaved && builtInLoading)
|
|
161
|
+
return /* @__PURE__ */ jsx("p", { style: styles.status, children: t("templates.editor.loading") });
|
|
162
|
+
if (error && !(notSaved && builtIn))
|
|
123
163
|
return /* @__PURE__ */ jsx("p", { style: styles.error, role: "alert", children: error.explanation });
|
|
124
164
|
return /* @__PURE__ */ jsxs("div", { style: styles.container, children: [
|
|
125
165
|
/* @__PURE__ */ jsx("h1", { style: styles.title, children: type }),
|
|
@@ -127,19 +167,23 @@ function TemplateEditorScreen({
|
|
|
127
167
|
onSelectLocale ? (
|
|
128
168
|
// Each tab opens another stored row, so this is navigation, not an
|
|
129
169
|
// ARIA tablist: plain buttons, the open one marked aria-current.
|
|
130
|
-
/* @__PURE__ */ jsx("nav", { "aria-label": t("templates.editor.locales"), style: styles.tabs, children:
|
|
131
|
-
const selected =
|
|
170
|
+
/* @__PURE__ */ jsx("nav", { "aria-label": t("templates.editor.locales"), style: styles.tabs, children: languages.map((l) => {
|
|
171
|
+
const selected = l.locale === (locale ?? null);
|
|
132
172
|
return /* @__PURE__ */ jsx(
|
|
133
173
|
"button",
|
|
134
174
|
{
|
|
135
175
|
type: "button",
|
|
136
176
|
"aria-current": selected ? "true" : void 0,
|
|
137
|
-
onClick: () => selected ? void 0 : switchTo(
|
|
138
|
-
style:
|
|
139
|
-
|
|
140
|
-
|
|
177
|
+
onClick: () => selected ? void 0 : switchTo({ type, locale: l.locale, system: !!email?.system }),
|
|
178
|
+
style: {
|
|
179
|
+
...selected ? styles.tabSelected : styles.tab,
|
|
180
|
+
...l.saved ? {} : styles.tabBuiltIn,
|
|
181
|
+
...l.active ? {} : styles.tabInactive
|
|
182
|
+
},
|
|
183
|
+
title: l.active ? void 0 : t("common.status.inactive"),
|
|
184
|
+
children: l.label
|
|
141
185
|
},
|
|
142
|
-
|
|
186
|
+
l.label
|
|
143
187
|
);
|
|
144
188
|
}) })
|
|
145
189
|
) : null,
|
|
@@ -150,17 +194,21 @@ function TemplateEditorScreen({
|
|
|
150
194
|
style: { ...styles.rollbackButton, marginLeft: "auto" },
|
|
151
195
|
onClick: () => {
|
|
152
196
|
if (dirty && !window.confirm(t("templates.editor.discardChanges"))) return;
|
|
153
|
-
onAddLocale(type, {
|
|
197
|
+
onAddLocale(type, {
|
|
198
|
+
locales: catalog ? suggestTemplateLocales(catalog, type) : [],
|
|
199
|
+
defaultLocale
|
|
200
|
+
});
|
|
154
201
|
},
|
|
155
202
|
children: t("templates.editor.addLocale")
|
|
156
203
|
}
|
|
157
204
|
) : null
|
|
158
205
|
] }) : null,
|
|
159
206
|
/* @__PURE__ */ jsxs("p", { style: styles.meta, children: [
|
|
160
|
-
/* @__PURE__ */ jsx("strong", { children: locale ??
|
|
161
|
-
|
|
162
|
-
template
|
|
163
|
-
|
|
207
|
+
/* @__PURE__ */ jsx("strong", { children: locale ?? defaultLocale }),
|
|
208
|
+
template ? ` \xB7 v${template.version}` : "",
|
|
209
|
+
template && protectedRow ? ` \xB7 ${t("templates.editor.builtInNote")}` : "",
|
|
210
|
+
!template && builtIn ? ` \xB7 ${t("templates.editor.builtInCopy")}` : "",
|
|
211
|
+
resolution && resolution.chain.length > 1 && resolution.requested === (locale ?? defaultLocale) ? ` \xB7 ${t("templates.editor.chain", { chain: [...resolution.chain, defaultLocale].join(" \u2192 ") })}` : ""
|
|
164
212
|
] }),
|
|
165
213
|
/* @__PURE__ */ jsxs("div", { style: styles.split, children: [
|
|
166
214
|
/* @__PURE__ */ jsxs("div", { style: styles.column, children: [
|
|
@@ -236,7 +284,16 @@ function TemplateEditorScreen({
|
|
|
236
284
|
}
|
|
237
285
|
),
|
|
238
286
|
!dirty && !isSaving && /* @__PURE__ */ jsx("span", { style: styles.meta, children: t("templates.editor.noChanges") }),
|
|
239
|
-
|
|
287
|
+
template && shipsHere && builtIn ? /* @__PURE__ */ jsx(
|
|
288
|
+
"button",
|
|
289
|
+
{
|
|
290
|
+
type: "button",
|
|
291
|
+
disabled: isDeleting,
|
|
292
|
+
onClick: () => void handleReset(),
|
|
293
|
+
style: { ...styles.rollbackButton, height: 36, marginLeft: "auto" },
|
|
294
|
+
children: t("templates.editor.resetToBuiltIn")
|
|
295
|
+
}
|
|
296
|
+
) : template && !protectedRow ? /* @__PURE__ */ jsx(
|
|
240
297
|
"button",
|
|
241
298
|
{
|
|
242
299
|
type: "button",
|
|
@@ -291,6 +348,43 @@ function TemplateEditorScreen({
|
|
|
291
348
|
) : preview ? /* @__PURE__ */ jsx("pre", { style: styles.previewText, children: preview.text }) : /* @__PURE__ */ jsx("p", { style: styles.meta, children: t("templates.editor.nothingRendered") })
|
|
292
349
|
] })
|
|
293
350
|
] }),
|
|
351
|
+
/* @__PURE__ */ jsxs("div", { style: styles.revisions, children: [
|
|
352
|
+
/* @__PURE__ */ jsx("h2", { style: styles.subtitle, children: t("templates.editor.whoReceives") }),
|
|
353
|
+
/* @__PURE__ */ jsxs(
|
|
354
|
+
"form",
|
|
355
|
+
{
|
|
356
|
+
style: { display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" },
|
|
357
|
+
onSubmit: (event) => {
|
|
358
|
+
event.preventDefault();
|
|
359
|
+
if (probe.trim()) void resolve(type, probe.trim());
|
|
360
|
+
},
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsx(
|
|
363
|
+
"input",
|
|
364
|
+
{
|
|
365
|
+
"aria-label": t("templates.editor.whoReceives"),
|
|
366
|
+
style: { ...styles.input, width: 200 },
|
|
367
|
+
value: probe,
|
|
368
|
+
placeholder: t("templates.editor.whoPlaceholder"),
|
|
369
|
+
spellCheck: false,
|
|
370
|
+
onChange: (event) => setProbe(event.target.value)
|
|
371
|
+
}
|
|
372
|
+
),
|
|
373
|
+
/* @__PURE__ */ jsx("button", { type: "submit", style: { ...styles.rollbackButton, height: 36 }, children: t("templates.editor.check") }),
|
|
374
|
+
resolution && probe.trim() ? /* @__PURE__ */ jsxs("span", { style: { ...styles.meta, marginBottom: 0 }, role: "status", children: [
|
|
375
|
+
t("templates.editor.receives", {
|
|
376
|
+
requested: resolution.requested,
|
|
377
|
+
sent: resolution.sent
|
|
378
|
+
}),
|
|
379
|
+
" ",
|
|
380
|
+
resolution.source === "saved" ? t("templates.editor.sourceSaved") : t("templates.editor.sourceBuiltIn"),
|
|
381
|
+
" ",
|
|
382
|
+
resolution.chain.length > 0 ? `(${[...resolution.chain, resolution.defaultLocale].join(" \u2192 ")})` : ""
|
|
383
|
+
] }) : null
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
)
|
|
387
|
+
] }),
|
|
294
388
|
revisions.length > 0 && /* @__PURE__ */ jsxs("div", { style: styles.revisions, children: [
|
|
295
389
|
/* @__PURE__ */ jsx("h2", { style: styles.subtitle, children: t("templates.editor.history") }),
|
|
296
390
|
/* @__PURE__ */ jsx("ul", { style: styles.list, children: revisions.map((rev) => /* @__PURE__ */ jsxs("li", { style: styles.row, children: [
|
|
@@ -347,7 +441,9 @@ var styles = {
|
|
|
347
441
|
borderBottomColor: "var(--fonderie-text,#171717)",
|
|
348
442
|
cursor: "default"
|
|
349
443
|
},
|
|
350
|
-
tabInactive: {
|
|
444
|
+
tabInactive: { opacity: 0.55, textDecoration: "line-through" },
|
|
445
|
+
// Fonderie's built-in copy, not saved by the app — the list's dashed chip.
|
|
446
|
+
tabBuiltIn: { fontStyle: "italic" },
|
|
351
447
|
// Two columns, always: the editor on the left, the rendered result on the
|
|
352
448
|
// right. Stacking the preview under a long form hid it below the fold.
|
|
353
449
|
split: {
|
|
@@ -517,10 +613,10 @@ var styles = {
|
|
|
517
613
|
// src/screens/TemplateListScreen.tsx
|
|
518
614
|
import {
|
|
519
615
|
createAdminT as createAdminT2,
|
|
520
|
-
|
|
616
|
+
templateLanguages as templateLanguages2
|
|
521
617
|
} from "@fonderie/client";
|
|
522
|
-
import {
|
|
523
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
618
|
+
import { useTemplateCatalog as useTemplateCatalog2 } from "@fonderie/react-courier-admin";
|
|
619
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
524
620
|
function TemplateListScreen({
|
|
525
621
|
client,
|
|
526
622
|
onSelectTemplate,
|
|
@@ -528,8 +624,14 @@ function TemplateListScreen({
|
|
|
528
624
|
locale
|
|
529
625
|
}) {
|
|
530
626
|
const t = createAdminT2(locale);
|
|
531
|
-
const {
|
|
532
|
-
const
|
|
627
|
+
const { catalog, isLoading, error } = useTemplateCatalog2(client);
|
|
628
|
+
const emails = catalog?.emails ?? [];
|
|
629
|
+
const defaultLocale = catalog?.defaultLocale ?? "en-US";
|
|
630
|
+
const chipStyle = (l) => ({
|
|
631
|
+
...chip,
|
|
632
|
+
...l.saved ? {} : chipBuiltIn,
|
|
633
|
+
...l.active ? {} : chipOff
|
|
634
|
+
});
|
|
533
635
|
return /* @__PURE__ */ jsxs2("div", { style: styles2.container, children: [
|
|
534
636
|
/* @__PURE__ */ jsxs2(
|
|
535
637
|
"div",
|
|
@@ -543,8 +645,12 @@ function TemplateListScreen({
|
|
|
543
645
|
type: "button",
|
|
544
646
|
onClick: () => onCreateTemplate({
|
|
545
647
|
locales: [
|
|
546
|
-
...new Set(
|
|
547
|
-
|
|
648
|
+
...new Set(
|
|
649
|
+
emails.flatMap(
|
|
650
|
+
(e) => templateLanguages2(e, defaultLocale).filter((l) => l.locale !== null).map((l) => l.label)
|
|
651
|
+
)
|
|
652
|
+
)
|
|
653
|
+
].sort()
|
|
548
654
|
}),
|
|
549
655
|
style: styles2.newButton,
|
|
550
656
|
children: t("templates.list.newTemplate")
|
|
@@ -554,39 +660,47 @@ function TemplateListScreen({
|
|
|
554
660
|
}
|
|
555
661
|
),
|
|
556
662
|
/* @__PURE__ */ jsx2("p", { style: styles2.hint, children: t("templates.list.hint") }),
|
|
557
|
-
isLoading ? /* @__PURE__ */ jsx2("p", { style: styles2.status, children: t("templates.list.loading") }) : error ? /* @__PURE__ */ jsx2("p", { style: styles2.error, role: "alert", children: error.explanation }) : /* @__PURE__ */
|
|
558
|
-
/* @__PURE__ */
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
663
|
+
isLoading ? /* @__PURE__ */ jsx2("p", { style: styles2.status, children: t("templates.list.loading") }) : error ? /* @__PURE__ */ jsx2("p", { style: styles2.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
664
|
+
/* @__PURE__ */ jsx2("ul", { style: styles2.list, children: emails.map((email) => {
|
|
665
|
+
const languages = templateLanguages2(email, defaultLocale);
|
|
666
|
+
const primary = languages.find((l) => l.locale === null) ?? languages[0];
|
|
667
|
+
const open = (l) => onSelectTemplate?.({
|
|
668
|
+
type: email.type,
|
|
669
|
+
locale: l?.locale ?? null,
|
|
670
|
+
system: email.system
|
|
671
|
+
});
|
|
672
|
+
return (
|
|
673
|
+
// Columns, not a flex row: the language chips line up down the
|
|
674
|
+
// list whatever the email name or badge.
|
|
675
|
+
/* @__PURE__ */ jsxs2("li", { style: styles2.row, children: [
|
|
676
|
+
/* @__PURE__ */ jsxs2("button", { type: "button", onClick: () => open(primary), style: styles2.rowButton, children: [
|
|
677
|
+
/* @__PURE__ */ jsx2("span", { style: styles2.type, children: email.type }),
|
|
678
|
+
email.system ? /* @__PURE__ */ jsx2("span", { style: styles2.builtIn, children: t("templates.builtInBadge") }) : /* @__PURE__ */ jsx2("span", {})
|
|
679
|
+
] }),
|
|
680
|
+
/* @__PURE__ */ jsx2("span", { style: styles2.chips, children: languages.map((l) => /* @__PURE__ */ jsx2(
|
|
681
|
+
"button",
|
|
682
|
+
{
|
|
683
|
+
type: "button",
|
|
684
|
+
onClick: () => open(l),
|
|
685
|
+
style: chipStyle(l),
|
|
686
|
+
"aria-label": t("templates.list.openLocale", {
|
|
687
|
+
type: email.type,
|
|
688
|
+
locale: l.label
|
|
689
|
+
}),
|
|
690
|
+
title: l.active ? void 0 : t("common.status.inactive"),
|
|
691
|
+
children: l.label
|
|
692
|
+
},
|
|
693
|
+
l.label
|
|
694
|
+
)) }),
|
|
695
|
+
/* @__PURE__ */ jsxs2("span", { style: primary?.active === false ? styles2.inactive : styles2.active, children: [
|
|
568
696
|
/* @__PURE__ */ jsx2("span", { style: styles2.dot }),
|
|
569
|
-
|
|
697
|
+
primary?.active === false ? t("common.status.inactive") : t("common.status.active")
|
|
570
698
|
] })
|
|
571
|
-
]
|
|
572
|
-
}
|
|
573
|
-
),
|
|
574
|
-
/* @__PURE__ */ jsx2("span", { style: styles2.chips, children: group.entries.map((entry) => {
|
|
575
|
-
const name = entry.locale ?? t("templates.defaultChip");
|
|
576
|
-
return /* @__PURE__ */ jsx2(
|
|
577
|
-
"button",
|
|
578
|
-
{
|
|
579
|
-
type: "button",
|
|
580
|
-
onClick: () => onSelectTemplate?.(entry),
|
|
581
|
-
style: entry.active ? styles2.chip : styles2.chipInactive,
|
|
582
|
-
"aria-label": t("templates.list.openLocale", { type: group.type, locale: name }),
|
|
583
|
-
title: entry.active ? void 0 : t("common.status.inactive"),
|
|
584
|
-
children: name
|
|
585
|
-
},
|
|
586
|
-
entry.locale ?? ""
|
|
699
|
+
] }, email.type)
|
|
587
700
|
);
|
|
588
|
-
}) })
|
|
589
|
-
|
|
701
|
+
}) }),
|
|
702
|
+
/* @__PURE__ */ jsx2("p", { style: styles2.legend, children: t("templates.list.legend") })
|
|
703
|
+
] })
|
|
590
704
|
] });
|
|
591
705
|
}
|
|
592
706
|
var pill = {
|
|
@@ -600,6 +714,7 @@ var pill = {
|
|
|
600
714
|
lineHeight: 1.5,
|
|
601
715
|
minWidth: 64
|
|
602
716
|
};
|
|
717
|
+
var MONO = 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)';
|
|
603
718
|
var chip = {
|
|
604
719
|
height: 24,
|
|
605
720
|
boxSizing: "border-box",
|
|
@@ -609,9 +724,15 @@ var chip = {
|
|
|
609
724
|
background: "var(--fonderie-surface,#fff)",
|
|
610
725
|
color: "var(--fonderie-text,#171717)",
|
|
611
726
|
fontSize: 12,
|
|
612
|
-
fontFamily:
|
|
727
|
+
fontFamily: MONO,
|
|
613
728
|
cursor: "pointer"
|
|
614
729
|
};
|
|
730
|
+
var chipBuiltIn = {
|
|
731
|
+
borderStyle: "dashed",
|
|
732
|
+
background: "transparent",
|
|
733
|
+
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
734
|
+
};
|
|
735
|
+
var chipOff = { opacity: 0.5, textDecoration: "line-through" };
|
|
615
736
|
var styles2 = {
|
|
616
737
|
container: { padding: "32px 40px 64px", maxWidth: 1160, boxSizing: "border-box" },
|
|
617
738
|
title: {
|
|
@@ -622,6 +743,7 @@ var styles2 = {
|
|
|
622
743
|
lineHeight: 1.25
|
|
623
744
|
},
|
|
624
745
|
hint: { fontSize: 13.5, color: "var(--fonderie-text-muted,#5c5c5c)", margin: "4px 0 24px" },
|
|
746
|
+
legend: { fontSize: 12.5, color: "var(--fonderie-text-muted,#5c5c5c)", margin: "10px 2px 0" },
|
|
625
747
|
status: { padding: "24px 0", color: "var(--fonderie-text-muted,#5c5c5c)", fontSize: 13.5 },
|
|
626
748
|
error: { color: "var(--fonderie-danger,#e00)", marginBottom: 12, fontSize: 14 },
|
|
627
749
|
list: {
|
|
@@ -634,20 +756,20 @@ var styles2 = {
|
|
|
634
756
|
overflow: "hidden",
|
|
635
757
|
boxShadow: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))"
|
|
636
758
|
},
|
|
759
|
+
// name + badge | languages | status — fixed tracks so every column aligns.
|
|
637
760
|
row: {
|
|
638
|
-
display: "
|
|
761
|
+
display: "grid",
|
|
762
|
+
gridTemplateColumns: "minmax(0, 1fr) minmax(180px, 280px) 88px",
|
|
639
763
|
alignItems: "center",
|
|
640
|
-
gap:
|
|
764
|
+
gap: 16,
|
|
641
765
|
paddingRight: 16,
|
|
642
766
|
borderBottom: "1px solid var(--fonderie-border-light,#f5f5f5)"
|
|
643
767
|
},
|
|
644
768
|
rowButton: {
|
|
645
|
-
flex: 1,
|
|
646
769
|
minWidth: 0,
|
|
647
770
|
display: "flex",
|
|
648
|
-
justifyContent: "space-between",
|
|
649
771
|
alignItems: "center",
|
|
650
|
-
gap:
|
|
772
|
+
gap: 12,
|
|
651
773
|
padding: "13px 16px",
|
|
652
774
|
background: "none",
|
|
653
775
|
border: "none",
|
|
@@ -659,12 +781,12 @@ var styles2 = {
|
|
|
659
781
|
type: {
|
|
660
782
|
fontSize: 13,
|
|
661
783
|
fontWeight: 600,
|
|
662
|
-
|
|
663
|
-
|
|
784
|
+
overflow: "hidden",
|
|
785
|
+
textOverflow: "ellipsis",
|
|
786
|
+
whiteSpace: "nowrap",
|
|
787
|
+
fontFamily: MONO
|
|
664
788
|
},
|
|
665
|
-
chips: { display: "flex", flexWrap: "wrap",
|
|
666
|
-
chip,
|
|
667
|
-
chipInactive: { ...chip, opacity: 0.5, textDecoration: "line-through" },
|
|
789
|
+
chips: { display: "flex", flexWrap: "wrap", gap: 6 },
|
|
668
790
|
dot: { width: 6, height: 6, borderRadius: 999, background: "currentColor" },
|
|
669
791
|
builtIn: {
|
|
670
792
|
fontSize: 11,
|
|
@@ -672,7 +794,8 @@ var styles2 = {
|
|
|
672
794
|
padding: "1px 7px",
|
|
673
795
|
borderRadius: 999,
|
|
674
796
|
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
675
|
-
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
797
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
798
|
+
flexShrink: 0
|
|
676
799
|
},
|
|
677
800
|
newButton: {
|
|
678
801
|
display: "inline-flex",
|
|
@@ -708,7 +831,7 @@ import {
|
|
|
708
831
|
} from "@fonderie/client";
|
|
709
832
|
import { useTemplatePreview as useTemplatePreview2 } from "@fonderie/react-courier-admin";
|
|
710
833
|
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
711
|
-
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
834
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
712
835
|
var TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;
|
|
713
836
|
var LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
714
837
|
var IMPLICIT2 = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
@@ -717,6 +840,7 @@ function TemplateCreateScreen({
|
|
|
717
840
|
client,
|
|
718
841
|
type,
|
|
719
842
|
locales = [],
|
|
843
|
+
defaultLocale,
|
|
720
844
|
onCreated,
|
|
721
845
|
locale
|
|
722
846
|
}) {
|
|
@@ -736,7 +860,7 @@ function TemplateCreateScreen({
|
|
|
736
860
|
const variables = useRef2([]);
|
|
737
861
|
useEffect2(() => {
|
|
738
862
|
if (!type) return;
|
|
739
|
-
client.getTemplate(type, null).then(({ result }) => {
|
|
863
|
+
client.getTemplate(type, null).catch(() => client.getBuiltInTemplate(type, null)).then(({ result }) => {
|
|
740
864
|
setSubject(result.subject ?? "");
|
|
741
865
|
setHtml(result.html ?? "");
|
|
742
866
|
setText(result.text);
|
|
@@ -779,6 +903,9 @@ function TemplateCreateScreen({
|
|
|
779
903
|
if (!TYPE_RE.test(t)) return setError(tr("templates.create.errorType"));
|
|
780
904
|
if (addingLocale && !l) return setError(tr("templates.create.errorLocaleRequired"));
|
|
781
905
|
if (l && !LOCALE_RE.test(l)) return setError(tr("templates.create.errorLocale"));
|
|
906
|
+
if (l && defaultLocale && l.toLowerCase() === defaultLocale.toLowerCase()) {
|
|
907
|
+
return setError(tr("templates.create.errorDefaultLocale", { locale: defaultLocale }));
|
|
908
|
+
}
|
|
782
909
|
if (!text.trim()) return setError(tr("templates.create.errorText"));
|
|
783
910
|
setBusy(true);
|
|
784
911
|
try {
|
|
@@ -808,7 +935,7 @@ function TemplateCreateScreen({
|
|
|
808
935
|
/* @__PURE__ */ jsx3("p", { style: styles3.meta, children: addingLocale ? tr("templates.create.hintLocale") : tr("templates.create.hintNew") }),
|
|
809
936
|
/* @__PURE__ */ jsxs3("div", { style: styles3.split, children: [
|
|
810
937
|
/* @__PURE__ */ jsxs3("form", { style: styles3.form, onSubmit: (e) => void submit(e), children: [
|
|
811
|
-
!addingLocale ? /* @__PURE__ */ jsxs3(
|
|
938
|
+
!addingLocale ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
812
939
|
/* @__PURE__ */ jsx3("label", { style: styles3.label, htmlFor: "new-template-type", children: tr("templates.create.type") }),
|
|
813
940
|
/* @__PURE__ */ jsx3(
|
|
814
941
|
"input",
|
|
@@ -896,7 +1023,7 @@ function TemplateCreateScreen({
|
|
|
896
1023
|
] })
|
|
897
1024
|
] });
|
|
898
1025
|
}
|
|
899
|
-
var
|
|
1026
|
+
var MONO2 = 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)';
|
|
900
1027
|
var styles3 = {
|
|
901
1028
|
container: { padding: "8px 40px 64px", maxWidth: 1400, boxSizing: "border-box" },
|
|
902
1029
|
// The editor's layout: the form on the left, the render pinned on the right.
|
|
@@ -929,7 +1056,7 @@ var styles3 = {
|
|
|
929
1056
|
borderRadius: 8,
|
|
930
1057
|
padding: 12,
|
|
931
1058
|
fontSize: 13,
|
|
932
|
-
fontFamily:
|
|
1059
|
+
fontFamily: MONO2
|
|
933
1060
|
},
|
|
934
1061
|
// The console's warning token (the shell's amber), readable in both themes.
|
|
935
1062
|
notice: {
|
|
@@ -982,7 +1109,7 @@ var styles3 = {
|
|
|
982
1109
|
lineHeight: 1.55,
|
|
983
1110
|
background: "var(--fonderie-surface,#fff)",
|
|
984
1111
|
color: "var(--fonderie-text,#171717)",
|
|
985
|
-
fontFamily:
|
|
1112
|
+
fontFamily: MONO2
|
|
986
1113
|
},
|
|
987
1114
|
error: {
|
|
988
1115
|
color: "var(--fonderie-danger,#e00)",
|