@fonderie/vue-courier-admin-screens 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fonderie, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @fonderie/vue-courier-admin-screens
2
+
3
+ Pre-built Vue 3 screens for the Fonderie courier admin API —
4
+ `TemplateListScreen` and `TemplateEditorScreen` — built on
5
+ [`@fonderie/vue-courier-admin`](https://github.com/fonderie-js/sdk/tree/main/packages/vue-courier-admin)
6
+ composables. Plain HTML elements via Vue's `h()` render function, inline
7
+ styles you can override, zero UI library dependency.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm install @fonderie/vue-courier-admin-screens
13
+ ```
14
+
15
+ ## Use
16
+
17
+ ```vue
18
+ <script setup>
19
+ import { CourierAdminClient } from '@fonderie/client';
20
+ import { TemplateListScreen, TemplateEditorScreen } from '@fonderie/vue-courier-admin-screens';
21
+
22
+ const admin = new CourierAdminClient({
23
+ baseUrl: 'https://api.example.com/v1',
24
+ adminToken: import.meta.env.VITE_FONDERIE_ADMIN_TOKEN,
25
+ });
26
+ </script>
27
+
28
+ <template>
29
+ <TemplateListScreen :client="admin" @select-template="(t) => (route = `edit/${t.type}`)" />
30
+ <TemplateEditorScreen :client="admin" type="password-reset" @saved="route = 'list'" />
31
+ </template>
32
+ ```
33
+
34
+ `TemplateListScreen` lists every template with its locale and active state.
35
+ `TemplateEditorScreen` is a subject/HTML/plain-text form with a revision
36
+ history and one-click rollback, using the loaded template's version as
37
+ optimistic-concurrency `ifVersion` on save. Need just the state management
38
+ without the markup? Use `@fonderie/vue-courier-admin`'s composables
39
+ directly.
40
+
41
+ ## Why this exists
42
+
43
+ You've shipped this plumbing before — auth, teams, billing, messaging —
44
+ and the next project will ask for it again. Fonderie packages it once:
45
+ plain TypeScript modules for
46
+ [`@fonderie/core`](https://github.com/fonderie-js/sdk/tree/main/packages/core),
47
+ PostgreSQL-backed, self-hosted, MIT. No external control plane, no
48
+ per-seat anything. Register the modules you need; skip the ones you don't.
49
+
50
+ **This package owns** pre-built Vue admin UI for courier's templates, so
51
+ you don't have to build a template editor from scratch. Swap it for your own
52
+ design system whenever you outgrow it — `@fonderie/vue-courier-admin`'s
53
+ composables work standalone.
54
+
55
+ Browse the whole set at
56
+ [fonderie-js/sdk](https://github.com/fonderie-js/sdk) · follow
57
+ [@fonderiejs](https://x.com/fonderiejs)
58
+
59
+ ## License
60
+
61
+ MIT © Fonderie, Inc.
package/dist/index.cjs ADDED
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ TemplateEditorScreen: () => TemplateEditorScreen,
24
+ TemplateListScreen: () => TemplateListScreen
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/screens/TemplateEditorScreen.ts
29
+ var import_vue_courier_admin = require("@fonderie/vue-courier-admin");
30
+ var import_vue = require("vue");
31
+
32
+ // src/styles.ts
33
+ var styles = {
34
+ container: { padding: "24px", maxWidth: "640px" },
35
+ title: { fontSize: "24px", fontWeight: 700 },
36
+ subtitle: { fontSize: "16px", fontWeight: 600, marginBottom: "8px" },
37
+ meta: { fontSize: "13px", color: "#666", marginBottom: "16px" },
38
+ status: { padding: "24px", textAlign: "center", color: "#666" },
39
+ error: { color: "#e11d48", marginBottom: "12px", fontSize: "14px" },
40
+ list: { listStyle: "none", padding: "0", margin: "0" },
41
+ row: { borderBottom: "1px solid #eee" },
42
+ rowButton: {
43
+ width: "100%",
44
+ display: "flex",
45
+ justifyContent: "space-between",
46
+ alignItems: "center",
47
+ padding: "12px 0",
48
+ background: "none",
49
+ border: "none",
50
+ cursor: "pointer",
51
+ textAlign: "left"
52
+ },
53
+ type: { fontSize: "14px", fontWeight: 600, flex: "1" },
54
+ locale: { fontSize: "13px", color: "#666", marginRight: "16px" },
55
+ active: { fontSize: "12px", color: "#16a34a" },
56
+ inactive: { fontSize: "12px", color: "#999" },
57
+ form: { display: "flex", flexDirection: "column", gap: "4px" },
58
+ label: { fontSize: "13px", fontWeight: 600, marginTop: "12px" },
59
+ input: { border: "1px solid #ddd", borderRadius: "8px", padding: "10px", fontSize: "14px" },
60
+ textarea: {
61
+ border: "1px solid #ddd",
62
+ borderRadius: "8px",
63
+ padding: "10px",
64
+ fontSize: "14px",
65
+ fontFamily: "monospace"
66
+ },
67
+ checkboxLabel: {
68
+ display: "flex",
69
+ alignItems: "center",
70
+ gap: "8px",
71
+ marginTop: "12px",
72
+ fontSize: "14px"
73
+ },
74
+ button: {
75
+ marginTop: "16px",
76
+ backgroundColor: "#000",
77
+ color: "#fff",
78
+ padding: "10px 20px",
79
+ borderRadius: "8px",
80
+ border: "none",
81
+ fontSize: "14px",
82
+ fontWeight: 600,
83
+ cursor: "pointer",
84
+ alignSelf: "flex-start"
85
+ },
86
+ revisions: { marginTop: "32px" },
87
+ revisionRow: {
88
+ display: "flex",
89
+ justifyContent: "space-between",
90
+ alignItems: "center",
91
+ padding: "8px 0",
92
+ borderBottom: "1px solid #eee",
93
+ fontSize: "13px"
94
+ },
95
+ rollbackButton: {
96
+ background: "none",
97
+ border: "1px solid #ddd",
98
+ borderRadius: "8px",
99
+ padding: "4px 10px",
100
+ fontSize: "12px",
101
+ cursor: "pointer"
102
+ }
103
+ };
104
+
105
+ // src/screens/TemplateEditorScreen.ts
106
+ var TemplateEditorScreen = (0, import_vue.defineComponent)({
107
+ name: "FonderieTemplateEditorScreen",
108
+ props: {
109
+ client: { type: Object, required: true },
110
+ type: { type: String, required: true },
111
+ locale: { type: String, default: null }
112
+ },
113
+ emits: {
114
+ saved: () => true
115
+ },
116
+ setup(props, { emit }) {
117
+ const { template, isLoading, error, refresh } = (0, import_vue_courier_admin.useTemplate)(
118
+ props.client,
119
+ props.type,
120
+ props.locale
121
+ );
122
+ const { saveTemplate, isLoading: isSaving, error: saveError } = (0, import_vue_courier_admin.useSaveTemplate)(props.client);
123
+ const { revisions, rollback } = (0, import_vue_courier_admin.useTemplateRevisions)(props.client, props.type, props.locale);
124
+ const subject = (0, import_vue.ref)("");
125
+ const html = (0, import_vue.ref)("");
126
+ const text = (0, import_vue.ref)("");
127
+ const active = (0, import_vue.ref)(true);
128
+ (0, import_vue.watch)(template, (tpl) => {
129
+ if (!tpl) return;
130
+ subject.value = tpl.subject ?? "";
131
+ html.value = tpl.html ?? "";
132
+ text.value = tpl.text;
133
+ active.value = tpl.active;
134
+ });
135
+ async function handleSubmit(event) {
136
+ event.preventDefault();
137
+ try {
138
+ const input = { text: text.value, active: active.value };
139
+ if (subject.value) input.subject = subject.value;
140
+ if (html.value) input.html = html.value;
141
+ if (template.value?.version !== void 0) input.ifVersion = template.value.version;
142
+ await saveTemplate(props.type, input, props.locale);
143
+ await refresh();
144
+ emit("saved");
145
+ } catch {
146
+ }
147
+ }
148
+ function renderRevision(rev) {
149
+ return (0, import_vue.h)("li", { key: rev.version, style: styles.revisionRow }, [
150
+ (0, import_vue.h)(
151
+ "span",
152
+ `v${rev.version} \u2014 ${rev.actor ?? "unknown"} \u2014 ${new Date(rev.createdAt).toLocaleString()}`
153
+ ),
154
+ (0, import_vue.h)(
155
+ "button",
156
+ { type: "button", style: styles.rollbackButton, onClick: () => rollback(rev.version) },
157
+ "Roll back"
158
+ )
159
+ ]);
160
+ }
161
+ return () => {
162
+ if (isLoading.value) return (0, import_vue.h)("p", { style: styles.status }, "Loading template\u2026");
163
+ if (error.value)
164
+ return (0, import_vue.h)("p", { style: styles.error, role: "alert" }, error.value.explanation);
165
+ return (0, import_vue.h)("div", { style: styles.container }, [
166
+ (0, import_vue.h)("h1", { style: styles.title }, props.type),
167
+ (0, import_vue.h)(
168
+ "p",
169
+ { style: styles.meta },
170
+ `${props.locale ?? "base"} \xB7 v${template.value?.version ?? 1}`
171
+ ),
172
+ (0, import_vue.h)("form", { style: styles.form, onSubmit: handleSubmit }, [
173
+ (0, import_vue.h)("label", { style: styles.label, for: "template-subject" }, "Subject"),
174
+ (0, import_vue.h)("input", {
175
+ id: "template-subject",
176
+ style: styles.input,
177
+ value: subject.value,
178
+ onInput: (e) => {
179
+ subject.value = e.target.value;
180
+ }
181
+ }),
182
+ (0, import_vue.h)("label", { style: styles.label, for: "template-html" }, "HTML body"),
183
+ (0, import_vue.h)("textarea", {
184
+ id: "template-html",
185
+ style: styles.textarea,
186
+ rows: 8,
187
+ value: html.value,
188
+ onInput: (e) => {
189
+ html.value = e.target.value;
190
+ }
191
+ }),
192
+ (0, import_vue.h)("label", { style: styles.label, for: "template-text" }, "Plain-text body"),
193
+ (0, import_vue.h)("textarea", {
194
+ id: "template-text",
195
+ style: styles.textarea,
196
+ rows: 4,
197
+ required: true,
198
+ value: text.value,
199
+ onInput: (e) => {
200
+ text.value = e.target.value;
201
+ }
202
+ }),
203
+ (0, import_vue.h)("label", { style: styles.checkboxLabel }, [
204
+ (0, import_vue.h)("input", {
205
+ type: "checkbox",
206
+ checked: active.value,
207
+ onChange: (e) => {
208
+ active.value = e.target.checked;
209
+ }
210
+ }),
211
+ "Active"
212
+ ]),
213
+ saveError.value ? (0, import_vue.h)("p", { style: styles.error, role: "alert" }, saveError.value.explanation) : null,
214
+ (0, import_vue.h)(
215
+ "button",
216
+ { type: "submit", disabled: isSaving.value, style: styles.button },
217
+ isSaving.value ? "Saving\u2026" : "Save"
218
+ )
219
+ ]),
220
+ revisions.value.length > 0 ? (0, import_vue.h)("div", { style: styles.revisions }, [
221
+ (0, import_vue.h)("h2", { style: styles.subtitle }, "History"),
222
+ (0, import_vue.h)("ul", { style: styles.list }, revisions.value.map(renderRevision))
223
+ ]) : null
224
+ ]);
225
+ };
226
+ }
227
+ });
228
+
229
+ // src/screens/TemplateListScreen.ts
230
+ var import_vue_courier_admin2 = require("@fonderie/vue-courier-admin");
231
+ var import_vue2 = require("vue");
232
+ var TemplateListScreen = (0, import_vue2.defineComponent)({
233
+ name: "FonderieTemplateListScreen",
234
+ props: {
235
+ client: { type: Object, required: true }
236
+ },
237
+ emits: {
238
+ "select-template": (_template) => true
239
+ },
240
+ setup(props, { emit }) {
241
+ const { templates, isLoading, error } = (0, import_vue_courier_admin2.useTemplates)(props.client);
242
+ function renderRow(template) {
243
+ return (0, import_vue2.h)("li", { key: `${template.type}:${template.locale ?? "base"}`, style: styles.row }, [
244
+ (0, import_vue2.h)(
245
+ "button",
246
+ {
247
+ type: "button",
248
+ style: styles.rowButton,
249
+ onClick: () => emit("select-template", template)
250
+ },
251
+ [
252
+ (0, import_vue2.h)("span", { style: styles.type }, template.type),
253
+ (0, import_vue2.h)("span", { style: styles.locale }, template.locale ?? "base"),
254
+ (0, import_vue2.h)(
255
+ "span",
256
+ { style: template.active ? styles.active : styles.inactive },
257
+ template.active ? "Active" : "Inactive"
258
+ )
259
+ ]
260
+ )
261
+ ]);
262
+ }
263
+ return () => {
264
+ if (isLoading.value) return (0, import_vue2.h)("p", { style: styles.status }, "Loading templates\u2026");
265
+ if (error.value)
266
+ return (0, import_vue2.h)("p", { style: styles.error, role: "alert" }, error.value.explanation);
267
+ return (0, import_vue2.h)("div", { style: styles.container }, [
268
+ (0, import_vue2.h)("h1", { style: styles.title }, "Templates"),
269
+ (0, import_vue2.h)("ul", { style: styles.list }, templates.value.map(renderRow))
270
+ ]);
271
+ };
272
+ }
273
+ });
274
+ // Annotate the CommonJS export names for ESM import in node:
275
+ 0 && (module.exports = {
276
+ TemplateEditorScreen,
277
+ TemplateListScreen
278
+ });
279
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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 { CourierAdminClient, ISetTemplateInput, ITemplateRevision } from '@fonderie/client';\nimport { useSaveTemplate, useTemplate, useTemplateRevisions } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h, ref, watch } from 'vue';\nimport { styles } from '../styles';\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\tconst { saveTemplate, isLoading: isSaving, error: saveError } = useSaveTemplate(props.client);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\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\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\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\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch {\n\t\t\t\t// Surfaced via saveError.\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('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\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: '640px' },\n\ttitle: { fontSize: '24px', fontWeight: 700 },\n\tsubtitle: { fontSize: '16px', fontWeight: 600, marginBottom: '8px' },\n\tmeta: { fontSize: '13px', color: '#666', marginBottom: '16px' },\n\tstatus: { padding: '24px', textAlign: 'center', color: '#666' },\n\terror: { color: '#e11d48', marginBottom: '12px', fontSize: '14px' },\n\tlist: { listStyle: 'none', padding: '0', margin: '0' },\n\trow: { borderBottom: '1px solid #eee' },\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: '#666', marginRight: '16px' },\n\tactive: { fontSize: '12px', color: '#16a34a' },\n\tinactive: { fontSize: '12px', color: '#999' },\n\tform: { display: 'flex', flexDirection: 'column', gap: '4px' },\n\tlabel: { fontSize: '13px', fontWeight: 600, marginTop: '12px' },\n\tinput: { border: '1px solid #ddd', borderRadius: '8px', padding: '10px', fontSize: '14px' },\n\ttextarea: {\n\t\tborder: '1px solid #ddd',\n\t\tborderRadius: '8px',\n\t\tpadding: '10px',\n\t\tfontSize: '14px',\n\t\tfontFamily: '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: '#000',\n\t\tcolor: '#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 #eee',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tbackground: 'none',\n\t\tborder: '1px solid #ddd',\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,+BAAmE;AAEnE,iBAA+C;;;ACDxC,IAAM,SAAwC;AAAA,EACpD,WAAW,EAAE,SAAS,QAAQ,UAAU,QAAQ;AAAA,EAChD,OAAO,EAAE,UAAU,QAAQ,YAAY,IAAI;AAAA,EAC3C,UAAU,EAAE,UAAU,QAAQ,YAAY,KAAK,cAAc,MAAM;AAAA,EACnE,MAAM,EAAE,UAAU,QAAQ,OAAO,QAAQ,cAAc,OAAO;AAAA,EAC9D,QAAQ,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,OAAO;AAAA,EAC9D,OAAO,EAAE,OAAO,WAAW,cAAc,QAAQ,UAAU,OAAO;AAAA,EAClE,MAAM,EAAE,WAAW,QAAQ,SAAS,KAAK,QAAQ,IAAI;AAAA,EACrD,KAAK,EAAE,cAAc,iBAAiB;AAAA,EACtC,WAAW;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,EACZ;AAAA,EACA,MAAM,EAAE,UAAU,QAAQ,YAAY,KAAK,MAAM,IAAI;AAAA,EACrD,QAAQ,EAAE,UAAU,QAAQ,OAAO,QAAQ,aAAa,OAAO;AAAA,EAC/D,QAAQ,EAAE,UAAU,QAAQ,OAAO,UAAU;AAAA,EAC7C,UAAU,EAAE,UAAU,QAAQ,OAAO,OAAO;AAAA,EAC5C,MAAM,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,MAAM;AAAA,EAC7D,OAAO,EAAE,UAAU,QAAQ,YAAY,KAAK,WAAW,OAAO;AAAA,EAC9D,OAAO,EAAE,QAAQ,kBAAkB,cAAc,OAAO,SAAS,QAAQ,UAAU,OAAO;AAAA,EAC1F,UAAU;AAAA,IACT,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACd,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,WAAW;AAAA,IACX,UAAU;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACP,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,EACZ;AAAA,EACA,WAAW,EAAE,WAAW,OAAO;AAAA,EAC/B,aAAa;AAAA,IACZ,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,cAAc;AAAA,IACd,UAAU;AAAA,EACX;AAAA,EACA,gBAAgB;AAAA,IACf,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA,EACT;AACD;;;ADlEO,IAAM,2BAAuB,4BAAgB;AAAA,EACnD,MAAM;AAAA,EACN,OAAO;AAAA,IACN,QAAQ,EAAE,MAAM,QAAwC,UAAU,KAAK;AAAA,IACvE,MAAM,EAAE,MAAM,QAAQ,UAAU,KAAK;AAAA,IACrC,QAAQ,EAAE,MAAM,QAAmC,SAAS,KAAK;AAAA,EAClE;AAAA,EACA,OAAO;AAAA,IACN,OAAO,MAAM;AAAA,EACd;AAAA,EACA,MAAM,OAAO,EAAE,KAAK,GAAG;AACtB,UAAM,EAAE,UAAU,WAAW,OAAO,QAAQ,QAAI;AAAA,MAC/C,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACP;AACA,UAAM,EAAE,cAAc,WAAW,UAAU,OAAO,UAAU,QAAI,0CAAgB,MAAM,MAAM;AAC5F,UAAM,EAAE,WAAW,SAAS,QAAI,+CAAqB,MAAM,QAAQ,MAAM,MAAM,MAAM,MAAM;AAE3F,UAAM,cAAU,gBAAI,EAAE;AACtB,UAAM,WAAO,gBAAI,EAAE;AACnB,UAAM,WAAO,gBAAI,EAAE;AACnB,UAAM,aAAS,gBAAI,IAAI;AAEvB,0BAAM,UAAU,CAAC,QAAQ;AACxB,UAAI,CAAC,IAAK;AACV,cAAQ,QAAQ,IAAI,WAAW;AAC/B,WAAK,QAAQ,IAAI,QAAQ;AACzB,WAAK,QAAQ,IAAI;AACjB,aAAO,QAAQ,IAAI;AAAA,IACpB,CAAC;AAED,mBAAe,aAAa,OAAc;AACzC,YAAM,eAAe;AACrB,UAAI;AACH,cAAM,QAA2B,EAAE,MAAM,KAAK,OAAO,QAAQ,OAAO,MAAM;AAC1E,YAAI,QAAQ,MAAO,OAAM,UAAU,QAAQ;AAC3C,YAAI,KAAK,MAAO,OAAM,OAAO,KAAK;AAClC,YAAI,SAAS,OAAO,YAAY,OAAW,OAAM,YAAY,SAAS,MAAM;AAC5E,cAAM,aAAa,MAAM,MAAM,OAAO,MAAM,MAAM;AAClD,cAAM,QAAQ;AACd,aAAK,OAAO;AAAA,MACb,QAAQ;AAAA,MAER;AAAA,IACD;AAEA,aAAS,eAAe,KAAwB;AAC/C,iBAAO,cAAE,MAAM,EAAE,KAAK,IAAI,SAAS,OAAO,OAAO,YAAY,GAAG;AAAA,YAC/D;AAAA,UACC;AAAA,UACA,IAAI,IAAI,OAAO,WAAM,IAAI,SAAS,SAAS,WAAM,IAAI,KAAK,IAAI,SAAS,EAAE,eAAe,CAAC;AAAA,QAC1F;AAAA,YACA;AAAA,UACC;AAAA,UACA,EAAE,MAAM,UAAU,OAAO,OAAO,gBAAgB,SAAS,MAAM,SAAS,IAAI,OAAO,EAAE;AAAA,UACrF;AAAA,QACD;AAAA,MACD,CAAC;AAAA,IACF;AAEA,WAAO,MAAM;AACZ,UAAI,UAAU,MAAO,YAAO,cAAE,KAAK,EAAE,OAAO,OAAO,OAAO,GAAG,wBAAmB;AAChF,UAAI,MAAM;AACT,mBAAO,cAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,MAAM,MAAM,WAAW;AAE9E,iBAAO,cAAE,OAAO,EAAE,OAAO,OAAO,UAAU,GAAG;AAAA,YAC5C,cAAE,MAAM,EAAE,OAAO,OAAO,MAAM,GAAG,MAAM,IAAI;AAAA,YAC3C;AAAA,UACC;AAAA,UACA,EAAE,OAAO,OAAO,KAAK;AAAA,UACrB,GAAG,MAAM,UAAU,MAAM,UAAO,SAAS,OAAO,WAAW,CAAC;AAAA,QAC7D;AAAA,YACA,cAAE,QAAQ,EAAE,OAAO,OAAO,MAAM,UAAU,aAAa,GAAG;AAAA,cACzD,cAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,mBAAmB,GAAG,SAAS;AAAA,cACtE,cAAE,SAAS;AAAA,YACV,IAAI;AAAA,YACJ,OAAO,OAAO;AAAA,YACd,OAAO,QAAQ;AAAA,YACf,SAAS,CAAC,MAAa;AACtB,sBAAQ,QAAS,EAAE,OAA4B;AAAA,YAChD;AAAA,UACD,CAAC;AAAA,cACD,cAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,gBAAgB,GAAG,WAAW;AAAA,cACrE,cAAE,YAAY;AAAA,YACb,IAAI;AAAA,YACJ,OAAO,OAAO;AAAA,YACd,MAAM;AAAA,YACN,OAAO,KAAK;AAAA,YACZ,SAAS,CAAC,MAAa;AACtB,mBAAK,QAAS,EAAE,OAA+B;AAAA,YAChD;AAAA,UACD,CAAC;AAAA,cACD,cAAE,SAAS,EAAE,OAAO,OAAO,OAAO,KAAK,gBAAgB,GAAG,iBAAiB;AAAA,cAC3E,cAAE,YAAY;AAAA,YACb,IAAI;AAAA,YACJ,OAAO,OAAO;AAAA,YACd,MAAM;AAAA,YACN,UAAU;AAAA,YACV,OAAO,KAAK;AAAA,YACZ,SAAS,CAAC,MAAa;AACtB,mBAAK,QAAS,EAAE,OAA+B;AAAA,YAChD;AAAA,UACD,CAAC;AAAA,cACD,cAAE,SAAS,EAAE,OAAO,OAAO,cAAc,GAAG;AAAA,gBAC3C,cAAE,SAAS;AAAA,cACV,MAAM;AAAA,cACN,SAAS,OAAO;AAAA,cAChB,UAAU,CAAC,MAAa;AACvB,uBAAO,QAAS,EAAE,OAA4B;AAAA,cAC/C;AAAA,YACD,CAAC;AAAA,YACD;AAAA,UACD,CAAC;AAAA,UACD,UAAU,YACP,cAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,UAAU,MAAM,WAAW,IAC1E;AAAA,cACH;AAAA,YACC;AAAA,YACA,EAAE,MAAM,UAAU,UAAU,SAAS,OAAO,OAAO,OAAO,OAAO;AAAA,YACjE,SAAS,QAAQ,iBAAY;AAAA,UAC9B;AAAA,QACD,CAAC;AAAA,QACD,UAAU,MAAM,SAAS,QACtB,cAAE,OAAO,EAAE,OAAO,OAAO,UAAU,GAAG;AAAA,cACtC,cAAE,MAAM,EAAE,OAAO,OAAO,SAAS,GAAG,SAAS;AAAA,cAC7C,cAAE,MAAM,EAAE,OAAO,OAAO,KAAK,GAAG,UAAU,MAAM,IAAI,cAAc,CAAC;AAAA,QACpE,CAAC,IACA;AAAA,MACJ,CAAC;AAAA,IACF;AAAA,EACD;AACD,CAAC;;;AEzID,IAAAA,4BAA6B;AAE7B,IAAAC,cAAmC;AAG5B,IAAM,yBAAqB,6BAAgB;AAAA,EACjD,MAAM;AAAA,EACN,OAAO;AAAA,IACN,QAAQ,EAAE,MAAM,QAAwC,UAAU,KAAK;AAAA,EACxE;AAAA,EACA,OAAO;AAAA,IACN,mBAAmB,CAAC,cAA8B;AAAA,EACnD;AAAA,EACA,MAAM,OAAO,EAAE,KAAK,GAAG;AACtB,UAAM,EAAE,WAAW,WAAW,MAAM,QAAI,wCAAa,MAAM,MAAM;AAEjE,aAAS,UAAU,UAA0B;AAC5C,iBAAO,eAAE,MAAM,EAAE,KAAK,GAAG,SAAS,IAAI,IAAI,SAAS,UAAU,MAAM,IAAI,OAAO,OAAO,IAAI,GAAG;AAAA,YAC3F;AAAA,UACC;AAAA,UACA;AAAA,YACC,MAAM;AAAA,YACN,OAAO,OAAO;AAAA,YACd,SAAS,MAAM,KAAK,mBAAmB,QAAQ;AAAA,UAChD;AAAA,UACA;AAAA,gBACC,eAAE,QAAQ,EAAE,OAAO,OAAO,KAAK,GAAG,SAAS,IAAI;AAAA,gBAC/C,eAAE,QAAQ,EAAE,OAAO,OAAO,OAAO,GAAG,SAAS,UAAU,MAAM;AAAA,gBAC7D;AAAA,cACC;AAAA,cACA,EAAE,OAAO,SAAS,SAAS,OAAO,SAAS,OAAO,SAAS;AAAA,cAC3D,SAAS,SAAS,WAAW;AAAA,YAC9B;AAAA,UACD;AAAA,QACD;AAAA,MACD,CAAC;AAAA,IACF;AAEA,WAAO,MAAM;AACZ,UAAI,UAAU,MAAO,YAAO,eAAE,KAAK,EAAE,OAAO,OAAO,OAAO,GAAG,yBAAoB;AACjF,UAAI,MAAM;AACT,mBAAO,eAAE,KAAK,EAAE,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,MAAM,MAAM,WAAW;AAE9E,iBAAO,eAAE,OAAO,EAAE,OAAO,OAAO,UAAU,GAAG;AAAA,YAC5C,eAAE,MAAM,EAAE,OAAO,OAAO,MAAM,GAAG,WAAW;AAAA,YAC5C,eAAE,MAAM,EAAE,OAAO,OAAO,KAAK,GAAG,UAAU,MAAM,IAAI,SAAS,CAAC;AAAA,MAC/D,CAAC;AAAA,IACF;AAAA,EACD;AACD,CAAC;","names":["import_vue_courier_admin","import_vue"]}
@@ -0,0 +1,59 @@
1
+ import * as vue from 'vue';
2
+ import { PropType } from 'vue';
3
+ import { CourierAdminClient, ITemplateEntry } from '@fonderie/client';
4
+
5
+ declare const TemplateEditorScreen: vue.DefineComponent<vue.ExtractPropTypes<{
6
+ client: {
7
+ type: PropType<CourierAdminClient>;
8
+ required: true;
9
+ };
10
+ type: {
11
+ type: StringConstructor;
12
+ required: true;
13
+ };
14
+ locale: {
15
+ type: PropType<string | null>;
16
+ default: null;
17
+ };
18
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
19
+ [key: string]: any;
20
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
21
+ saved: () => true;
22
+ }, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
23
+ client: {
24
+ type: PropType<CourierAdminClient>;
25
+ required: true;
26
+ };
27
+ type: {
28
+ type: StringConstructor;
29
+ required: true;
30
+ };
31
+ locale: {
32
+ type: PropType<string | null>;
33
+ default: null;
34
+ };
35
+ }>> & Readonly<{
36
+ onSaved?: () => any;
37
+ }>, {
38
+ locale: string | null;
39
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
40
+
41
+ declare const TemplateListScreen: vue.DefineComponent<vue.ExtractPropTypes<{
42
+ client: {
43
+ type: PropType<CourierAdminClient>;
44
+ required: true;
45
+ };
46
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
47
+ [key: string]: any;
48
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
49
+ 'select-template': (_template: ITemplateEntry) => true;
50
+ }, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
51
+ client: {
52
+ type: PropType<CourierAdminClient>;
53
+ required: true;
54
+ };
55
+ }>> & Readonly<{
56
+ "onSelect-template"?: (_template: ITemplateEntry) => any;
57
+ }>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
58
+
59
+ export { TemplateEditorScreen, TemplateListScreen };
@@ -0,0 +1,59 @@
1
+ import * as vue from 'vue';
2
+ import { PropType } from 'vue';
3
+ import { CourierAdminClient, ITemplateEntry } from '@fonderie/client';
4
+
5
+ declare const TemplateEditorScreen: vue.DefineComponent<vue.ExtractPropTypes<{
6
+ client: {
7
+ type: PropType<CourierAdminClient>;
8
+ required: true;
9
+ };
10
+ type: {
11
+ type: StringConstructor;
12
+ required: true;
13
+ };
14
+ locale: {
15
+ type: PropType<string | null>;
16
+ default: null;
17
+ };
18
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
19
+ [key: string]: any;
20
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
21
+ saved: () => true;
22
+ }, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
23
+ client: {
24
+ type: PropType<CourierAdminClient>;
25
+ required: true;
26
+ };
27
+ type: {
28
+ type: StringConstructor;
29
+ required: true;
30
+ };
31
+ locale: {
32
+ type: PropType<string | null>;
33
+ default: null;
34
+ };
35
+ }>> & Readonly<{
36
+ onSaved?: () => any;
37
+ }>, {
38
+ locale: string | null;
39
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
40
+
41
+ declare const TemplateListScreen: vue.DefineComponent<vue.ExtractPropTypes<{
42
+ client: {
43
+ type: PropType<CourierAdminClient>;
44
+ required: true;
45
+ };
46
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
47
+ [key: string]: any;
48
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
49
+ 'select-template': (_template: ITemplateEntry) => true;
50
+ }, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
51
+ client: {
52
+ type: PropType<CourierAdminClient>;
53
+ required: true;
54
+ };
55
+ }>> & Readonly<{
56
+ "onSelect-template"?: (_template: ITemplateEntry) => any;
57
+ }>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
58
+
59
+ export { TemplateEditorScreen, TemplateListScreen };
package/dist/index.js ADDED
@@ -0,0 +1,251 @@
1
+ // src/screens/TemplateEditorScreen.ts
2
+ import { useSaveTemplate, useTemplate, useTemplateRevisions } from "@fonderie/vue-courier-admin";
3
+ import { defineComponent, h, ref, watch } from "vue";
4
+
5
+ // src/styles.ts
6
+ var styles = {
7
+ container: { padding: "24px", maxWidth: "640px" },
8
+ title: { fontSize: "24px", fontWeight: 700 },
9
+ subtitle: { fontSize: "16px", fontWeight: 600, marginBottom: "8px" },
10
+ meta: { fontSize: "13px", color: "#666", marginBottom: "16px" },
11
+ status: { padding: "24px", textAlign: "center", color: "#666" },
12
+ error: { color: "#e11d48", marginBottom: "12px", fontSize: "14px" },
13
+ list: { listStyle: "none", padding: "0", margin: "0" },
14
+ row: { borderBottom: "1px solid #eee" },
15
+ rowButton: {
16
+ width: "100%",
17
+ display: "flex",
18
+ justifyContent: "space-between",
19
+ alignItems: "center",
20
+ padding: "12px 0",
21
+ background: "none",
22
+ border: "none",
23
+ cursor: "pointer",
24
+ textAlign: "left"
25
+ },
26
+ type: { fontSize: "14px", fontWeight: 600, flex: "1" },
27
+ locale: { fontSize: "13px", color: "#666", marginRight: "16px" },
28
+ active: { fontSize: "12px", color: "#16a34a" },
29
+ inactive: { fontSize: "12px", color: "#999" },
30
+ form: { display: "flex", flexDirection: "column", gap: "4px" },
31
+ label: { fontSize: "13px", fontWeight: 600, marginTop: "12px" },
32
+ input: { border: "1px solid #ddd", borderRadius: "8px", padding: "10px", fontSize: "14px" },
33
+ textarea: {
34
+ border: "1px solid #ddd",
35
+ borderRadius: "8px",
36
+ padding: "10px",
37
+ fontSize: "14px",
38
+ fontFamily: "monospace"
39
+ },
40
+ checkboxLabel: {
41
+ display: "flex",
42
+ alignItems: "center",
43
+ gap: "8px",
44
+ marginTop: "12px",
45
+ fontSize: "14px"
46
+ },
47
+ button: {
48
+ marginTop: "16px",
49
+ backgroundColor: "#000",
50
+ color: "#fff",
51
+ padding: "10px 20px",
52
+ borderRadius: "8px",
53
+ border: "none",
54
+ fontSize: "14px",
55
+ fontWeight: 600,
56
+ cursor: "pointer",
57
+ alignSelf: "flex-start"
58
+ },
59
+ revisions: { marginTop: "32px" },
60
+ revisionRow: {
61
+ display: "flex",
62
+ justifyContent: "space-between",
63
+ alignItems: "center",
64
+ padding: "8px 0",
65
+ borderBottom: "1px solid #eee",
66
+ fontSize: "13px"
67
+ },
68
+ rollbackButton: {
69
+ background: "none",
70
+ border: "1px solid #ddd",
71
+ borderRadius: "8px",
72
+ padding: "4px 10px",
73
+ fontSize: "12px",
74
+ cursor: "pointer"
75
+ }
76
+ };
77
+
78
+ // src/screens/TemplateEditorScreen.ts
79
+ var TemplateEditorScreen = defineComponent({
80
+ name: "FonderieTemplateEditorScreen",
81
+ props: {
82
+ client: { type: Object, required: true },
83
+ type: { type: String, required: true },
84
+ locale: { type: String, default: null }
85
+ },
86
+ emits: {
87
+ saved: () => true
88
+ },
89
+ setup(props, { emit }) {
90
+ const { template, isLoading, error, refresh } = useTemplate(
91
+ props.client,
92
+ props.type,
93
+ props.locale
94
+ );
95
+ const { saveTemplate, isLoading: isSaving, error: saveError } = useSaveTemplate(props.client);
96
+ const { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);
97
+ const subject = ref("");
98
+ const html = ref("");
99
+ const text = ref("");
100
+ const active = ref(true);
101
+ watch(template, (tpl) => {
102
+ if (!tpl) return;
103
+ subject.value = tpl.subject ?? "";
104
+ html.value = tpl.html ?? "";
105
+ text.value = tpl.text;
106
+ active.value = tpl.active;
107
+ });
108
+ async function handleSubmit(event) {
109
+ event.preventDefault();
110
+ try {
111
+ const input = { text: text.value, active: active.value };
112
+ if (subject.value) input.subject = subject.value;
113
+ if (html.value) input.html = html.value;
114
+ if (template.value?.version !== void 0) input.ifVersion = template.value.version;
115
+ await saveTemplate(props.type, input, props.locale);
116
+ await refresh();
117
+ emit("saved");
118
+ } catch {
119
+ }
120
+ }
121
+ function renderRevision(rev) {
122
+ return h("li", { key: rev.version, style: styles.revisionRow }, [
123
+ h(
124
+ "span",
125
+ `v${rev.version} \u2014 ${rev.actor ?? "unknown"} \u2014 ${new Date(rev.createdAt).toLocaleString()}`
126
+ ),
127
+ h(
128
+ "button",
129
+ { type: "button", style: styles.rollbackButton, onClick: () => rollback(rev.version) },
130
+ "Roll back"
131
+ )
132
+ ]);
133
+ }
134
+ return () => {
135
+ if (isLoading.value) return h("p", { style: styles.status }, "Loading template\u2026");
136
+ if (error.value)
137
+ return h("p", { style: styles.error, role: "alert" }, error.value.explanation);
138
+ return h("div", { style: styles.container }, [
139
+ h("h1", { style: styles.title }, props.type),
140
+ h(
141
+ "p",
142
+ { style: styles.meta },
143
+ `${props.locale ?? "base"} \xB7 v${template.value?.version ?? 1}`
144
+ ),
145
+ h("form", { style: styles.form, onSubmit: handleSubmit }, [
146
+ h("label", { style: styles.label, for: "template-subject" }, "Subject"),
147
+ h("input", {
148
+ id: "template-subject",
149
+ style: styles.input,
150
+ value: subject.value,
151
+ onInput: (e) => {
152
+ subject.value = e.target.value;
153
+ }
154
+ }),
155
+ h("label", { style: styles.label, for: "template-html" }, "HTML body"),
156
+ h("textarea", {
157
+ id: "template-html",
158
+ style: styles.textarea,
159
+ rows: 8,
160
+ value: html.value,
161
+ onInput: (e) => {
162
+ html.value = e.target.value;
163
+ }
164
+ }),
165
+ h("label", { style: styles.label, for: "template-text" }, "Plain-text body"),
166
+ h("textarea", {
167
+ id: "template-text",
168
+ style: styles.textarea,
169
+ rows: 4,
170
+ required: true,
171
+ value: text.value,
172
+ onInput: (e) => {
173
+ text.value = e.target.value;
174
+ }
175
+ }),
176
+ h("label", { style: styles.checkboxLabel }, [
177
+ h("input", {
178
+ type: "checkbox",
179
+ checked: active.value,
180
+ onChange: (e) => {
181
+ active.value = e.target.checked;
182
+ }
183
+ }),
184
+ "Active"
185
+ ]),
186
+ saveError.value ? h("p", { style: styles.error, role: "alert" }, saveError.value.explanation) : null,
187
+ h(
188
+ "button",
189
+ { type: "submit", disabled: isSaving.value, style: styles.button },
190
+ isSaving.value ? "Saving\u2026" : "Save"
191
+ )
192
+ ]),
193
+ revisions.value.length > 0 ? h("div", { style: styles.revisions }, [
194
+ h("h2", { style: styles.subtitle }, "History"),
195
+ h("ul", { style: styles.list }, revisions.value.map(renderRevision))
196
+ ]) : null
197
+ ]);
198
+ };
199
+ }
200
+ });
201
+
202
+ // src/screens/TemplateListScreen.ts
203
+ import { useTemplates } from "@fonderie/vue-courier-admin";
204
+ import { defineComponent as defineComponent2, h as h2 } from "vue";
205
+ var TemplateListScreen = defineComponent2({
206
+ name: "FonderieTemplateListScreen",
207
+ props: {
208
+ client: { type: Object, required: true }
209
+ },
210
+ emits: {
211
+ "select-template": (_template) => true
212
+ },
213
+ setup(props, { emit }) {
214
+ const { templates, isLoading, error } = useTemplates(props.client);
215
+ function renderRow(template) {
216
+ return h2("li", { key: `${template.type}:${template.locale ?? "base"}`, style: styles.row }, [
217
+ h2(
218
+ "button",
219
+ {
220
+ type: "button",
221
+ style: styles.rowButton,
222
+ onClick: () => emit("select-template", template)
223
+ },
224
+ [
225
+ h2("span", { style: styles.type }, template.type),
226
+ h2("span", { style: styles.locale }, template.locale ?? "base"),
227
+ h2(
228
+ "span",
229
+ { style: template.active ? styles.active : styles.inactive },
230
+ template.active ? "Active" : "Inactive"
231
+ )
232
+ ]
233
+ )
234
+ ]);
235
+ }
236
+ return () => {
237
+ if (isLoading.value) return h2("p", { style: styles.status }, "Loading templates\u2026");
238
+ if (error.value)
239
+ return h2("p", { style: styles.error, role: "alert" }, error.value.explanation);
240
+ return h2("div", { style: styles.container }, [
241
+ h2("h1", { style: styles.title }, "Templates"),
242
+ h2("ul", { style: styles.list }, templates.value.map(renderRow))
243
+ ]);
244
+ };
245
+ }
246
+ });
247
+ export {
248
+ TemplateEditorScreen,
249
+ TemplateListScreen
250
+ };
251
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/screens/TemplateEditorScreen.ts","../src/styles.ts","../src/screens/TemplateListScreen.ts"],"sourcesContent":["import type { CourierAdminClient, ISetTemplateInput, ITemplateRevision } from '@fonderie/client';\nimport { useSaveTemplate, useTemplate, useTemplateRevisions } from '@fonderie/vue-courier-admin';\nimport type { PropType } from 'vue';\nimport { defineComponent, h, ref, watch } from 'vue';\nimport { styles } from '../styles';\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\tconst { saveTemplate, isLoading: isSaving, error: saveError } = useSaveTemplate(props.client);\n\t\tconst { revisions, rollback } = useTemplateRevisions(props.client, props.type, props.locale);\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\tasync function handleSubmit(event: Event) {\n\t\t\tevent.preventDefault();\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\tawait refresh();\n\t\t\t\temit('saved');\n\t\t\t} catch {\n\t\t\t\t// Surfaced via saveError.\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('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\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: '640px' },\n\ttitle: { fontSize: '24px', fontWeight: 700 },\n\tsubtitle: { fontSize: '16px', fontWeight: 600, marginBottom: '8px' },\n\tmeta: { fontSize: '13px', color: '#666', marginBottom: '16px' },\n\tstatus: { padding: '24px', textAlign: 'center', color: '#666' },\n\terror: { color: '#e11d48', marginBottom: '12px', fontSize: '14px' },\n\tlist: { listStyle: 'none', padding: '0', margin: '0' },\n\trow: { borderBottom: '1px solid #eee' },\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: '#666', marginRight: '16px' },\n\tactive: { fontSize: '12px', color: '#16a34a' },\n\tinactive: { fontSize: '12px', color: '#999' },\n\tform: { display: 'flex', flexDirection: 'column', gap: '4px' },\n\tlabel: { fontSize: '13px', fontWeight: 600, marginTop: '12px' },\n\tinput: { border: '1px solid #ddd', borderRadius: '8px', padding: '10px', fontSize: '14px' },\n\ttextarea: {\n\t\tborder: '1px solid #ddd',\n\t\tborderRadius: '8px',\n\t\tpadding: '10px',\n\t\tfontSize: '14px',\n\t\tfontFamily: '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: '#000',\n\t\tcolor: '#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 #eee',\n\t\tfontSize: '13px',\n\t},\n\trollbackButton: {\n\t\tbackground: 'none',\n\t\tborder: '1px solid #ddd',\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":["defineComponent","h","defineComponent","h"]}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@fonderie/vue-courier-admin-screens",
3
+ "version": "0.1.0",
4
+ "description": "Pre-built Vue screens for the Fonderie courier admin API — template list, template editor with revision history and rollback.",
5
+ "keywords": [
6
+ "fonderie-js",
7
+ "vue",
8
+ "courier",
9
+ "templates",
10
+ "admin",
11
+ "screens",
12
+ "ui",
13
+ "typescript"
14
+ ],
15
+ "license": "MIT",
16
+ "type": "module",
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.cjs"
25
+ }
26
+ },
27
+ "main": "./dist/index.cjs",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "dev": "tsup --watch",
33
+ "typecheck": "tsc --noEmit",
34
+ "lint": "biome lint src",
35
+ "format": "biome format --write src",
36
+ "check": "biome check --write src"
37
+ },
38
+ "dependencies": {
39
+ "@fonderie/client": "*",
40
+ "@fonderie/vue-courier-admin": "*"
41
+ },
42
+ "peerDependencies": {
43
+ "vue": ">=3.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^25.6.0",
47
+ "tsup": "^8.5.1",
48
+ "typescript": "^6.0.3",
49
+ "vue": "^3.5.0"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "files": [
55
+ "dist",
56
+ "LICENSE",
57
+ "README.md"
58
+ ],
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/fonderiejs/fonderie.git",
62
+ "directory": "packages/vue-courier-admin-screens"
63
+ },
64
+ "homepage": "https://github.com/fonderiejs/fonderie/tree/main/packages/vue-courier-admin-screens#readme",
65
+ "bugs": {
66
+ "url": "https://github.com/fonderiejs/fonderie/issues"
67
+ }
68
+ }