@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.cjs
CHANGED
|
@@ -46,8 +46,16 @@ function TemplateEditorScreen({
|
|
|
46
46
|
}) {
|
|
47
47
|
const t = (0, import_react.useMemo)(() => (0, import_client.createAdminT)(uiLocale), [uiLocale]);
|
|
48
48
|
const { template, isLoading, error, refresh } = (0, import_react_courier_admin.useTemplate)(client, type, locale);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
49
|
+
const notSaved = error?.status === 404;
|
|
50
|
+
const { builtIn, isLoading: builtInLoading } = (0, import_react_courier_admin.useBuiltInTemplate)(client, type, locale);
|
|
51
|
+
const { catalog, refresh: refreshCatalog } = (0, import_react_courier_admin.useTemplateCatalog)(client);
|
|
52
|
+
const defaultLocale = catalog?.defaultLocale ?? "en-US";
|
|
53
|
+
const email = catalog?.emails.find((e) => e.type === type);
|
|
54
|
+
const languages = email ? (0, import_client.templateLanguages)(email, defaultLocale) : [];
|
|
55
|
+
const source = template ?? (notSaved ? builtIn : null);
|
|
56
|
+
const { resolution, resolve } = (0, import_react_courier_admin.useTemplateResolution)(client);
|
|
57
|
+
const [probe, setProbe] = (0, import_react.useState)("");
|
|
58
|
+
const { saveTemplate, removeTemplate } = (0, import_react_courier_admin.useTemplates)(client);
|
|
51
59
|
const [isDeleting, setIsDeleting] = (0, import_react.useState)(false);
|
|
52
60
|
const { revisions, rollback } = (0, import_react_courier_admin.useTemplateRevisions)(client, type, locale);
|
|
53
61
|
const [isSaving, setIsSaving] = (0, import_react.useState)(false);
|
|
@@ -60,12 +68,15 @@ function TemplateEditorScreen({
|
|
|
60
68
|
const [sampleJson, setSampleJson] = (0, import_react.useState)("{}");
|
|
61
69
|
const [sampleError, setSampleError] = (0, import_react.useState)(null);
|
|
62
70
|
(0, import_react.useEffect)(() => {
|
|
63
|
-
if (!
|
|
64
|
-
setSubject(
|
|
65
|
-
setHtml(
|
|
66
|
-
setText(
|
|
67
|
-
setActive(template.active);
|
|
68
|
-
}, [template]);
|
|
71
|
+
if (!source) return;
|
|
72
|
+
setSubject(source.subject ?? "");
|
|
73
|
+
setHtml(source.html ?? "");
|
|
74
|
+
setText(source.text);
|
|
75
|
+
setActive(template ? template.active : true);
|
|
76
|
+
}, [source, template]);
|
|
77
|
+
(0, import_react.useEffect)(() => {
|
|
78
|
+
void resolve(type, locale ?? defaultLocale);
|
|
79
|
+
}, [resolve, type, locale, defaultLocale]);
|
|
69
80
|
const run = (0, import_react.useCallback)(async () => {
|
|
70
81
|
let data = {};
|
|
71
82
|
try {
|
|
@@ -93,13 +104,15 @@ function TemplateEditorScreen({
|
|
|
93
104
|
}, [renderPreview, type, text, subject, html, locale, sampleJson, t]);
|
|
94
105
|
const runRef = (0, import_react.useRef)(run);
|
|
95
106
|
runRef.current = run;
|
|
96
|
-
const loadedType =
|
|
107
|
+
const loadedType = source ? `${type}:${locale ?? ""}` : null;
|
|
97
108
|
(0, import_react.useEffect)(() => {
|
|
98
109
|
if (!loadedType) return;
|
|
99
110
|
const timer = setTimeout(() => void runRef.current(), PREVIEW_DEBOUNCE_MS);
|
|
100
111
|
return () => clearTimeout(timer);
|
|
101
112
|
}, [loadedType, subject, html, text, sampleJson]);
|
|
102
|
-
const dirty = !!template && (subject !== (template.subject ?? "") || html !== (template.html ?? "") || text !== template.text || active !== template.active);
|
|
113
|
+
const dirty = notSaved && !!builtIn || !!template && (subject !== (template.subject ?? "") || html !== (template.html ?? "") || text !== template.text || active !== template.active);
|
|
114
|
+
const protectedRow = !locale && (email?.system ?? system);
|
|
115
|
+
const shipsHere = locale ? languages.some((l) => l.locale === locale && l.builtIn) : !!email?.builtIn.default;
|
|
103
116
|
const handleSubmit = async (event) => {
|
|
104
117
|
event.preventDefault();
|
|
105
118
|
setIsSaving(true);
|
|
@@ -110,7 +123,7 @@ function TemplateEditorScreen({
|
|
|
110
123
|
if (html) input.html = html;
|
|
111
124
|
if (template?.version !== void 0) input.ifVersion = template.version;
|
|
112
125
|
await saveTemplate(type, input, locale);
|
|
113
|
-
await refresh();
|
|
126
|
+
await Promise.all([refresh(), refreshCatalog()]);
|
|
114
127
|
onSaved?.();
|
|
115
128
|
} catch (err) {
|
|
116
129
|
setSaveError(err);
|
|
@@ -118,9 +131,32 @@ function TemplateEditorScreen({
|
|
|
118
131
|
setIsSaving(false);
|
|
119
132
|
}
|
|
120
133
|
};
|
|
121
|
-
const switchTo = (
|
|
122
|
-
if (dirty && !window.confirm(t("templates.editor.discardChanges")))
|
|
123
|
-
|
|
134
|
+
const switchTo = (next) => {
|
|
135
|
+
if (dirty && !(notSaved && !!builtIn) && !window.confirm(t("templates.editor.discardChanges")))
|
|
136
|
+
return;
|
|
137
|
+
onSelectLocale?.(next);
|
|
138
|
+
};
|
|
139
|
+
const handleReset = async () => {
|
|
140
|
+
if (!builtIn || !window.confirm(t("templates.editor.confirmReset", { locale: locale ?? defaultLocale })))
|
|
141
|
+
return;
|
|
142
|
+
setIsDeleting(true);
|
|
143
|
+
setSaveError(null);
|
|
144
|
+
try {
|
|
145
|
+
if (locale) {
|
|
146
|
+
await removeTemplate(type, locale);
|
|
147
|
+
} else {
|
|
148
|
+
const input = { text: builtIn.text, active };
|
|
149
|
+
if (builtIn.subject) input.subject = builtIn.subject;
|
|
150
|
+
if (builtIn.html) input.html = builtIn.html;
|
|
151
|
+
if (template?.version !== void 0) input.ifVersion = template.version;
|
|
152
|
+
await saveTemplate(type, input, null);
|
|
153
|
+
}
|
|
154
|
+
await Promise.all([refresh(), refreshCatalog()]);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
setSaveError(err);
|
|
157
|
+
} finally {
|
|
158
|
+
setIsDeleting(false);
|
|
159
|
+
}
|
|
124
160
|
};
|
|
125
161
|
const handleDelete = async () => {
|
|
126
162
|
const message = locale ? t("templates.editor.confirmDeleteLocale", { type, locale }) : t("templates.editor.confirmDelete", { type });
|
|
@@ -136,8 +172,9 @@ function TemplateEditorScreen({
|
|
|
136
172
|
setIsDeleting(false);
|
|
137
173
|
}
|
|
138
174
|
};
|
|
139
|
-
if (isLoading
|
|
140
|
-
|
|
175
|
+
if (isLoading || notSaved && builtInLoading)
|
|
176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.status, children: t("templates.editor.loading") });
|
|
177
|
+
if (error && !(notSaved && builtIn))
|
|
141
178
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, role: "alert", children: error.explanation });
|
|
142
179
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.container, children: [
|
|
143
180
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { style: styles.title, children: type }),
|
|
@@ -145,19 +182,23 @@ function TemplateEditorScreen({
|
|
|
145
182
|
onSelectLocale ? (
|
|
146
183
|
// Each tab opens another stored row, so this is navigation, not an
|
|
147
184
|
// ARIA tablist: plain buttons, the open one marked aria-current.
|
|
148
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": t("templates.editor.locales"), style: styles.tabs, children:
|
|
149
|
-
const selected =
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": t("templates.editor.locales"), style: styles.tabs, children: languages.map((l) => {
|
|
186
|
+
const selected = l.locale === (locale ?? null);
|
|
150
187
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
151
188
|
"button",
|
|
152
189
|
{
|
|
153
190
|
type: "button",
|
|
154
191
|
"aria-current": selected ? "true" : void 0,
|
|
155
|
-
onClick: () => selected ? void 0 : switchTo(
|
|
156
|
-
style:
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
onClick: () => selected ? void 0 : switchTo({ type, locale: l.locale, system: !!email?.system }),
|
|
193
|
+
style: {
|
|
194
|
+
...selected ? styles.tabSelected : styles.tab,
|
|
195
|
+
...l.saved ? {} : styles.tabBuiltIn,
|
|
196
|
+
...l.active ? {} : styles.tabInactive
|
|
197
|
+
},
|
|
198
|
+
title: l.active ? void 0 : t("common.status.inactive"),
|
|
199
|
+
children: l.label
|
|
159
200
|
},
|
|
160
|
-
|
|
201
|
+
l.label
|
|
161
202
|
);
|
|
162
203
|
}) })
|
|
163
204
|
) : null,
|
|
@@ -168,17 +209,21 @@ function TemplateEditorScreen({
|
|
|
168
209
|
style: { ...styles.rollbackButton, marginLeft: "auto" },
|
|
169
210
|
onClick: () => {
|
|
170
211
|
if (dirty && !window.confirm(t("templates.editor.discardChanges"))) return;
|
|
171
|
-
onAddLocale(type, {
|
|
212
|
+
onAddLocale(type, {
|
|
213
|
+
locales: catalog ? (0, import_client.suggestTemplateLocales)(catalog, type) : [],
|
|
214
|
+
defaultLocale
|
|
215
|
+
});
|
|
172
216
|
},
|
|
173
217
|
children: t("templates.editor.addLocale")
|
|
174
218
|
}
|
|
175
219
|
) : null
|
|
176
220
|
] }) : null,
|
|
177
221
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.meta, children: [
|
|
178
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: locale ??
|
|
179
|
-
|
|
180
|
-
template
|
|
181
|
-
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: locale ?? defaultLocale }),
|
|
223
|
+
template ? ` \xB7 v${template.version}` : "",
|
|
224
|
+
template && protectedRow ? ` \xB7 ${t("templates.editor.builtInNote")}` : "",
|
|
225
|
+
!template && builtIn ? ` \xB7 ${t("templates.editor.builtInCopy")}` : "",
|
|
226
|
+
resolution && resolution.chain.length > 1 && resolution.requested === (locale ?? defaultLocale) ? ` \xB7 ${t("templates.editor.chain", { chain: [...resolution.chain, defaultLocale].join(" \u2192 ") })}` : ""
|
|
182
227
|
] }),
|
|
183
228
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.split, children: [
|
|
184
229
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.column, children: [
|
|
@@ -254,7 +299,16 @@ function TemplateEditorScreen({
|
|
|
254
299
|
}
|
|
255
300
|
),
|
|
256
301
|
!dirty && !isSaving && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.meta, children: t("templates.editor.noChanges") }),
|
|
257
|
-
|
|
302
|
+
template && shipsHere && builtIn ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
303
|
+
"button",
|
|
304
|
+
{
|
|
305
|
+
type: "button",
|
|
306
|
+
disabled: isDeleting,
|
|
307
|
+
onClick: () => void handleReset(),
|
|
308
|
+
style: { ...styles.rollbackButton, height: 36, marginLeft: "auto" },
|
|
309
|
+
children: t("templates.editor.resetToBuiltIn")
|
|
310
|
+
}
|
|
311
|
+
) : template && !protectedRow ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
258
312
|
"button",
|
|
259
313
|
{
|
|
260
314
|
type: "button",
|
|
@@ -309,6 +363,43 @@ function TemplateEditorScreen({
|
|
|
309
363
|
) : preview ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: styles.previewText, children: preview.text }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.meta, children: t("templates.editor.nothingRendered") })
|
|
310
364
|
] })
|
|
311
365
|
] }),
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.revisions, children: [
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.subtitle, children: t("templates.editor.whoReceives") }),
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
369
|
+
"form",
|
|
370
|
+
{
|
|
371
|
+
style: { display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" },
|
|
372
|
+
onSubmit: (event) => {
|
|
373
|
+
event.preventDefault();
|
|
374
|
+
if (probe.trim()) void resolve(type, probe.trim());
|
|
375
|
+
},
|
|
376
|
+
children: [
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
378
|
+
"input",
|
|
379
|
+
{
|
|
380
|
+
"aria-label": t("templates.editor.whoReceives"),
|
|
381
|
+
style: { ...styles.input, width: 200 },
|
|
382
|
+
value: probe,
|
|
383
|
+
placeholder: t("templates.editor.whoPlaceholder"),
|
|
384
|
+
spellCheck: false,
|
|
385
|
+
onChange: (event) => setProbe(event.target.value)
|
|
386
|
+
}
|
|
387
|
+
),
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", style: { ...styles.rollbackButton, height: 36 }, children: t("templates.editor.check") }),
|
|
389
|
+
resolution && probe.trim() ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { ...styles.meta, marginBottom: 0 }, role: "status", children: [
|
|
390
|
+
t("templates.editor.receives", {
|
|
391
|
+
requested: resolution.requested,
|
|
392
|
+
sent: resolution.sent
|
|
393
|
+
}),
|
|
394
|
+
" ",
|
|
395
|
+
resolution.source === "saved" ? t("templates.editor.sourceSaved") : t("templates.editor.sourceBuiltIn"),
|
|
396
|
+
" ",
|
|
397
|
+
resolution.chain.length > 0 ? `(${[...resolution.chain, resolution.defaultLocale].join(" \u2192 ")})` : ""
|
|
398
|
+
] }) : null
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
] }),
|
|
312
403
|
revisions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.revisions, children: [
|
|
313
404
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: styles.subtitle, children: t("templates.editor.history") }),
|
|
314
405
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.list, children: revisions.map((rev) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: styles.row, children: [
|
|
@@ -365,7 +456,9 @@ var styles = {
|
|
|
365
456
|
borderBottomColor: "var(--fonderie-text,#171717)",
|
|
366
457
|
cursor: "default"
|
|
367
458
|
},
|
|
368
|
-
tabInactive: {
|
|
459
|
+
tabInactive: { opacity: 0.55, textDecoration: "line-through" },
|
|
460
|
+
// Fonderie's built-in copy, not saved by the app — the list's dashed chip.
|
|
461
|
+
tabBuiltIn: { fontStyle: "italic" },
|
|
369
462
|
// Two columns, always: the editor on the left, the rendered result on the
|
|
370
463
|
// right. Stacking the preview under a long form hid it below the fold.
|
|
371
464
|
split: {
|
|
@@ -543,8 +636,14 @@ function TemplateListScreen({
|
|
|
543
636
|
locale
|
|
544
637
|
}) {
|
|
545
638
|
const t = (0, import_client2.createAdminT)(locale);
|
|
546
|
-
const {
|
|
547
|
-
const
|
|
639
|
+
const { catalog, isLoading, error } = (0, import_react_courier_admin2.useTemplateCatalog)(client);
|
|
640
|
+
const emails = catalog?.emails ?? [];
|
|
641
|
+
const defaultLocale = catalog?.defaultLocale ?? "en-US";
|
|
642
|
+
const chipStyle = (l) => ({
|
|
643
|
+
...chip,
|
|
644
|
+
...l.saved ? {} : chipBuiltIn,
|
|
645
|
+
...l.active ? {} : chipOff
|
|
646
|
+
});
|
|
548
647
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.container, children: [
|
|
549
648
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
550
649
|
"div",
|
|
@@ -558,8 +657,12 @@ function TemplateListScreen({
|
|
|
558
657
|
type: "button",
|
|
559
658
|
onClick: () => onCreateTemplate({
|
|
560
659
|
locales: [
|
|
561
|
-
...new Set(
|
|
562
|
-
|
|
660
|
+
...new Set(
|
|
661
|
+
emails.flatMap(
|
|
662
|
+
(e) => (0, import_client2.templateLanguages)(e, defaultLocale).filter((l) => l.locale !== null).map((l) => l.label)
|
|
663
|
+
)
|
|
664
|
+
)
|
|
665
|
+
].sort()
|
|
563
666
|
}),
|
|
564
667
|
style: styles2.newButton,
|
|
565
668
|
children: t("templates.list.newTemplate")
|
|
@@ -569,39 +672,47 @@ function TemplateListScreen({
|
|
|
569
672
|
}
|
|
570
673
|
),
|
|
571
674
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.hint, children: t("templates.list.hint") }),
|
|
572
|
-
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.status, children: t("templates.list.loading") }) : error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
573
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
675
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.status, children: t("templates.list.loading") }) : error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: styles2.list, children: emails.map((email) => {
|
|
677
|
+
const languages = (0, import_client2.templateLanguages)(email, defaultLocale);
|
|
678
|
+
const primary = languages.find((l) => l.locale === null) ?? languages[0];
|
|
679
|
+
const open = (l) => onSelectTemplate?.({
|
|
680
|
+
type: email.type,
|
|
681
|
+
locale: l?.locale ?? null,
|
|
682
|
+
system: email.system
|
|
683
|
+
});
|
|
684
|
+
return (
|
|
685
|
+
// Columns, not a flex row: the language chips line up down the
|
|
686
|
+
// list whatever the email name or badge.
|
|
687
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { style: styles2.row, children: [
|
|
688
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", onClick: () => open(primary), style: styles2.rowButton, children: [
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.type, children: email.type }),
|
|
690
|
+
email.system ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.builtIn, children: t("templates.builtInBadge") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {})
|
|
691
|
+
] }),
|
|
692
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.chips, children: languages.map((l) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
693
|
+
"button",
|
|
694
|
+
{
|
|
695
|
+
type: "button",
|
|
696
|
+
onClick: () => open(l),
|
|
697
|
+
style: chipStyle(l),
|
|
698
|
+
"aria-label": t("templates.list.openLocale", {
|
|
699
|
+
type: email.type,
|
|
700
|
+
locale: l.label
|
|
701
|
+
}),
|
|
702
|
+
title: l.active ? void 0 : t("common.status.inactive"),
|
|
703
|
+
children: l.label
|
|
704
|
+
},
|
|
705
|
+
l.label
|
|
706
|
+
)) }),
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: primary?.active === false ? styles2.inactive : styles2.active, children: [
|
|
583
708
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.dot }),
|
|
584
|
-
|
|
709
|
+
primary?.active === false ? t("common.status.inactive") : t("common.status.active")
|
|
585
710
|
] })
|
|
586
|
-
]
|
|
587
|
-
}
|
|
588
|
-
),
|
|
589
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.chips, children: group.entries.map((entry) => {
|
|
590
|
-
const name = entry.locale ?? t("templates.defaultChip");
|
|
591
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
592
|
-
"button",
|
|
593
|
-
{
|
|
594
|
-
type: "button",
|
|
595
|
-
onClick: () => onSelectTemplate?.(entry),
|
|
596
|
-
style: entry.active ? styles2.chip : styles2.chipInactive,
|
|
597
|
-
"aria-label": t("templates.list.openLocale", { type: group.type, locale: name }),
|
|
598
|
-
title: entry.active ? void 0 : t("common.status.inactive"),
|
|
599
|
-
children: name
|
|
600
|
-
},
|
|
601
|
-
entry.locale ?? ""
|
|
711
|
+
] }, email.type)
|
|
602
712
|
);
|
|
603
|
-
}) })
|
|
604
|
-
|
|
713
|
+
}) }),
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.legend, children: t("templates.list.legend") })
|
|
715
|
+
] })
|
|
605
716
|
] });
|
|
606
717
|
}
|
|
607
718
|
var pill = {
|
|
@@ -615,6 +726,7 @@ var pill = {
|
|
|
615
726
|
lineHeight: 1.5,
|
|
616
727
|
minWidth: 64
|
|
617
728
|
};
|
|
729
|
+
var MONO = 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)';
|
|
618
730
|
var chip = {
|
|
619
731
|
height: 24,
|
|
620
732
|
boxSizing: "border-box",
|
|
@@ -624,9 +736,15 @@ var chip = {
|
|
|
624
736
|
background: "var(--fonderie-surface,#fff)",
|
|
625
737
|
color: "var(--fonderie-text,#171717)",
|
|
626
738
|
fontSize: 12,
|
|
627
|
-
fontFamily:
|
|
739
|
+
fontFamily: MONO,
|
|
628
740
|
cursor: "pointer"
|
|
629
741
|
};
|
|
742
|
+
var chipBuiltIn = {
|
|
743
|
+
borderStyle: "dashed",
|
|
744
|
+
background: "transparent",
|
|
745
|
+
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
746
|
+
};
|
|
747
|
+
var chipOff = { opacity: 0.5, textDecoration: "line-through" };
|
|
630
748
|
var styles2 = {
|
|
631
749
|
container: { padding: "32px 40px 64px", maxWidth: 1160, boxSizing: "border-box" },
|
|
632
750
|
title: {
|
|
@@ -637,6 +755,7 @@ var styles2 = {
|
|
|
637
755
|
lineHeight: 1.25
|
|
638
756
|
},
|
|
639
757
|
hint: { fontSize: 13.5, color: "var(--fonderie-text-muted,#5c5c5c)", margin: "4px 0 24px" },
|
|
758
|
+
legend: { fontSize: 12.5, color: "var(--fonderie-text-muted,#5c5c5c)", margin: "10px 2px 0" },
|
|
640
759
|
status: { padding: "24px 0", color: "var(--fonderie-text-muted,#5c5c5c)", fontSize: 13.5 },
|
|
641
760
|
error: { color: "var(--fonderie-danger,#e00)", marginBottom: 12, fontSize: 14 },
|
|
642
761
|
list: {
|
|
@@ -649,20 +768,20 @@ var styles2 = {
|
|
|
649
768
|
overflow: "hidden",
|
|
650
769
|
boxShadow: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))"
|
|
651
770
|
},
|
|
771
|
+
// name + badge | languages | status — fixed tracks so every column aligns.
|
|
652
772
|
row: {
|
|
653
|
-
display: "
|
|
773
|
+
display: "grid",
|
|
774
|
+
gridTemplateColumns: "minmax(0, 1fr) minmax(180px, 280px) 88px",
|
|
654
775
|
alignItems: "center",
|
|
655
|
-
gap:
|
|
776
|
+
gap: 16,
|
|
656
777
|
paddingRight: 16,
|
|
657
778
|
borderBottom: "1px solid var(--fonderie-border-light,#f5f5f5)"
|
|
658
779
|
},
|
|
659
780
|
rowButton: {
|
|
660
|
-
flex: 1,
|
|
661
781
|
minWidth: 0,
|
|
662
782
|
display: "flex",
|
|
663
|
-
justifyContent: "space-between",
|
|
664
783
|
alignItems: "center",
|
|
665
|
-
gap:
|
|
784
|
+
gap: 12,
|
|
666
785
|
padding: "13px 16px",
|
|
667
786
|
background: "none",
|
|
668
787
|
border: "none",
|
|
@@ -674,12 +793,12 @@ var styles2 = {
|
|
|
674
793
|
type: {
|
|
675
794
|
fontSize: 13,
|
|
676
795
|
fontWeight: 600,
|
|
677
|
-
|
|
678
|
-
|
|
796
|
+
overflow: "hidden",
|
|
797
|
+
textOverflow: "ellipsis",
|
|
798
|
+
whiteSpace: "nowrap",
|
|
799
|
+
fontFamily: MONO
|
|
679
800
|
},
|
|
680
|
-
chips: { display: "flex", flexWrap: "wrap",
|
|
681
|
-
chip,
|
|
682
|
-
chipInactive: { ...chip, opacity: 0.5, textDecoration: "line-through" },
|
|
801
|
+
chips: { display: "flex", flexWrap: "wrap", gap: 6 },
|
|
683
802
|
dot: { width: 6, height: 6, borderRadius: 999, background: "currentColor" },
|
|
684
803
|
builtIn: {
|
|
685
804
|
fontSize: 11,
|
|
@@ -687,7 +806,8 @@ var styles2 = {
|
|
|
687
806
|
padding: "1px 7px",
|
|
688
807
|
borderRadius: 999,
|
|
689
808
|
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
690
|
-
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
809
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
810
|
+
flexShrink: 0
|
|
691
811
|
},
|
|
692
812
|
newButton: {
|
|
693
813
|
display: "inline-flex",
|
|
@@ -729,6 +849,7 @@ function TemplateCreateScreen({
|
|
|
729
849
|
client,
|
|
730
850
|
type,
|
|
731
851
|
locales = [],
|
|
852
|
+
defaultLocale,
|
|
732
853
|
onCreated,
|
|
733
854
|
locale
|
|
734
855
|
}) {
|
|
@@ -748,7 +869,7 @@ function TemplateCreateScreen({
|
|
|
748
869
|
const variables = (0, import_react2.useRef)([]);
|
|
749
870
|
(0, import_react2.useEffect)(() => {
|
|
750
871
|
if (!type) return;
|
|
751
|
-
client.getTemplate(type, null).then(({ result }) => {
|
|
872
|
+
client.getTemplate(type, null).catch(() => client.getBuiltInTemplate(type, null)).then(({ result }) => {
|
|
752
873
|
setSubject(result.subject ?? "");
|
|
753
874
|
setHtml(result.html ?? "");
|
|
754
875
|
setText(result.text);
|
|
@@ -791,6 +912,9 @@ function TemplateCreateScreen({
|
|
|
791
912
|
if (!TYPE_RE.test(t)) return setError(tr("templates.create.errorType"));
|
|
792
913
|
if (addingLocale && !l) return setError(tr("templates.create.errorLocaleRequired"));
|
|
793
914
|
if (l && !LOCALE_RE.test(l)) return setError(tr("templates.create.errorLocale"));
|
|
915
|
+
if (l && defaultLocale && l.toLowerCase() === defaultLocale.toLowerCase()) {
|
|
916
|
+
return setError(tr("templates.create.errorDefaultLocale", { locale: defaultLocale }));
|
|
917
|
+
}
|
|
794
918
|
if (!text.trim()) return setError(tr("templates.create.errorText"));
|
|
795
919
|
setBusy(true);
|
|
796
920
|
try {
|
|
@@ -908,7 +1032,7 @@ function TemplateCreateScreen({
|
|
|
908
1032
|
] })
|
|
909
1033
|
] });
|
|
910
1034
|
}
|
|
911
|
-
var
|
|
1035
|
+
var MONO2 = 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)';
|
|
912
1036
|
var styles3 = {
|
|
913
1037
|
container: { padding: "8px 40px 64px", maxWidth: 1400, boxSizing: "border-box" },
|
|
914
1038
|
// The editor's layout: the form on the left, the render pinned on the right.
|
|
@@ -941,7 +1065,7 @@ var styles3 = {
|
|
|
941
1065
|
borderRadius: 8,
|
|
942
1066
|
padding: 12,
|
|
943
1067
|
fontSize: 13,
|
|
944
|
-
fontFamily:
|
|
1068
|
+
fontFamily: MONO2
|
|
945
1069
|
},
|
|
946
1070
|
// The console's warning token (the shell's amber), readable in both themes.
|
|
947
1071
|
notice: {
|
|
@@ -994,7 +1118,7 @@ var styles3 = {
|
|
|
994
1118
|
lineHeight: 1.55,
|
|
995
1119
|
background: "var(--fonderie-surface,#fff)",
|
|
996
1120
|
color: "var(--fonderie-text,#171717)",
|
|
997
|
-
fontFamily:
|
|
1121
|
+
fontFamily: MONO2
|
|
998
1122
|
},
|
|
999
1123
|
error: {
|
|
1000
1124
|
color: "var(--fonderie-danger,#e00)",
|