@fonderie/vue-courier-admin-screens 0.4.1 → 0.5.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 +43 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +44 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,9 +31,14 @@ var import_vue = require("vue");
|
|
|
31
31
|
|
|
32
32
|
// src/styles.ts
|
|
33
33
|
var styles = {
|
|
34
|
-
container: { padding: "24px"
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
container: { padding: "24px" },
|
|
35
|
+
// Two columns, always: editor left, rendered result right. Stacking the
|
|
36
|
+
// preview under a long form hid it below the fold.
|
|
37
|
+
split: { display: "grid", gridTemplateColumns: "minmax(0, 1fr) minmax(0, 1fr)", gap: "24px", alignItems: "start" },
|
|
38
|
+
column: { minWidth: "0", display: "flex", flexDirection: "column" },
|
|
39
|
+
// Pinned while the form scrolls, so the preview stays in view as you edit.
|
|
40
|
+
previewColumn: { minWidth: "0", display: "flex", flexDirection: "column", position: "sticky", top: "16px" },
|
|
41
|
+
saveRow: { display: "flex", alignItems: "center", gap: "12px", marginTop: "16px" },
|
|
37
42
|
previewHeader: {
|
|
38
43
|
display: "flex",
|
|
39
44
|
justifyContent: "space-between",
|
|
@@ -96,7 +101,6 @@ var styles = {
|
|
|
96
101
|
fontSize: "14px"
|
|
97
102
|
},
|
|
98
103
|
button: {
|
|
99
|
-
marginTop: "16px",
|
|
100
104
|
backgroundColor: "var(--fonderie-text,#171717)",
|
|
101
105
|
color: "var(--fonderie-surface,#fff)",
|
|
102
106
|
padding: "10px 20px",
|
|
@@ -107,6 +111,17 @@ var styles = {
|
|
|
107
111
|
cursor: "pointer",
|
|
108
112
|
alignSelf: "flex-start"
|
|
109
113
|
},
|
|
114
|
+
buttonDisabled: {
|
|
115
|
+
backgroundColor: "var(--fonderie-border,#e0e0e0)",
|
|
116
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
117
|
+
padding: "10px 20px",
|
|
118
|
+
borderRadius: "8px",
|
|
119
|
+
border: "none",
|
|
120
|
+
fontSize: "14px",
|
|
121
|
+
fontWeight: 600,
|
|
122
|
+
cursor: "not-allowed",
|
|
123
|
+
alignSelf: "flex-start"
|
|
124
|
+
},
|
|
110
125
|
revisions: { marginTop: "32px" },
|
|
111
126
|
revisionRow: {
|
|
112
127
|
display: "flex",
|
|
@@ -127,6 +142,7 @@ var styles = {
|
|
|
127
142
|
};
|
|
128
143
|
|
|
129
144
|
// src/screens/TemplateEditorScreen.ts
|
|
145
|
+
var PREVIEW_DEBOUNCE_MS = 500;
|
|
130
146
|
var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
131
147
|
var TemplateEditorScreen = (0, import_vue.defineComponent)({
|
|
132
148
|
name: "FonderieTemplateEditorScreen",
|
|
@@ -200,8 +216,15 @@ var TemplateEditorScreen = (0, import_vue.defineComponent)({
|
|
|
200
216
|
);
|
|
201
217
|
}
|
|
202
218
|
}
|
|
203
|
-
|
|
204
|
-
|
|
219
|
+
let previewTimer;
|
|
220
|
+
(0, import_vue.watch)([template, subject, html, text, sampleJson], () => {
|
|
221
|
+
if (!template.value) return;
|
|
222
|
+
clearTimeout(previewTimer);
|
|
223
|
+
previewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);
|
|
224
|
+
});
|
|
225
|
+
const dirty = (0, import_vue.computed)(() => {
|
|
226
|
+
const tpl = template.value;
|
|
227
|
+
return !!tpl && (subject.value !== (tpl.subject ?? "") || html.value !== (tpl.html ?? "") || text.value !== tpl.text || active.value !== tpl.active);
|
|
205
228
|
});
|
|
206
229
|
async function handleSubmit(event) {
|
|
207
230
|
event.preventDefault();
|
|
@@ -289,11 +312,18 @@ var TemplateEditorScreen = (0, import_vue.defineComponent)({
|
|
|
289
312
|
"Active"
|
|
290
313
|
]),
|
|
291
314
|
saveError.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, saveError.value.explanation) : null,
|
|
292
|
-
(0, import_vue.h)(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
315
|
+
(0, import_vue.h)("div", { style: styles.saveRow }, [
|
|
316
|
+
(0, import_vue.h)(
|
|
317
|
+
"button",
|
|
318
|
+
{
|
|
319
|
+
type: "submit",
|
|
320
|
+
disabled: isSaving.value || !dirty.value,
|
|
321
|
+
style: dirty.value ? styles.button : styles.buttonDisabled
|
|
322
|
+
},
|
|
323
|
+
isSaving.value ? "Saving\u2026" : "Save"
|
|
324
|
+
),
|
|
325
|
+
!dirty.value && !isSaving.value ? (0, import_vue.h)("span", { style: styles.meta }, "No changes to save") : null
|
|
326
|
+
])
|
|
297
327
|
]),
|
|
298
328
|
(0, import_vue.h)("label", { style: styles.label, for: "template-sample" }, "Sample data"),
|
|
299
329
|
(0, import_vue.h)("textarea", {
|
|
@@ -308,19 +338,10 @@ var TemplateEditorScreen = (0, import_vue.defineComponent)({
|
|
|
308
338
|
}),
|
|
309
339
|
sampleError.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, sampleError.value) : null
|
|
310
340
|
]),
|
|
311
|
-
(0, import_vue.h)("div", { style: styles.
|
|
341
|
+
(0, import_vue.h)("div", { style: styles.previewColumn }, [
|
|
312
342
|
(0, import_vue.h)("div", { style: styles.previewHeader }, [
|
|
313
343
|
(0, import_vue.h)("span", { style: styles.label }, "Preview"),
|
|
314
|
-
(0, import_vue.h)(
|
|
315
|
-
"button",
|
|
316
|
-
{
|
|
317
|
-
type: "button",
|
|
318
|
-
style: styles.rollbackButton,
|
|
319
|
-
disabled: isPreviewing.value,
|
|
320
|
-
onClick: () => void run()
|
|
321
|
-
},
|
|
322
|
-
isPreviewing.value ? "Rendering\u2026" : "Render"
|
|
323
|
-
)
|
|
344
|
+
(0, import_vue.h)("span", { style: styles.meta }, isPreviewing.value ? "Rendering\u2026" : "Live")
|
|
324
345
|
]),
|
|
325
346
|
previewError.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, previewError.value.explanation) : null,
|
|
326
347
|
preview.value?.subject ? (0, import_vue.h)("p", { style: styles.previewSubject }, preview.value.subject) : null,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/screens/TemplateEditorScreen.ts","../src/styles.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["export { TemplateEditorScreen, TemplateListScreen } from './screens';\n","import type {\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h, ref, watch } from 'vue';\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { saveTemplate } = useTemplates(props.client);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<string | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'Sample data must be a JSON object.';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'Sample data is not valid JSON.';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// One render once the template has loaded, so the pane is never empty on\n\t\t// arrival. After that it is explicit — a request per keystroke is not a\n\t\t// preview, it is a load test.\n\t\twatch(template, (tpl) => {\n\t\t\tif (tpl) void run();\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? 'unknown'} — ${new Date(rev.createdAt).toLocaleString()}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\t'Roll back',\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading template…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t`${props.locale ?? 'base'} · v${template.value?.version ?? 1}`,\n\t\t\t\t),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, 'Subject'),\n\t\t\t\t\th('input', {\n\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, 'HTML body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, 'Plain-text body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t'Active',\n\t\t\t\t\t]),\n\t\t\t\t\tsaveError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\th(\n\t\t\t\t\t\t'button',\n\t\t\t\t\t\t{ type: 'submit', disabled: isSaving.value, style: styles.button },\n\t\t\t\t\t\tisSaving.value ? 'Saving…' : 'Save',\n\t\t\t\t\t),\n\t\t\t\t]),\n\t\t\t\th('label', { style: styles.label, for: 'template-sample' }, 'Sample data'),\n\t\t\t\th('textarea', {\n\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\trows: 6,\n\t\t\t\t\tspellcheck: false,\n\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tsampleError.value\n\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, sampleError.value)\n\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\th('span', { style: styles.label }, 'Preview'),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: styles.rollbackButton,\n\t\t\t\t\t\t\t\tdisabled: isPreviewing.value,\n\t\t\t\t\t\t\t\tonClick: () => void run(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tisPreviewing.value ? 'Rendering…' : 'Render',\n\t\t\t\t\t\t),\n\t\t\t\t\t]),\n\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\ttitle: 'Template preview',\n\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t: h('p', { style: styles.meta }, 'Nothing rendered yet.'),\n\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, 'History'),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '24px', maxWidth: '1180px' },\n\tsplit: { display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' },\n\tcolumn: { flex: '1 1 460px', minWidth: '320px', display: 'flex', flexDirection: 'column' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: { fontSize: '24px', fontWeight: 700 },\n\tsubtitle: { fontSize: '16px', fontWeight: 600, marginBottom: '8px' },\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '16px' },\n\tstatus: { padding: '24px', textAlign: 'center', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\terror: { color: 'var(--fonderie-danger,#e00)', marginBottom: '12px', fontSize: '14px' },\n\tlist: { listStyle: 'none', padding: '0', margin: '0' },\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '12px 0',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t},\n\ttype: { fontSize: '14px', fontWeight: 600, flex: '1' },\n\tlocale: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginRight: '16px' },\n\tactive: { fontSize: '12px', color: 'var(--fonderie-accent-strong,#009767)' },\n\tinactive: { fontSize: '12px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tform: { display: 'flex', flexDirection: 'column', gap: '4px' },\n\tlabel: { fontSize: '13px', fontWeight: 600, marginTop: '12px' },\n\tinput: { border: '1px solid var(--fonderie-border,#e0e0e0)', borderRadius: '8px', padding: '10px', fontSize: '14px' },\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '10px',\n\t\tfontSize: '14px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tmarginTop: '16px',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '10px 20px',\n\t\tborderRadius: '8px',\n\t\tborder: 'none',\n\t\tfontSize: '14px',\n\t\tfontWeight: 600,\n\t\tcursor: 'pointer',\n\t\talignSelf: 'flex-start',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '8px 0',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tbackground: 'none',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '4px 10px',\n\t\tfontSize: '12px',\n\t\tcursor: 'pointer',\n\t},\n};\n","import type { CourierAdminClient, ITemplateEntry } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t},\n\temits: {\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\n\t\tfunction renderRow(template: ITemplateEntry) {\n\t\t\treturn h('li', { key: `${template.type}:${template.locale ?? 'base'}`, style: styles.row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: styles.rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', template),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, template.type),\n\t\t\t\t\t\th('span', { style: styles.locale }, template.locale ?? 'base'),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t{ style: template.active ? styles.active : styles.inactive },\n\t\t\t\t\t\t\ttemplate.active ? 'Active' : 'Inactive',\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading templates…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, 'Templates'),\n\t\t\t\th('ul', { style: styles.list }, templates.value.map(renderRow)),\n\t\t\t]);\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["import_vue_courier_admin","import_vue"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/screens/TemplateEditorScreen.ts","../src/styles.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["export { TemplateEditorScreen, TemplateListScreen } from './screens';\n","import type {\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { computed, defineComponent, h, ref, watch } from 'vue';\n\nconst PREVIEW_DEBOUNCE_MS = 500;\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { saveTemplate } = useTemplates(props.client);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<string | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'Sample data must be a JSON object.';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'Sample data is not valid JSON.';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// The preview is always live: it renders once the template loads, then\n\t\t// again PREVIEW_DEBOUNCE_MS after the last edit to the content or the sample\n\t\t// data — debounced, so typing a paragraph costs one request, not one per key.\n\t\tlet previewTimer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([template, subject, html, text, sampleJson], () => {\n\t\t\tif (!template.value) return;\n\t\t\tclearTimeout(previewTimer);\n\t\t\tpreviewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\t// Saving what is already stored would only mint an identical version (the\n\t\t// server treats it as a no-op anyway), so Save waits for a real change.\n\t\tconst dirty = computed(() => {\n\t\t\tconst tpl = template.value;\n\t\t\treturn (\n\t\t\t\t!!tpl &&\n\t\t\t\t(subject.value !== (tpl.subject ?? '') ||\n\t\t\t\t\thtml.value !== (tpl.html ?? '') ||\n\t\t\t\t\ttext.value !== tpl.text ||\n\t\t\t\t\tactive.value !== tpl.active)\n\t\t\t);\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? 'unknown'} — ${new Date(rev.createdAt).toLocaleString()}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\t'Roll back',\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading template…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t`${props.locale ?? 'base'} · v${template.value?.version ?? 1}`,\n\t\t\t\t),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, 'Subject'),\n\t\t\t\t\th('input', {\n\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, 'HTML body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, 'Plain-text body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t'Active',\n\t\t\t\t\t]),\n\t\t\t\t\tsaveError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\th('div', { style: styles.saveRow }, [\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\tdisabled: isSaving.value || !dirty.value,\n\t\t\t\t\t\t\t\tstyle: dirty.value ? styles.button : styles.buttonDisabled,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tisSaving.value ? 'Saving…' : 'Save',\n\t\t\t\t\t\t),\n\t\t\t\t\t\t!dirty.value && !isSaving.value ? h('span', { style: styles.meta }, 'No changes to save') : null,\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\th('label', { style: styles.label, for: 'template-sample' }, 'Sample data'),\n\t\t\t\th('textarea', {\n\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\trows: 6,\n\t\t\t\t\tspellcheck: false,\n\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tsampleError.value\n\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, sampleError.value)\n\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\th('span', { style: styles.label }, 'Preview'),\n\t\t\t\t\t\th('span', { style: styles.meta }, isPreviewing.value ? 'Rendering…' : 'Live'),\n\t\t\t\t\t]),\n\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\ttitle: 'Template preview',\n\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t: h('p', { style: styles.meta }, 'Nothing rendered yet.'),\n\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, 'History'),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '24px' },\n\t// Two columns, always: editor left, rendered result right. Stacking the\n\t// preview under a long form hid it below the fold.\n\tsplit: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: '24px', alignItems: 'start' },\n\tcolumn: { minWidth: '0', display: 'flex', flexDirection: 'column' },\n\t// Pinned while the form scrolls, so the preview stays in view as you edit.\n\tpreviewColumn: { minWidth: '0', display: 'flex', flexDirection: 'column', position: 'sticky', top: '16px' },\n\tsaveRow: { display: 'flex', alignItems: 'center', gap: '12px', marginTop: '16px' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: { fontSize: '24px', fontWeight: 700 },\n\tsubtitle: { fontSize: '16px', fontWeight: 600, marginBottom: '8px' },\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '16px' },\n\tstatus: { padding: '24px', textAlign: 'center', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\terror: { color: 'var(--fonderie-danger,#e00)', marginBottom: '12px', fontSize: '14px' },\n\tlist: { listStyle: 'none', padding: '0', margin: '0' },\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '12px 0',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t},\n\ttype: { fontSize: '14px', fontWeight: 600, flex: '1' },\n\tlocale: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginRight: '16px' },\n\tactive: { fontSize: '12px', color: 'var(--fonderie-accent-strong,#009767)' },\n\tinactive: { fontSize: '12px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tform: { display: 'flex', flexDirection: 'column', gap: '4px' },\n\tlabel: { fontSize: '13px', fontWeight: 600, marginTop: '12px' },\n\tinput: { border: '1px solid var(--fonderie-border,#e0e0e0)', borderRadius: '8px', padding: '10px', fontSize: '14px' },\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '10px',\n\t\tfontSize: '14px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '10px 20px',\n\t\tborderRadius: '8px',\n\t\tborder: 'none',\n\t\tfontSize: '14px',\n\t\tfontWeight: 600,\n\t\tcursor: 'pointer',\n\t\talignSelf: 'flex-start',\n\t},\n\tbuttonDisabled: {\n\t\tbackgroundColor: 'var(--fonderie-border,#e0e0e0)',\n\t\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\t\tpadding: '10px 20px',\n\t\tborderRadius: '8px',\n\t\tborder: 'none',\n\t\tfontSize: '14px',\n\t\tfontWeight: 600,\n\t\tcursor: 'not-allowed',\n\t\talignSelf: 'flex-start',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '8px 0',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tbackground: 'none',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '4px 10px',\n\t\tfontSize: '12px',\n\t\tcursor: 'pointer',\n\t},\n};\n","import type { CourierAdminClient, ITemplateEntry } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t},\n\temits: {\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\n\t\tfunction renderRow(template: ITemplateEntry) {\n\t\t\treturn h('li', { key: `${template.type}:${template.locale ?? 'base'}`, style: styles.row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: styles.rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', template),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, template.type),\n\t\t\t\t\t\th('span', { style: styles.locale }, template.locale ?? 'base'),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t{ style: template.active ? styles.active : styles.inactive },\n\t\t\t\t\t\t\ttemplate.active ? 'Active' : 'Inactive',\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading templates…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, 'Templates'),\n\t\t\t\th('ul', { style: styles.list }, templates.value.map(renderRow)),\n\t\t\t]);\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["import_vue_courier_admin","import_vue"]}
|
package/dist/index.js
CHANGED
|
@@ -5,13 +5,18 @@ import {
|
|
|
5
5
|
useTemplateRevisions,
|
|
6
6
|
useTemplates
|
|
7
7
|
} from "@fonderie/vue-courier-admin";
|
|
8
|
-
import { defineComponent, h, ref, watch } from "vue";
|
|
8
|
+
import { computed, defineComponent, h, ref, watch } from "vue";
|
|
9
9
|
|
|
10
10
|
// src/styles.ts
|
|
11
11
|
var styles = {
|
|
12
|
-
container: { padding: "24px"
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
container: { padding: "24px" },
|
|
13
|
+
// Two columns, always: editor left, rendered result right. Stacking the
|
|
14
|
+
// preview under a long form hid it below the fold.
|
|
15
|
+
split: { display: "grid", gridTemplateColumns: "minmax(0, 1fr) minmax(0, 1fr)", gap: "24px", alignItems: "start" },
|
|
16
|
+
column: { minWidth: "0", display: "flex", flexDirection: "column" },
|
|
17
|
+
// Pinned while the form scrolls, so the preview stays in view as you edit.
|
|
18
|
+
previewColumn: { minWidth: "0", display: "flex", flexDirection: "column", position: "sticky", top: "16px" },
|
|
19
|
+
saveRow: { display: "flex", alignItems: "center", gap: "12px", marginTop: "16px" },
|
|
15
20
|
previewHeader: {
|
|
16
21
|
display: "flex",
|
|
17
22
|
justifyContent: "space-between",
|
|
@@ -74,7 +79,6 @@ var styles = {
|
|
|
74
79
|
fontSize: "14px"
|
|
75
80
|
},
|
|
76
81
|
button: {
|
|
77
|
-
marginTop: "16px",
|
|
78
82
|
backgroundColor: "var(--fonderie-text,#171717)",
|
|
79
83
|
color: "var(--fonderie-surface,#fff)",
|
|
80
84
|
padding: "10px 20px",
|
|
@@ -85,6 +89,17 @@ var styles = {
|
|
|
85
89
|
cursor: "pointer",
|
|
86
90
|
alignSelf: "flex-start"
|
|
87
91
|
},
|
|
92
|
+
buttonDisabled: {
|
|
93
|
+
backgroundColor: "var(--fonderie-border,#e0e0e0)",
|
|
94
|
+
color: "var(--fonderie-text-muted,#5c5c5c)",
|
|
95
|
+
padding: "10px 20px",
|
|
96
|
+
borderRadius: "8px",
|
|
97
|
+
border: "none",
|
|
98
|
+
fontSize: "14px",
|
|
99
|
+
fontWeight: 600,
|
|
100
|
+
cursor: "not-allowed",
|
|
101
|
+
alignSelf: "flex-start"
|
|
102
|
+
},
|
|
88
103
|
revisions: { marginTop: "32px" },
|
|
89
104
|
revisionRow: {
|
|
90
105
|
display: "flex",
|
|
@@ -105,6 +120,7 @@ var styles = {
|
|
|
105
120
|
};
|
|
106
121
|
|
|
107
122
|
// src/screens/TemplateEditorScreen.ts
|
|
123
|
+
var PREVIEW_DEBOUNCE_MS = 500;
|
|
108
124
|
var IMPLICIT = /* @__PURE__ */ new Set(["subject", "preheader", "brandName"]);
|
|
109
125
|
var TemplateEditorScreen = defineComponent({
|
|
110
126
|
name: "FonderieTemplateEditorScreen",
|
|
@@ -178,8 +194,15 @@ var TemplateEditorScreen = defineComponent({
|
|
|
178
194
|
);
|
|
179
195
|
}
|
|
180
196
|
}
|
|
181
|
-
|
|
182
|
-
|
|
197
|
+
let previewTimer;
|
|
198
|
+
watch([template, subject, html, text, sampleJson], () => {
|
|
199
|
+
if (!template.value) return;
|
|
200
|
+
clearTimeout(previewTimer);
|
|
201
|
+
previewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);
|
|
202
|
+
});
|
|
203
|
+
const dirty = computed(() => {
|
|
204
|
+
const tpl = template.value;
|
|
205
|
+
return !!tpl && (subject.value !== (tpl.subject ?? "") || html.value !== (tpl.html ?? "") || text.value !== tpl.text || active.value !== tpl.active);
|
|
183
206
|
});
|
|
184
207
|
async function handleSubmit(event) {
|
|
185
208
|
event.preventDefault();
|
|
@@ -267,11 +290,18 @@ var TemplateEditorScreen = defineComponent({
|
|
|
267
290
|
"Active"
|
|
268
291
|
]),
|
|
269
292
|
saveError.value ? h("p", { style: styles.error, role: "alert" }, saveError.value.explanation) : null,
|
|
270
|
-
h(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
293
|
+
h("div", { style: styles.saveRow }, [
|
|
294
|
+
h(
|
|
295
|
+
"button",
|
|
296
|
+
{
|
|
297
|
+
type: "submit",
|
|
298
|
+
disabled: isSaving.value || !dirty.value,
|
|
299
|
+
style: dirty.value ? styles.button : styles.buttonDisabled
|
|
300
|
+
},
|
|
301
|
+
isSaving.value ? "Saving\u2026" : "Save"
|
|
302
|
+
),
|
|
303
|
+
!dirty.value && !isSaving.value ? h("span", { style: styles.meta }, "No changes to save") : null
|
|
304
|
+
])
|
|
275
305
|
]),
|
|
276
306
|
h("label", { style: styles.label, for: "template-sample" }, "Sample data"),
|
|
277
307
|
h("textarea", {
|
|
@@ -286,19 +316,10 @@ var TemplateEditorScreen = defineComponent({
|
|
|
286
316
|
}),
|
|
287
317
|
sampleError.value ? h("p", { style: styles.error, role: "alert" }, sampleError.value) : null
|
|
288
318
|
]),
|
|
289
|
-
h("div", { style: styles.
|
|
319
|
+
h("div", { style: styles.previewColumn }, [
|
|
290
320
|
h("div", { style: styles.previewHeader }, [
|
|
291
321
|
h("span", { style: styles.label }, "Preview"),
|
|
292
|
-
h(
|
|
293
|
-
"button",
|
|
294
|
-
{
|
|
295
|
-
type: "button",
|
|
296
|
-
style: styles.rollbackButton,
|
|
297
|
-
disabled: isPreviewing.value,
|
|
298
|
-
onClick: () => void run()
|
|
299
|
-
},
|
|
300
|
-
isPreviewing.value ? "Rendering\u2026" : "Render"
|
|
301
|
-
)
|
|
322
|
+
h("span", { style: styles.meta }, isPreviewing.value ? "Rendering\u2026" : "Live")
|
|
302
323
|
]),
|
|
303
324
|
previewError.value ? h("p", { style: styles.error, role: "alert" }, previewError.value.explanation) : null,
|
|
304
325
|
preview.value?.subject ? h("p", { style: styles.previewSubject }, preview.value.subject) : null,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/screens/TemplateEditorScreen.ts","../src/styles.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["import type {\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h, ref, watch } from 'vue';\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { saveTemplate } = useTemplates(props.client);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<string | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'Sample data must be a JSON object.';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'Sample data is not valid JSON.';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// One render once the template has loaded, so the pane is never empty on\n\t\t// arrival. After that it is explicit — a request per keystroke is not a\n\t\t// preview, it is a load test.\n\t\twatch(template, (tpl) => {\n\t\t\tif (tpl) void run();\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? 'unknown'} — ${new Date(rev.createdAt).toLocaleString()}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\t'Roll back',\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading template…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t`${props.locale ?? 'base'} · v${template.value?.version ?? 1}`,\n\t\t\t\t),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, 'Subject'),\n\t\t\t\t\th('input', {\n\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, 'HTML body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, 'Plain-text body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t'Active',\n\t\t\t\t\t]),\n\t\t\t\t\tsaveError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\th(\n\t\t\t\t\t\t'button',\n\t\t\t\t\t\t{ type: 'submit', disabled: isSaving.value, style: styles.button },\n\t\t\t\t\t\tisSaving.value ? 'Saving…' : 'Save',\n\t\t\t\t\t),\n\t\t\t\t]),\n\t\t\t\th('label', { style: styles.label, for: 'template-sample' }, 'Sample data'),\n\t\t\t\th('textarea', {\n\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\trows: 6,\n\t\t\t\t\tspellcheck: false,\n\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tsampleError.value\n\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, sampleError.value)\n\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\th('span', { style: styles.label }, 'Preview'),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\tstyle: styles.rollbackButton,\n\t\t\t\t\t\t\t\tdisabled: isPreviewing.value,\n\t\t\t\t\t\t\t\tonClick: () => void run(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tisPreviewing.value ? 'Rendering…' : 'Render',\n\t\t\t\t\t\t),\n\t\t\t\t\t]),\n\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\ttitle: 'Template preview',\n\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t: h('p', { style: styles.meta }, 'Nothing rendered yet.'),\n\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, 'History'),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '24px', maxWidth: '1180px' },\n\tsplit: { display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' },\n\tcolumn: { flex: '1 1 460px', minWidth: '320px', display: 'flex', flexDirection: 'column' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: { fontSize: '24px', fontWeight: 700 },\n\tsubtitle: { fontSize: '16px', fontWeight: 600, marginBottom: '8px' },\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '16px' },\n\tstatus: { padding: '24px', textAlign: 'center', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\terror: { color: 'var(--fonderie-danger,#e00)', marginBottom: '12px', fontSize: '14px' },\n\tlist: { listStyle: 'none', padding: '0', margin: '0' },\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '12px 0',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t},\n\ttype: { fontSize: '14px', fontWeight: 600, flex: '1' },\n\tlocale: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginRight: '16px' },\n\tactive: { fontSize: '12px', color: 'var(--fonderie-accent-strong,#009767)' },\n\tinactive: { fontSize: '12px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tform: { display: 'flex', flexDirection: 'column', gap: '4px' },\n\tlabel: { fontSize: '13px', fontWeight: 600, marginTop: '12px' },\n\tinput: { border: '1px solid var(--fonderie-border,#e0e0e0)', borderRadius: '8px', padding: '10px', fontSize: '14px' },\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '10px',\n\t\tfontSize: '14px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tmarginTop: '16px',\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '10px 20px',\n\t\tborderRadius: '8px',\n\t\tborder: 'none',\n\t\tfontSize: '14px',\n\t\tfontWeight: 600,\n\t\tcursor: 'pointer',\n\t\talignSelf: 'flex-start',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '8px 0',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tbackground: 'none',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '4px 10px',\n\t\tfontSize: '12px',\n\t\tcursor: 'pointer',\n\t},\n};\n","import type { CourierAdminClient, ITemplateEntry } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t},\n\temits: {\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\n\t\tfunction renderRow(template: ITemplateEntry) {\n\t\t\treturn h('li', { key: `${template.type}:${template.locale ?? 'base'}`, style: styles.row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: styles.rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', template),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, template.type),\n\t\t\t\t\t\th('span', { style: styles.locale }, template.locale ?? 'base'),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t{ style: template.active ? styles.active : styles.inactive },\n\t\t\t\t\t\t\ttemplate.active ? 'Active' : 'Inactive',\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading templates…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, 'Templates'),\n\t\t\t\th('ul', { style: styles.list }, templates.value.map(renderRow)),\n\t\t\t]);\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["useTemplates","defineComponent","h","defineComponent","useTemplates","h"]}
|
|
1
|
+
{"version":3,"sources":["../src/screens/TemplateEditorScreen.ts","../src/styles.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["import type {\n\tCourierAdminClient,\n\tFonderieApiError,\n\tISetTemplateInput,\n\tITemplateRevision,\n} from '@fonderie/client';\nimport {\n\tuseTemplate,\n\tuseTemplatePreview,\n\tuseTemplateRevisions,\n\tuseTemplates,\n} from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { computed, defineComponent, h, ref, watch } from 'vue';\n\nconst PREVIEW_DEBOUNCE_MS = 500;\nimport { styles } from '../styles';\n\n// Implicit variables the layout injects — an operator never supplies these, so\n// offering them as fields would just be noise.\nconst IMPLICIT = new Set(['subject', 'preheader', 'brandName']);\n\nexport const TemplateEditorScreen = defineComponent({\n\tname: 'FonderieTemplateEditorScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t\ttype: { type: String, required: true },\n\t\tlocale: { type: String as PropType<string | null>, default: null },\n\t},\n\temits: {\n\t\tsaved: () => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { template, isLoading, error, refresh } = useTemplate(\n\t\t\tprops.client,\n\t\t\tprops.type,\n\t\t\tprops.locale,\n\t\t);\n\t\t// Saves go through the list composable (which re-fetches the template list\n\t\t// after each write); mounting it adds a template-list fetch to this\n\t\t// single-template editor — acceptable for an admin dashboard. Its\n\t\t// isLoading/error track that list fetch, so the save action keeps local state.\n\t\tconst { saveTemplate } = useTemplates(props.client);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\n\t\tconst isSaving = ref(false);\n\t\tconst saveError = ref<FonderieApiError | null>(null);\n\n\t\tconst subject = ref('');\n\t\tconst html = ref('');\n\t\tconst text = ref('');\n\t\tconst active = ref(true);\n\n\t\twatch(template, (tpl) => {\n\t\t\tif (!tpl) return;\n\t\t\tsubject.value = tpl.subject ?? '';\n\t\t\thtml.value = tpl.html ?? '';\n\t\t\ttext.value = tpl.text;\n\t\t\tactive.value = tpl.active;\n\t\t});\n\n\t\tconst {\n\t\t\tpreview,\n\t\t\tisPreviewing,\n\t\t\terror: previewError,\n\t\t\trenderPreview,\n\t\t} = useTemplatePreview(props.client);\n\t\t// Sample values as JSON text rather than an object, so a half-typed value\n\t\t// does not have to parse on every keystroke.\n\t\tconst sampleJson = ref('{}');\n\t\tconst sampleError = ref<string | null>(null);\n\n\t\tasync function run() {\n\t\t\tlet data: Record<string, unknown> = {};\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(sampleJson.value || '{}');\n\t\t\t\tif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\t\t\tsampleError.value = 'Sample data must be a JSON object.';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdata = parsed as Record<string, unknown>;\n\t\t\t\tsampleError.value = null;\n\t\t\t} catch {\n\t\t\t\tsampleError.value = 'Sample data is not valid JSON.';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await renderPreview(\n\t\t\t\tprops.type,\n\t\t\t\t{\n\t\t\t\t\ttext: text.value,\n\t\t\t\t\tdata,\n\t\t\t\t\t...(subject.value ? { subject: subject.value } : {}),\n\t\t\t\t\t...(html.value ? { html: html.value } : {}),\n\t\t\t\t},\n\t\t\t\tprops.locale,\n\t\t\t);\n\t\t\t// The server reports which variables this content uses; seed the ones\n\t\t\t// with no value yet with their own name so the render shows where each\n\t\t\t// lands. Never overwrite something already typed.\n\t\t\tconst missing = result.variables.filter((v) => !IMPLICIT.has(v) && !(v in data));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tsampleJson.value = JSON.stringify(\n\t\t\t\t\t{ ...data, ...Object.fromEntries(missing.map((v) => [v, v])) },\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// The preview is always live: it renders once the template loads, then\n\t\t// again PREVIEW_DEBOUNCE_MS after the last edit to the content or the sample\n\t\t// data — debounced, so typing a paragraph costs one request, not one per key.\n\t\tlet previewTimer: ReturnType<typeof setTimeout> | undefined;\n\t\twatch([template, subject, html, text, sampleJson], () => {\n\t\t\tif (!template.value) return;\n\t\t\tclearTimeout(previewTimer);\n\t\t\tpreviewTimer = setTimeout(() => void run(), PREVIEW_DEBOUNCE_MS);\n\t\t});\n\n\t\t// Saving what is already stored would only mint an identical version (the\n\t\t// server treats it as a no-op anyway), so Save waits for a real change.\n\t\tconst dirty = computed(() => {\n\t\t\tconst tpl = template.value;\n\t\t\treturn (\n\t\t\t\t!!tpl &&\n\t\t\t\t(subject.value !== (tpl.subject ?? '') ||\n\t\t\t\t\thtml.value !== (tpl.html ?? '') ||\n\t\t\t\t\ttext.value !== tpl.text ||\n\t\t\t\t\tactive.value !== tpl.active)\n\t\t\t);\n\t\t});\n\n\t\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\n\t\t\tisSaving.value = true;\n\t\t\tsaveError.value = null;\n\t\t\ttry {\n\t\t\t\tconst input: ISetTemplateInput = { text: text.value, active: active.value };\n\t\t\t\tif (subject.value) input.subject = subject.value;\n\t\t\t\tif (html.value) input.html = html.value;\n\t\t\t\tif (template.value?.version !== undefined) input.ifVersion = template.value.version;\n\t\t\t\tawait saveTemplate(props.type, input, props.locale);\n\t\t\t\t// The list composable refreshes its own list; this screen renders the\n\t\t\t\t// single template, so re-read it too.\n\t\t\t\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch (err) {\n\t\t\t\t// useTemplates normalizes every failure to FonderieApiError before throwing.\n\t\t\t\tsaveError.value = err as FonderieApiError;\n\t\t\t} finally {\n\t\t\t\tisSaving.value = false;\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRevision(rev: ITemplateRevision) {\n\t\t\treturn h('li', { key: rev.version, style: styles.revisionRow }, [\n\t\t\t\th(\n\t\t\t\t\t'span',\n\t\t\t\t\t`v${rev.version} — ${rev.actor ?? 'unknown'} — ${new Date(rev.createdAt).toLocaleString()}`,\n\t\t\t\t),\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{ type: 'button', style: styles.rollbackButton, onClick: () => rollback(rev.version) },\n\t\t\t\t\t'Roll back',\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading template…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, props.type),\n\t\t\t\th(\n\t\t\t\t\t'p',\n\t\t\t\t\t{ style: styles.meta },\n\t\t\t\t\t`${props.locale ?? 'base'} · v${template.value?.version ?? 1}`,\n\t\t\t\t),\n\t\t\t\th('div', { style: styles.split }, [\n\t\t\t\th('div', { style: styles.column }, [\n\t\t\t\th('form', { style: styles.form, onSubmit: handleSubmit }, [\n\t\t\t\t\th('label', { style: styles.label, for: 'template-subject' }, 'Subject'),\n\t\t\t\t\th('input', {\n\t\t\t\t\t\tid: 'template-subject',\n\t\t\t\t\t\tstyle: styles.input,\n\t\t\t\t\t\tvalue: subject.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\tsubject.value = (e.target as HTMLInputElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-html' }, 'HTML body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-html',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 8,\n\t\t\t\t\t\tvalue: html.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\thtml.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.label, for: 'template-text' }, 'Plain-text body'),\n\t\t\t\t\th('textarea', {\n\t\t\t\t\t\tid: 'template-text',\n\t\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\t\trows: 4,\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tvalue: text.value,\n\t\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\t\ttext.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\th('label', { style: styles.checkboxLabel }, [\n\t\t\t\t\t\th('input', {\n\t\t\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\t\t\tchecked: active.value,\n\t\t\t\t\t\t\tonChange: (e: Event) => {\n\t\t\t\t\t\t\t\tactive.value = (e.target as HTMLInputElement).checked;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t'Active',\n\t\t\t\t\t]),\n\t\t\t\t\tsaveError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, saveError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\th('div', { style: styles.saveRow }, [\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'button',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'submit',\n\t\t\t\t\t\t\t\tdisabled: isSaving.value || !dirty.value,\n\t\t\t\t\t\t\t\tstyle: dirty.value ? styles.button : styles.buttonDisabled,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tisSaving.value ? 'Saving…' : 'Save',\n\t\t\t\t\t\t),\n\t\t\t\t\t\t!dirty.value && !isSaving.value ? h('span', { style: styles.meta }, 'No changes to save') : null,\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\th('label', { style: styles.label, for: 'template-sample' }, 'Sample data'),\n\t\t\t\th('textarea', {\n\t\t\t\t\tid: 'template-sample',\n\t\t\t\t\tstyle: styles.textarea,\n\t\t\t\t\trows: 6,\n\t\t\t\t\tspellcheck: false,\n\t\t\t\t\tvalue: sampleJson.value,\n\t\t\t\t\tonInput: (e: Event) => {\n\t\t\t\t\t\tsampleJson.value = (e.target as HTMLTextAreaElement).value;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tsampleError.value\n\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, sampleError.value)\n\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t\th('div', { style: styles.previewColumn }, [\n\t\t\t\t\th('div', { style: styles.previewHeader }, [\n\t\t\t\t\t\th('span', { style: styles.label }, 'Preview'),\n\t\t\t\t\t\th('span', { style: styles.meta }, isPreviewing.value ? 'Rendering…' : 'Live'),\n\t\t\t\t\t]),\n\t\t\t\t\tpreviewError.value\n\t\t\t\t\t\t? h('p', { style: styles.error, role: 'alert' }, previewError.value.explanation)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.subject\n\t\t\t\t\t\t? h('p', { style: styles.previewSubject }, preview.value.subject)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpreview.value?.html\n\t\t\t\t\t\t? // sandbox= — no scripts, no same-origin. Operator-authored HTML\n\t\t\t\t\t\t\t// must never execute in the dashboard's origin, where the admin\n\t\t\t\t\t\t\t// token lives.\n\t\t\t\t\t\t\th('iframe', {\n\t\t\t\t\t\t\t\ttitle: 'Template preview',\n\t\t\t\t\t\t\t\tstyle: styles.previewFrame,\n\t\t\t\t\t\t\t\tsandbox: '',\n\t\t\t\t\t\t\t\tsrcdoc: preview.value.html,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: preview.value\n\t\t\t\t\t\t\t? h('pre', { style: styles.previewText }, preview.value.text)\n\t\t\t\t\t\t\t: h('p', { style: styles.meta }, 'Nothing rendered yet.'),\n\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t\trevisions.value.length > 0\n\t\t\t\t\t? h('div', { style: styles.revisions }, [\n\t\t\t\t\t\t\th('h2', { style: styles.subtitle }, 'History'),\n\t\t\t\t\t\t\th('ul', { style: styles.list }, revisions.value.map(renderRevision)),\n\t\t\t\t\t\t])\n\t\t\t\t\t: null,\n\t\t\t]);\n\t\t};\n\t},\n});\n","import type { CSSProperties } from 'vue';\n\nexport const styles: Record<string, CSSProperties> = {\n\tcontainer: { padding: '24px' },\n\t// Two columns, always: editor left, rendered result right. Stacking the\n\t// preview under a long form hid it below the fold.\n\tsplit: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: '24px', alignItems: 'start' },\n\tcolumn: { minWidth: '0', display: 'flex', flexDirection: 'column' },\n\t// Pinned while the form scrolls, so the preview stays in view as you edit.\n\tpreviewColumn: { minWidth: '0', display: 'flex', flexDirection: 'column', position: 'sticky', top: '16px' },\n\tsaveRow: { display: 'flex', alignItems: 'center', gap: '12px', marginTop: '16px' },\n\tpreviewHeader: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tmarginTop: '12px',\n\t},\n\tpreviewSubject: { fontSize: '14px', fontWeight: '600', margin: '8px 0' },\n\tpreviewFrame: {\n\t\twidth: '100%',\n\t\theight: '520px',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tbackground: 'var(--fonderie-surface,#fff)',\n\t},\n\tpreviewText: {\n\t\twhiteSpace: 'pre-wrap',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '12px',\n\t\tfontSize: '13px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\ttitle: { fontSize: '24px', fontWeight: 700 },\n\tsubtitle: { fontSize: '16px', fontWeight: 600, marginBottom: '8px' },\n\tmeta: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginBottom: '16px' },\n\tstatus: { padding: '24px', textAlign: 'center', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\terror: { color: 'var(--fonderie-danger,#e00)', marginBottom: '12px', fontSize: '14px' },\n\tlist: { listStyle: 'none', padding: '0', margin: '0' },\n\trow: { borderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)' },\n\trowButton: {\n\t\twidth: '100%',\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '12px 0',\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\ttextAlign: 'left',\n\t},\n\ttype: { fontSize: '14px', fontWeight: 600, flex: '1' },\n\tlocale: { fontSize: '13px', color: 'var(--fonderie-text-muted,#5c5c5c)', marginRight: '16px' },\n\tactive: { fontSize: '12px', color: 'var(--fonderie-accent-strong,#009767)' },\n\tinactive: { fontSize: '12px', color: 'var(--fonderie-text-muted,#5c5c5c)' },\n\tform: { display: 'flex', flexDirection: 'column', gap: '4px' },\n\tlabel: { fontSize: '13px', fontWeight: 600, marginTop: '12px' },\n\tinput: { border: '1px solid var(--fonderie-border,#e0e0e0)', borderRadius: '8px', padding: '10px', fontSize: '14px' },\n\ttextarea: {\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '10px',\n\t\tfontSize: '14px',\n\t\tfontFamily: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace)',\n\t},\n\tcheckboxLabel: {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tgap: '8px',\n\t\tmarginTop: '12px',\n\t\tfontSize: '14px',\n\t},\n\tbutton: {\n\t\tbackgroundColor: 'var(--fonderie-text,#171717)',\n\t\tcolor: 'var(--fonderie-surface,#fff)',\n\t\tpadding: '10px 20px',\n\t\tborderRadius: '8px',\n\t\tborder: 'none',\n\t\tfontSize: '14px',\n\t\tfontWeight: 600,\n\t\tcursor: 'pointer',\n\t\talignSelf: 'flex-start',\n\t},\n\tbuttonDisabled: {\n\t\tbackgroundColor: 'var(--fonderie-border,#e0e0e0)',\n\t\tcolor: 'var(--fonderie-text-muted,#5c5c5c)',\n\t\tpadding: '10px 20px',\n\t\tborderRadius: '8px',\n\t\tborder: 'none',\n\t\tfontSize: '14px',\n\t\tfontWeight: 600,\n\t\tcursor: 'not-allowed',\n\t\talignSelf: 'flex-start',\n\t},\n\trevisions: { marginTop: '32px' },\n\trevisionRow: {\n\t\tdisplay: 'flex',\n\t\tjustifyContent: 'space-between',\n\t\talignItems: 'center',\n\t\tpadding: '8px 0',\n\t\tborderBottom: '1px solid var(--fonderie-border-light,#f5f5f5)',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tbackground: 'none',\n\t\tborder: '1px solid var(--fonderie-border,#e0e0e0)',\n\t\tborderRadius: '8px',\n\t\tpadding: '4px 10px',\n\t\tfontSize: '12px',\n\t\tcursor: 'pointer',\n\t},\n};\n","import type { CourierAdminClient, ITemplateEntry } from '@fonderie/client';\nimport { useTemplates } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\nimport { styles } from '../styles';\n\nexport const TemplateListScreen = defineComponent({\n\tname: 'FonderieTemplateListScreen',\n\tprops: {\n\t\tclient: { type: Object as PropType<CourierAdminClient>, required: true },\n\t},\n\temits: {\n\t\t'select-template': (_template: ITemplateEntry) => true,\n\t},\n\tsetup(props, { emit }) {\n\t\tconst { templates, isLoading, error } = useTemplates(props.client);\n\n\t\tfunction renderRow(template: ITemplateEntry) {\n\t\t\treturn h('li', { key: `${template.type}:${template.locale ?? 'base'}`, style: styles.row }, [\n\t\t\t\th(\n\t\t\t\t\t'button',\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tstyle: styles.rowButton,\n\t\t\t\t\t\tonClick: () => emit('select-template', template),\n\t\t\t\t\t},\n\t\t\t\t\t[\n\t\t\t\t\t\th('span', { style: styles.type }, template.type),\n\t\t\t\t\t\th('span', { style: styles.locale }, template.locale ?? 'base'),\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\t'span',\n\t\t\t\t\t\t\t{ style: template.active ? styles.active : styles.inactive },\n\t\t\t\t\t\t\ttemplate.active ? 'Active' : 'Inactive',\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t]);\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (isLoading.value) return h('p', { style: styles.status }, 'Loading templates…');\n\t\t\tif (error.value)\n\t\t\t\treturn h('p', { style: styles.error, role: 'alert' }, error.value.explanation);\n\n\t\t\treturn h('div', { style: styles.container }, [\n\t\t\t\th('h1', { style: styles.title }, 'Templates'),\n\t\t\t\th('ul', { style: styles.list }, templates.value.map(renderRow)),\n\t\t\t]);\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["useTemplates","defineComponent","h","defineComponent","useTemplates","h"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonderie/vue-courier-admin-screens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Pre-built Vue screens for the Fonderie courier admin API — template list, template editor with revision history and rollback.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fonderiejs",
|