@fonderie/react-courier-admin-screens 0.5.0 → 0.7.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 +507 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.js +506 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
TemplateCreateScreen: () => TemplateCreateScreen,
|
|
23
24
|
TemplateEditorScreen: () => TemplateEditorScreen,
|
|
24
25
|
TemplateListScreen: () => TemplateListScreen
|
|
25
26
|
});
|
|
@@ -35,10 +36,14 @@ function TemplateEditorScreen({
|
|
|
35
36
|
client,
|
|
36
37
|
type,
|
|
37
38
|
locale,
|
|
38
|
-
onSaved
|
|
39
|
+
onSaved,
|
|
40
|
+
system = false,
|
|
41
|
+
onDeleted,
|
|
42
|
+
onAddLocale
|
|
39
43
|
}) {
|
|
40
44
|
const { template, isLoading, error, refresh } = (0, import_react_courier_admin.useTemplate)(client, type, locale);
|
|
41
|
-
const { saveTemplate } = (0, import_react_courier_admin.useTemplates)(client);
|
|
45
|
+
const { saveTemplate, removeTemplate } = (0, import_react_courier_admin.useTemplates)(client);
|
|
46
|
+
const [isDeleting, setIsDeleting] = (0, import_react.useState)(false);
|
|
42
47
|
const { revisions, rollback } = (0, import_react_courier_admin.useTemplateRevisions)(client, type, locale);
|
|
43
48
|
const [isSaving, setIsSaving] = (0, import_react.useState)(false);
|
|
44
49
|
const [saveError, setSaveError] = (0, import_react.useState)(null);
|
|
@@ -108,15 +113,42 @@ function TemplateEditorScreen({
|
|
|
108
113
|
setIsSaving(false);
|
|
109
114
|
}
|
|
110
115
|
};
|
|
116
|
+
const handleDelete = async () => {
|
|
117
|
+
const which = locale ? `the ${locale} version of "${type}"` : `"${type}"`;
|
|
118
|
+
const fallback = locale ? " People in that locale will receive the default version." : "";
|
|
119
|
+
if (!window.confirm(`Delete ${which}?${fallback}`)) return;
|
|
120
|
+
setIsDeleting(true);
|
|
121
|
+
setSaveError(null);
|
|
122
|
+
try {
|
|
123
|
+
await removeTemplate(type, locale);
|
|
124
|
+
onDeleted?.();
|
|
125
|
+
} catch (err) {
|
|
126
|
+
setSaveError(err);
|
|
127
|
+
} finally {
|
|
128
|
+
setIsDeleting(false);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
111
131
|
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.status, children: "Loading template\u2026" });
|
|
112
132
|
if (error)
|
|
113
133
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, role: "alert", children: error.explanation });
|
|
114
134
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.container, children: [
|
|
115
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
135
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }, children: [
|
|
136
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { style: styles.title, children: type }),
|
|
137
|
+
onAddLocale && !locale ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
138
|
+
"button",
|
|
139
|
+
{
|
|
140
|
+
type: "button",
|
|
141
|
+
style: { ...styles.rollbackButton, marginLeft: "auto" },
|
|
142
|
+
onClick: () => onAddLocale(type),
|
|
143
|
+
children: "+ Add locale"
|
|
144
|
+
}
|
|
145
|
+
) : null
|
|
146
|
+
] }),
|
|
116
147
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.meta, children: [
|
|
117
|
-
locale ?? "
|
|
148
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: locale ?? "default locale" }),
|
|
118
149
|
" \xB7 v",
|
|
119
|
-
template?.version ?? 1
|
|
150
|
+
template?.version ?? 1,
|
|
151
|
+
system ? " \xB7 built-in email: edit or roll back, it cannot be deleted" : ""
|
|
120
152
|
] }),
|
|
121
153
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.split, children: [
|
|
122
154
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.column, children: [
|
|
@@ -165,10 +197,49 @@ function TemplateEditorScreen({
|
|
|
165
197
|
),
|
|
166
198
|
"Active"
|
|
167
199
|
] }),
|
|
168
|
-
saveError
|
|
200
|
+
saveError?.reason === "VERSION_CONFLICT" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.error, role: "alert", children: [
|
|
201
|
+
"Someone changed this template since you opened it. Reload to see their change, then edit again.",
|
|
202
|
+
" ",
|
|
203
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
204
|
+
"button",
|
|
205
|
+
{
|
|
206
|
+
type: "button",
|
|
207
|
+
style: styles.rollbackButton,
|
|
208
|
+
onClick: () => {
|
|
209
|
+
setSaveError(null);
|
|
210
|
+
void refresh();
|
|
211
|
+
},
|
|
212
|
+
children: "Reload"
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
] }) : saveError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, role: "alert", children: saveError.explanation }) : null,
|
|
169
216
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.saveRow, children: [
|
|
170
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
171
|
-
|
|
217
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
218
|
+
"button",
|
|
219
|
+
{
|
|
220
|
+
type: "submit",
|
|
221
|
+
disabled: isSaving || !dirty,
|
|
222
|
+
style: dirty ? styles.button : styles.buttonDisabled,
|
|
223
|
+
children: isSaving ? "Saving\u2026" : "Save"
|
|
224
|
+
}
|
|
225
|
+
),
|
|
226
|
+
!dirty && !isSaving && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.meta, children: "No changes to save" }),
|
|
227
|
+
!system ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
228
|
+
"button",
|
|
229
|
+
{
|
|
230
|
+
type: "button",
|
|
231
|
+
disabled: isDeleting,
|
|
232
|
+
onClick: () => void handleDelete(),
|
|
233
|
+
style: {
|
|
234
|
+
...styles.rollbackButton,
|
|
235
|
+
height: 36,
|
|
236
|
+
marginLeft: "auto",
|
|
237
|
+
color: "var(--fonderie-danger,#e00)",
|
|
238
|
+
borderColor: "color-mix(in srgb, var(--fonderie-danger,#e00) 40%, transparent)"
|
|
239
|
+
},
|
|
240
|
+
children: isDeleting ? "Deleting\u2026" : "Delete"
|
|
241
|
+
}
|
|
242
|
+
) : null
|
|
172
243
|
] })
|
|
173
244
|
] }),
|
|
174
245
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { style: styles.label, htmlFor: "template-sample", children: "Sample data" }),
|
|
@@ -234,13 +305,24 @@ function TemplateEditorScreen({
|
|
|
234
305
|
] });
|
|
235
306
|
}
|
|
236
307
|
var styles = {
|
|
237
|
-
container: { padding:
|
|
308
|
+
container: { padding: "8px 40px 64px", maxWidth: 1400, boxSizing: "border-box" },
|
|
238
309
|
// Two columns, always: the editor on the left, the rendered result on the
|
|
239
310
|
// right. Stacking the preview under a long form hid it below the fold.
|
|
240
|
-
split: {
|
|
311
|
+
split: {
|
|
312
|
+
display: "grid",
|
|
313
|
+
gridTemplateColumns: "minmax(0, 1fr) minmax(0, 1fr)",
|
|
314
|
+
gap: 24,
|
|
315
|
+
alignItems: "start"
|
|
316
|
+
},
|
|
241
317
|
column: { minWidth: 0, display: "flex", flexDirection: "column" },
|
|
242
318
|
// Pinned while the form scrolls, so the preview stays in view as you edit.
|
|
243
|
-
previewColumn: {
|
|
319
|
+
previewColumn: {
|
|
320
|
+
minWidth: 0,
|
|
321
|
+
display: "flex",
|
|
322
|
+
flexDirection: "column",
|
|
323
|
+
position: "sticky",
|
|
324
|
+
top: 16
|
|
325
|
+
},
|
|
244
326
|
saveRow: { display: "flex", alignItems: "center", gap: 12, marginTop: 16 },
|
|
245
327
|
previewHeader: {
|
|
246
328
|
display: "flex",
|
|
@@ -250,6 +332,7 @@ var styles = {
|
|
|
250
332
|
},
|
|
251
333
|
previewSubject: { fontSize: 14, fontWeight: 600, margin: "8px 0" },
|
|
252
334
|
previewFrame: {
|
|
335
|
+
boxShadow: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))",
|
|
253
336
|
width: "100%",
|
|
254
337
|
height: 520,
|
|
255
338
|
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
@@ -264,60 +347,127 @@ var styles = {
|
|
|
264
347
|
fontSize: 13,
|
|
265
348
|
fontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)'
|
|
266
349
|
},
|
|
267
|
-
title: {
|
|
268
|
-
|
|
350
|
+
title: {
|
|
351
|
+
fontSize: 22,
|
|
352
|
+
fontWeight: 600,
|
|
353
|
+
margin: "8px 0 4px",
|
|
354
|
+
letterSpacing: "var(--fonderie-tracking-display,-0.05em)",
|
|
355
|
+
lineHeight: 1.25
|
|
356
|
+
},
|
|
357
|
+
meta: { fontSize: 13, color: "var(--fonderie-text-muted,#5c5c5c)", marginBottom: 20 },
|
|
269
358
|
status: { padding: 24, textAlign: "center", color: "var(--fonderie-text-muted,#5c5c5c)" },
|
|
270
|
-
error: {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
359
|
+
error: {
|
|
360
|
+
color: "var(--fonderie-danger,#e00)",
|
|
361
|
+
background: "color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)",
|
|
362
|
+
borderRadius: 6,
|
|
363
|
+
padding: "8px 12px",
|
|
364
|
+
margin: "8px 0",
|
|
365
|
+
fontSize: 13.5
|
|
366
|
+
},
|
|
367
|
+
form: {
|
|
368
|
+
display: "flex",
|
|
369
|
+
flexDirection: "column",
|
|
370
|
+
gap: 4,
|
|
371
|
+
background: "var(--fonderie-surface,#fff)",
|
|
372
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
373
|
+
borderRadius: "var(--fonderie-radius-lg,8px)",
|
|
374
|
+
padding: "6px 20px 20px",
|
|
375
|
+
boxShadow: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))"
|
|
376
|
+
},
|
|
377
|
+
label: { fontSize: 13, fontWeight: 500, marginTop: 14, marginBottom: 2 },
|
|
378
|
+
input: {
|
|
379
|
+
height: 36,
|
|
380
|
+
boxSizing: "border-box",
|
|
381
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
382
|
+
borderRadius: 6,
|
|
383
|
+
padding: "0 10px",
|
|
384
|
+
fontSize: 13.5,
|
|
385
|
+
fontFamily: "inherit",
|
|
386
|
+
background: "var(--fonderie-surface,#fff)",
|
|
387
|
+
color: "var(--fonderie-text,#171717)"
|
|
388
|
+
},
|
|
274
389
|
textarea: {
|
|
275
390
|
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
276
|
-
borderRadius:
|
|
391
|
+
borderRadius: 6,
|
|
277
392
|
padding: 10,
|
|
278
|
-
fontSize:
|
|
393
|
+
fontSize: 13,
|
|
394
|
+
lineHeight: 1.55,
|
|
395
|
+
background: "var(--fonderie-surface,#fff)",
|
|
396
|
+
color: "var(--fonderie-text,#171717)",
|
|
279
397
|
fontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)'
|
|
280
398
|
},
|
|
281
399
|
checkboxLabel: { display: "flex", alignItems: "center", gap: 8, marginTop: 12, fontSize: 14 },
|
|
282
400
|
button: {
|
|
401
|
+
display: "inline-flex",
|
|
402
|
+
alignItems: "center",
|
|
403
|
+
height: 36,
|
|
404
|
+
boxSizing: "border-box",
|
|
283
405
|
backgroundColor: "var(--fonderie-text,#171717)",
|
|
284
406
|
color: "var(--fonderie-surface,#fff)",
|
|
285
|
-
padding: "
|
|
286
|
-
borderRadius:
|
|
287
|
-
border: "
|
|
288
|
-
fontSize:
|
|
407
|
+
padding: "0 16px",
|
|
408
|
+
borderRadius: 6,
|
|
409
|
+
border: "1px solid var(--fonderie-text,#171717)",
|
|
410
|
+
fontSize: 13.5,
|
|
289
411
|
fontWeight: 600,
|
|
412
|
+
fontFamily: "inherit",
|
|
290
413
|
cursor: "pointer",
|
|
291
414
|
alignSelf: "flex-start"
|
|
292
415
|
},
|
|
293
416
|
buttonDisabled: {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
417
|
+
display: "inline-flex",
|
|
418
|
+
alignItems: "center",
|
|
419
|
+
height: 36,
|
|
420
|
+
boxSizing: "border-box",
|
|
421
|
+
backgroundColor: "var(--fonderie-text,#171717)",
|
|
422
|
+
color: "var(--fonderie-surface,#fff)",
|
|
423
|
+
padding: "0 16px",
|
|
424
|
+
borderRadius: 6,
|
|
425
|
+
border: "1px solid var(--fonderie-text,#171717)",
|
|
426
|
+
fontSize: 13.5,
|
|
300
427
|
fontWeight: 600,
|
|
301
|
-
|
|
302
|
-
alignSelf: "flex-start"
|
|
428
|
+
fontFamily: "inherit",
|
|
429
|
+
alignSelf: "flex-start",
|
|
430
|
+
opacity: 0.45,
|
|
431
|
+
cursor: "not-allowed"
|
|
303
432
|
},
|
|
304
433
|
revisions: { marginTop: 32 },
|
|
305
|
-
subtitle: {
|
|
306
|
-
|
|
434
|
+
subtitle: {
|
|
435
|
+
fontSize: 15,
|
|
436
|
+
fontWeight: 600,
|
|
437
|
+
margin: "0 0 10px",
|
|
438
|
+
letterSpacing: "var(--fonderie-tracking-display,-0.05em)"
|
|
439
|
+
},
|
|
440
|
+
list: {
|
|
441
|
+
listStyle: "none",
|
|
442
|
+
padding: 0,
|
|
443
|
+
margin: 0,
|
|
444
|
+
background: "var(--fonderie-surface,#fff)",
|
|
445
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
446
|
+
borderRadius: "var(--fonderie-radius-lg,8px)",
|
|
447
|
+
overflow: "hidden"
|
|
448
|
+
},
|
|
307
449
|
row: {
|
|
308
450
|
display: "flex",
|
|
309
451
|
justifyContent: "space-between",
|
|
310
452
|
alignItems: "center",
|
|
311
|
-
|
|
453
|
+
gap: 12,
|
|
454
|
+
padding: "9px 16px",
|
|
312
455
|
borderBottom: "1px solid var(--fonderie-border-light,#f5f5f5)",
|
|
313
456
|
fontSize: 13
|
|
314
457
|
},
|
|
315
458
|
rollbackButton: {
|
|
316
|
-
|
|
459
|
+
display: "inline-flex",
|
|
460
|
+
alignItems: "center",
|
|
461
|
+
height: 28,
|
|
462
|
+
boxSizing: "border-box",
|
|
463
|
+
background: "var(--fonderie-surface,#fff)",
|
|
464
|
+
color: "var(--fonderie-text,#171717)",
|
|
317
465
|
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
318
|
-
borderRadius:
|
|
319
|
-
padding: "
|
|
320
|
-
fontSize: 12,
|
|
466
|
+
borderRadius: 6,
|
|
467
|
+
padding: "0 10px",
|
|
468
|
+
fontSize: 12.5,
|
|
469
|
+
fontWeight: 500,
|
|
470
|
+
fontFamily: "inherit",
|
|
321
471
|
cursor: "pointer"
|
|
322
472
|
}
|
|
323
473
|
};
|
|
@@ -325,14 +475,37 @@ var styles = {
|
|
|
325
475
|
// src/screens/TemplateListScreen.tsx
|
|
326
476
|
var import_react_courier_admin2 = require("@fonderie/react-courier-admin");
|
|
327
477
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
328
|
-
function TemplateListScreen({
|
|
478
|
+
function TemplateListScreen({
|
|
479
|
+
client,
|
|
480
|
+
onSelectTemplate,
|
|
481
|
+
onCreateTemplate
|
|
482
|
+
}) {
|
|
329
483
|
const { templates, isLoading, error } = (0, import_react_courier_admin2.useTemplates)(client);
|
|
330
|
-
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.status, children: "Loading templates\u2026" });
|
|
331
|
-
if (error)
|
|
332
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.error, role: "alert", children: error.explanation });
|
|
333
484
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.container, children: [
|
|
334
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
335
|
-
|
|
485
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
486
|
+
"div",
|
|
487
|
+
{
|
|
488
|
+
style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 },
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { style: styles2.title, children: "Templates" }),
|
|
491
|
+
onCreateTemplate ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
492
|
+
"button",
|
|
493
|
+
{
|
|
494
|
+
type: "button",
|
|
495
|
+
onClick: () => onCreateTemplate({
|
|
496
|
+
locales: [
|
|
497
|
+
...new Set(templates.map((t) => t.locale).filter((l) => !!l))
|
|
498
|
+
]
|
|
499
|
+
}),
|
|
500
|
+
style: styles2.newButton,
|
|
501
|
+
children: "New template"
|
|
502
|
+
}
|
|
503
|
+
) : null
|
|
504
|
+
]
|
|
505
|
+
}
|
|
506
|
+
),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.hint, children: "Every email the app sends. Open one to edit its copy and preview it live." }),
|
|
508
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.status, children: "Loading templates\u2026" }) : error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles2.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: styles2.list, children: templates.map((template) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { style: styles2.row, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
336
509
|
"button",
|
|
337
510
|
{
|
|
338
511
|
type: "button",
|
|
@@ -340,38 +513,316 @@ function TemplateListScreen({ client, onSelectTemplate }) {
|
|
|
340
513
|
style: styles2.rowButton,
|
|
341
514
|
children: [
|
|
342
515
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.type, children: template.type }),
|
|
343
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.locale, children: template.locale ?? "
|
|
344
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style:
|
|
516
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.locale, children: template.locale ?? "default locale" }),
|
|
517
|
+
template.system ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.builtIn, children: "built-in" }) : null,
|
|
518
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: template.active ? styles2.active : styles2.inactive, children: [
|
|
519
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.dot }),
|
|
520
|
+
template.active ? "active" : "inactive"
|
|
521
|
+
] })
|
|
345
522
|
]
|
|
346
523
|
}
|
|
347
524
|
) }, `${template.type}:${template.locale ?? "base"}`)) })
|
|
348
525
|
] });
|
|
349
526
|
}
|
|
527
|
+
var pill = {
|
|
528
|
+
display: "inline-flex",
|
|
529
|
+
alignItems: "center",
|
|
530
|
+
gap: 6,
|
|
531
|
+
borderRadius: 999,
|
|
532
|
+
padding: "2px 9px 2px 8px",
|
|
533
|
+
fontSize: 12,
|
|
534
|
+
fontWeight: 600,
|
|
535
|
+
lineHeight: 1.5,
|
|
536
|
+
minWidth: 64
|
|
537
|
+
};
|
|
350
538
|
var styles2 = {
|
|
351
|
-
container: { padding:
|
|
352
|
-
title: {
|
|
353
|
-
|
|
539
|
+
container: { padding: "32px 40px 64px", maxWidth: 1160, boxSizing: "border-box" },
|
|
540
|
+
title: {
|
|
541
|
+
fontSize: 22,
|
|
542
|
+
fontWeight: 600,
|
|
543
|
+
margin: 0,
|
|
544
|
+
letterSpacing: "var(--fonderie-tracking-display,-0.05em)",
|
|
545
|
+
lineHeight: 1.25
|
|
546
|
+
},
|
|
547
|
+
hint: { fontSize: 13.5, color: "var(--fonderie-text-muted,#5c5c5c)", margin: "4px 0 24px" },
|
|
548
|
+
status: { padding: "24px 0", color: "var(--fonderie-text-muted,#5c5c5c)", fontSize: 13.5 },
|
|
354
549
|
error: { color: "var(--fonderie-danger,#e00)", marginBottom: 12, fontSize: 14 },
|
|
355
|
-
list: {
|
|
550
|
+
list: {
|
|
551
|
+
listStyle: "none",
|
|
552
|
+
padding: 0,
|
|
553
|
+
margin: 0,
|
|
554
|
+
background: "var(--fonderie-surface,#fff)",
|
|
555
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
556
|
+
borderRadius: "var(--fonderie-radius-lg,8px)",
|
|
557
|
+
overflow: "hidden",
|
|
558
|
+
boxShadow: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))"
|
|
559
|
+
},
|
|
356
560
|
row: { borderBottom: "1px solid var(--fonderie-border-light,#f5f5f5)" },
|
|
357
561
|
rowButton: {
|
|
358
562
|
width: "100%",
|
|
359
563
|
display: "flex",
|
|
360
564
|
justifyContent: "space-between",
|
|
361
565
|
alignItems: "center",
|
|
362
|
-
|
|
566
|
+
gap: 16,
|
|
567
|
+
padding: "13px 16px",
|
|
363
568
|
background: "none",
|
|
364
569
|
border: "none",
|
|
365
570
|
cursor: "pointer",
|
|
366
|
-
textAlign: "left"
|
|
571
|
+
textAlign: "left",
|
|
572
|
+
color: "var(--fonderie-text,#171717)",
|
|
573
|
+
fontFamily: "inherit"
|
|
574
|
+
},
|
|
575
|
+
type: {
|
|
576
|
+
fontSize: 13,
|
|
577
|
+
fontWeight: 600,
|
|
578
|
+
flex: 1,
|
|
579
|
+
fontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)'
|
|
580
|
+
},
|
|
581
|
+
locale: { fontSize: 12.5, color: "var(--fonderie-text-muted,#5c5c5c)" },
|
|
582
|
+
dot: { width: 6, height: 6, borderRadius: 999, background: "currentColor" },
|
|
583
|
+
builtIn: {
|
|
584
|
+
fontSize: 11,
|
|
585
|
+
fontWeight: 500,
|
|
586
|
+
padding: "1px 7px",
|
|
587
|
+
borderRadius: 999,
|
|
588
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
589
|
+
color: "var(--fonderie-text-muted,#5c5c5c)"
|
|
590
|
+
},
|
|
591
|
+
newButton: {
|
|
592
|
+
display: "inline-flex",
|
|
593
|
+
alignItems: "center",
|
|
594
|
+
height: 32,
|
|
595
|
+
boxSizing: "border-box",
|
|
596
|
+
borderRadius: 6,
|
|
597
|
+
padding: "0 12px",
|
|
598
|
+
fontSize: 13,
|
|
599
|
+
fontWeight: 500,
|
|
600
|
+
fontFamily: "inherit",
|
|
601
|
+
cursor: "pointer",
|
|
602
|
+
backgroundColor: "var(--fonderie-text,#171717)",
|
|
603
|
+
color: "var(--fonderie-surface,#fff)",
|
|
604
|
+
border: "1px solid var(--fonderie-text,#171717)"
|
|
367
605
|
},
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
606
|
+
active: {
|
|
607
|
+
...pill,
|
|
608
|
+
color: "var(--fonderie-accent-strong,#009767)",
|
|
609
|
+
background: "color-mix(in srgb, var(--fonderie-accent-strong,#009767) 13%, transparent)"
|
|
610
|
+
},
|
|
611
|
+
inactive: {
|
|
612
|
+
...pill,
|
|
613
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
614
|
+
background: "color-mix(in srgb, var(--fonderie-text-muted,#5c5c5c) 10%, transparent)"
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// src/screens/TemplateCreateScreen.tsx
|
|
619
|
+
var import_client = require("@fonderie/client");
|
|
620
|
+
var import_react2 = require("react");
|
|
621
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
622
|
+
var TYPE_RE = /^[a-z0-9][a-z0-9_-]{0,80}$/;
|
|
623
|
+
var LOCALE_RE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
624
|
+
function TemplateCreateScreen({
|
|
625
|
+
client,
|
|
626
|
+
type,
|
|
627
|
+
locales = [],
|
|
628
|
+
onCreated
|
|
629
|
+
}) {
|
|
630
|
+
const addingLocale = type !== void 0;
|
|
631
|
+
const [newType, setNewType] = (0, import_react2.useState)("");
|
|
632
|
+
const [locale, setLocale] = (0, import_react2.useState)("");
|
|
633
|
+
const [subject, setSubject] = (0, import_react2.useState)("");
|
|
634
|
+
const [html, setHtml] = (0, import_react2.useState)("");
|
|
635
|
+
const [text, setText] = (0, import_react2.useState)("");
|
|
636
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
637
|
+
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
638
|
+
(0, import_react2.useEffect)(() => {
|
|
639
|
+
if (!type) return;
|
|
640
|
+
client.getTemplate(type, null).then(({ result }) => {
|
|
641
|
+
setSubject(result.subject ?? "");
|
|
642
|
+
setHtml(result.html ?? "");
|
|
643
|
+
setText(result.text);
|
|
644
|
+
}).catch(() => void 0);
|
|
645
|
+
}, [client, type]);
|
|
646
|
+
const submit = async (e) => {
|
|
647
|
+
e.preventDefault();
|
|
648
|
+
setError(null);
|
|
649
|
+
const t = addingLocale ? type : newType.trim();
|
|
650
|
+
const l = locale.trim() || null;
|
|
651
|
+
if (!TYPE_RE.test(t))
|
|
652
|
+
return setError("Type: lowercase letters, digits, - and _ (e.g. weekly-digest).");
|
|
653
|
+
if (addingLocale && !l) return setError("Choose the locale to add, e.g. fr or fr-CA.");
|
|
654
|
+
if (l && !LOCALE_RE.test(l)) return setError("Locale: a language tag such as fr, es or fr-CA.");
|
|
655
|
+
if (!text.trim())
|
|
656
|
+
return setError("The plain-text body is required \u2014 it is what every email client can show.");
|
|
657
|
+
setBusy(true);
|
|
658
|
+
try {
|
|
659
|
+
const exists = await client.getTemplate(t, l).then(
|
|
660
|
+
() => true,
|
|
661
|
+
(err) => !(err instanceof import_client.FonderieApiError && err.status === 404)
|
|
662
|
+
);
|
|
663
|
+
if (exists) {
|
|
664
|
+
setError(`"${t}"${l ? ` (${l})` : ""} already exists \u2014 open it from the list to edit.`);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
const input = { text, active: true };
|
|
668
|
+
if (subject) input.subject = subject;
|
|
669
|
+
if (html) input.html = html;
|
|
670
|
+
await client.setTemplate(t, input, l);
|
|
671
|
+
onCreated?.({ type: t, locale: l });
|
|
672
|
+
} catch (err) {
|
|
673
|
+
setError(err instanceof import_client.FonderieApiError ? err.explanation : String(err));
|
|
674
|
+
} finally {
|
|
675
|
+
setBusy(false);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: styles3.container, children: [
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { style: styles3.title, children: addingLocale ? `Add a locale to ${type}` : "New template" }),
|
|
680
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: styles3.meta, children: addingLocale ? "Starts from the default copy. People whose locale matches receive this version; everyone else keeps the default." : "For an email your app sends that has no stored copy yet. The type must match what the app sends." }),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { style: styles3.form, onSubmit: (e) => void submit(e), children: [
|
|
682
|
+
!addingLocale ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: styles3.label, htmlFor: "new-template-type", children: "Type" }),
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
685
|
+
"input",
|
|
686
|
+
{
|
|
687
|
+
id: "new-template-type",
|
|
688
|
+
style: styles3.input,
|
|
689
|
+
value: newType,
|
|
690
|
+
placeholder: "weekly-digest",
|
|
691
|
+
autoComplete: "off",
|
|
692
|
+
spellCheck: false,
|
|
693
|
+
onChange: (e) => setNewType(e.target.value)
|
|
694
|
+
}
|
|
695
|
+
)
|
|
696
|
+
] }) : null,
|
|
697
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: styles3.label, htmlFor: "new-template-locale", children: [
|
|
698
|
+
"Locale ",
|
|
699
|
+
addingLocale ? "" : "(optional \u2014 empty is the default)"
|
|
700
|
+
] }),
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
702
|
+
"input",
|
|
703
|
+
{
|
|
704
|
+
id: "new-template-locale",
|
|
705
|
+
style: styles3.input,
|
|
706
|
+
value: locale,
|
|
707
|
+
placeholder: "fr",
|
|
708
|
+
list: "new-template-locales",
|
|
709
|
+
autoComplete: "off",
|
|
710
|
+
spellCheck: false,
|
|
711
|
+
onChange: (e) => setLocale(e.target.value)
|
|
712
|
+
}
|
|
713
|
+
),
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("datalist", { id: "new-template-locales", children: [...new Set(locales)].map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: l }, l)) }),
|
|
715
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: styles3.label, htmlFor: "new-template-subject", children: "Subject" }),
|
|
716
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
717
|
+
"input",
|
|
718
|
+
{
|
|
719
|
+
id: "new-template-subject",
|
|
720
|
+
style: styles3.input,
|
|
721
|
+
value: subject,
|
|
722
|
+
onChange: (e) => setSubject(e.target.value)
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: styles3.label, htmlFor: "new-template-html", children: "HTML body" }),
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
727
|
+
"textarea",
|
|
728
|
+
{
|
|
729
|
+
id: "new-template-html",
|
|
730
|
+
style: { ...styles3.textarea, minHeight: 160 },
|
|
731
|
+
value: html,
|
|
732
|
+
onChange: (e) => setHtml(e.target.value)
|
|
733
|
+
}
|
|
734
|
+
),
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: styles3.label, htmlFor: "new-template-text", children: "Plain-text body" }),
|
|
736
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
737
|
+
"textarea",
|
|
738
|
+
{
|
|
739
|
+
id: "new-template-text",
|
|
740
|
+
style: { ...styles3.textarea, minHeight: 100 },
|
|
741
|
+
value: text,
|
|
742
|
+
onChange: (e) => setText(e.target.value)
|
|
743
|
+
}
|
|
744
|
+
),
|
|
745
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: styles3.error, role: "alert", children: error }) : null,
|
|
746
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", disabled: busy, style: styles3.button, children: busy ? "Creating\u2026" : addingLocale ? "Add locale" : "Create template" })
|
|
747
|
+
] })
|
|
748
|
+
] });
|
|
749
|
+
}
|
|
750
|
+
var MONO = 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)';
|
|
751
|
+
var styles3 = {
|
|
752
|
+
container: { padding: "8px 40px 64px", maxWidth: 760, boxSizing: "border-box" },
|
|
753
|
+
title: {
|
|
754
|
+
fontSize: 22,
|
|
755
|
+
fontWeight: 600,
|
|
756
|
+
margin: "8px 0 4px",
|
|
757
|
+
letterSpacing: "var(--fonderie-tracking-display,-0.05em)",
|
|
758
|
+
lineHeight: 1.25
|
|
759
|
+
},
|
|
760
|
+
meta: {
|
|
761
|
+
fontSize: 13,
|
|
762
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
763
|
+
marginBottom: 20,
|
|
764
|
+
lineHeight: 1.5
|
|
765
|
+
},
|
|
766
|
+
form: {
|
|
767
|
+
display: "flex",
|
|
768
|
+
flexDirection: "column",
|
|
769
|
+
gap: 4,
|
|
770
|
+
background: "var(--fonderie-surface,#fff)",
|
|
771
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
772
|
+
borderRadius: "var(--fonderie-radius-lg,8px)",
|
|
773
|
+
padding: "6px 20px 20px"
|
|
774
|
+
},
|
|
775
|
+
label: { fontSize: 13, fontWeight: 500, marginTop: 14, marginBottom: 2 },
|
|
776
|
+
input: {
|
|
777
|
+
height: 36,
|
|
778
|
+
boxSizing: "border-box",
|
|
779
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
780
|
+
borderRadius: 6,
|
|
781
|
+
padding: "0 10px",
|
|
782
|
+
fontSize: 13.5,
|
|
783
|
+
fontFamily: "inherit",
|
|
784
|
+
background: "var(--fonderie-surface,#fff)",
|
|
785
|
+
color: "var(--fonderie-text,#171717)"
|
|
786
|
+
},
|
|
787
|
+
textarea: {
|
|
788
|
+
border: "1px solid var(--fonderie-border,#e0e0e0)",
|
|
789
|
+
borderRadius: 6,
|
|
790
|
+
padding: 10,
|
|
791
|
+
fontSize: 13,
|
|
792
|
+
lineHeight: 1.55,
|
|
793
|
+
background: "var(--fonderie-surface,#fff)",
|
|
794
|
+
color: "var(--fonderie-text,#171717)",
|
|
795
|
+
fontFamily: MONO
|
|
796
|
+
},
|
|
797
|
+
error: {
|
|
798
|
+
color: "var(--fonderie-danger,#e00)",
|
|
799
|
+
background: "color-mix(in srgb, var(--fonderie-danger,#e00) 8%, transparent)",
|
|
800
|
+
borderRadius: 6,
|
|
801
|
+
padding: "8px 12px",
|
|
802
|
+
margin: "8px 0",
|
|
803
|
+
fontSize: 13.5
|
|
804
|
+
},
|
|
805
|
+
button: {
|
|
806
|
+
display: "inline-flex",
|
|
807
|
+
alignItems: "center",
|
|
808
|
+
height: 36,
|
|
809
|
+
boxSizing: "border-box",
|
|
810
|
+
backgroundColor: "var(--fonderie-text,#171717)",
|
|
811
|
+
color: "var(--fonderie-surface,#fff)",
|
|
812
|
+
padding: "0 16px",
|
|
813
|
+
borderRadius: 6,
|
|
814
|
+
border: "1px solid var(--fonderie-text,#171717)",
|
|
815
|
+
fontSize: 13.5,
|
|
816
|
+
fontWeight: 600,
|
|
817
|
+
fontFamily: "inherit",
|
|
818
|
+
cursor: "pointer",
|
|
819
|
+
alignSelf: "flex-start",
|
|
820
|
+
marginTop: 16
|
|
821
|
+
}
|
|
372
822
|
};
|
|
373
823
|
// Annotate the CommonJS export names for ESM import in node:
|
|
374
824
|
0 && (module.exports = {
|
|
825
|
+
TemplateCreateScreen,
|
|
375
826
|
TemplateEditorScreen,
|
|
376
827
|
TemplateListScreen
|
|
377
828
|
});
|