@thebes/cadmea 1.0.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 +21 -0
- package/README.md +133 -0
- package/dist/RichTextEditor-BPilh7Pw.js +36 -0
- package/dist/RichTextEditor-BPilh7Pw.js.map +1 -0
- package/dist/RichTextEditor-DcLqdFY7.js +15 -0
- package/dist/RichTextEditor-DcLqdFY7.js.map +1 -0
- package/dist/index/index.d.ts +147 -0
- package/dist/index/index.js +740 -0
- package/dist/index/index.js.map +1 -0
- package/dist/index/server.js +508 -0
- package/dist/index/server.js.map +1 -0
- package/dist/tanstack-start/index.d.ts +180 -0
- package/dist/tanstack-start/index.js +897 -0
- package/dist/tanstack-start/index.js.map +1 -0
- package/dist/tanstack-start/server.js +730 -0
- package/dist/tanstack-start/server.js.map +1 -0
- package/package.json +138 -0
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
import { createComponent, escape, ssr, ssrAttribute } from "solid-js/web";
|
|
2
|
+
import { createMutation, createQuery, useQueryClient } from "@tanstack/solid-query";
|
|
3
|
+
import { For, Show, Suspense, createEffect, createSignal, lazy } from "solid-js";
|
|
4
|
+
import { Link, useBlocker } from "@tanstack/solid-router";
|
|
5
|
+
//#region src/CollectionEdit.tsx
|
|
6
|
+
var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmpl$2$3 = "<span class=\"loading loading-spinner loading-sm\"></span>", _tmpl$3$1 = [
|
|
7
|
+
"<button type=\"button\" class=\"btn flex-1\"",
|
|
8
|
+
">",
|
|
9
|
+
"</button>"
|
|
10
|
+
], _tmpl$4$1 = [
|
|
11
|
+
"<button type=\"button\" class=\"btn btn-primary flex-1\"",
|
|
12
|
+
">",
|
|
13
|
+
"</button>"
|
|
14
|
+
], _tmpl$5$1 = [
|
|
15
|
+
"<button type=\"button\" class=\"btn btn-outline flex-1\"",
|
|
16
|
+
">",
|
|
17
|
+
"</button>"
|
|
18
|
+
], _tmpl$6$1 = [
|
|
19
|
+
"<form class=\"flex flex-col gap-4\">",
|
|
20
|
+
"",
|
|
21
|
+
"<div class=\"bg-base-100 sticky bottom-0 flex gap-2 border-t py-3\">",
|
|
22
|
+
"</div></form>"
|
|
23
|
+
], _tmpl$7$1 = "<span class=\"text-error\"> *</span>", _tmpl$8$1 = [
|
|
24
|
+
"<div class=\"form-control\"><label class=\"label\"",
|
|
25
|
+
">",
|
|
26
|
+
"",
|
|
27
|
+
"</label>",
|
|
28
|
+
"</div>"
|
|
29
|
+
], _tmpl$9$1 = [
|
|
30
|
+
"<button type=\"submit\" class=\"btn btn-primary flex-1\"",
|
|
31
|
+
">",
|
|
32
|
+
"</button>"
|
|
33
|
+
], _tmpl$0$1 = [
|
|
34
|
+
"<input",
|
|
35
|
+
" class=\"input\" type=\"text\"",
|
|
36
|
+
"",
|
|
37
|
+
">"
|
|
38
|
+
], _tmpl$1$1 = [
|
|
39
|
+
"<select",
|
|
40
|
+
" class=\"select\"",
|
|
41
|
+
"",
|
|
42
|
+
">",
|
|
43
|
+
"</select>"
|
|
44
|
+
], _tmpl$10$1 = [
|
|
45
|
+
"<option",
|
|
46
|
+
">",
|
|
47
|
+
"</option>"
|
|
48
|
+
], _tmpl$11$1 = [
|
|
49
|
+
"<input",
|
|
50
|
+
" class=\"input\" type=\"number\"",
|
|
51
|
+
"",
|
|
52
|
+
">"
|
|
53
|
+
], _tmpl$12$1 = [
|
|
54
|
+
"<input",
|
|
55
|
+
" class=\"input\" type=\"text\" readonly",
|
|
56
|
+
">"
|
|
57
|
+
], _tmpl$13$1 = [
|
|
58
|
+
"<input",
|
|
59
|
+
" class=\"checkbox\" type=\"checkbox\"",
|
|
60
|
+
">"
|
|
61
|
+
], _tmpl$14$1 = ["<p class=\"text-sm opacity-70 break-all\">", "</p>"], _tmpl$15 = ["<p class=\"text-sm text-error\">", "</p>"], _tmpl$16 = [
|
|
62
|
+
"<div class=\"flex flex-col gap-2\">",
|
|
63
|
+
"<input",
|
|
64
|
+
" class=\"file-input\" type=\"file\"",
|
|
65
|
+
"",
|
|
66
|
+
">",
|
|
67
|
+
"",
|
|
68
|
+
"</div>"
|
|
69
|
+
], _tmpl$17 = [
|
|
70
|
+
"<select",
|
|
71
|
+
" class=\"select\"",
|
|
72
|
+
"",
|
|
73
|
+
"><option value>—</option>",
|
|
74
|
+
"</select>"
|
|
75
|
+
], _tmpl$18 = [
|
|
76
|
+
"<div class=\"flex flex-col gap-3\">",
|
|
77
|
+
"<button type=\"button\" class=\"btn btn-outline btn-sm self-start\">Add ",
|
|
78
|
+
"</button></div>"
|
|
79
|
+
], _tmpl$19 = ["<div class=\"card bg-base-200 flex flex-col gap-2 p-3\">", "<button type=\"button\" class=\"btn btn-error btn-outline btn-sm self-start\">Remove</button></div>"];
|
|
80
|
+
const RichTextEditor = lazy(() => import("../RichTextEditor-DcLqdFY7.js").then((mod) => ({ default: mod.RichTextEditor })));
|
|
81
|
+
function editableFields(config) {
|
|
82
|
+
return Object.entries(config.fields).filter(([key]) => key !== "id");
|
|
83
|
+
}
|
|
84
|
+
function CollectionEdit(props) {
|
|
85
|
+
const initialSnapshot = JSON.stringify(props.initialValues ?? {});
|
|
86
|
+
const [values, setValues] = createSignal(props.initialValues ?? {});
|
|
87
|
+
createEffect(() => {
|
|
88
|
+
props.onDirtyChange?.(JSON.stringify(values()) !== initialSnapshot);
|
|
89
|
+
});
|
|
90
|
+
function setField(key, value) {
|
|
91
|
+
setValues((prev) => ({
|
|
92
|
+
...prev,
|
|
93
|
+
[key]: value
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
const ctx = {
|
|
97
|
+
onUploadFile: props.onUploadFile,
|
|
98
|
+
relationshipOptions: props.relationshipOptions
|
|
99
|
+
};
|
|
100
|
+
const versioned = () => props.config.versions?.drafts && props.draftActions;
|
|
101
|
+
return ssr(_tmpl$6$1, escape(createComponent(Show, {
|
|
102
|
+
get when() {
|
|
103
|
+
return props.error;
|
|
104
|
+
},
|
|
105
|
+
get children() {
|
|
106
|
+
return ssr(_tmpl$$4, escape(props.error));
|
|
107
|
+
}
|
|
108
|
+
})), escape(createComponent(For, {
|
|
109
|
+
get each() {
|
|
110
|
+
return editableFields(props.config);
|
|
111
|
+
},
|
|
112
|
+
children: ([key, field]) => ssr(_tmpl$8$1, ssrAttribute("for", escape(key, true), false), escape(key), escape(createComponent(Show, {
|
|
113
|
+
get when() {
|
|
114
|
+
return field.required;
|
|
115
|
+
},
|
|
116
|
+
get children() {
|
|
117
|
+
return ssr(_tmpl$7$1);
|
|
118
|
+
}
|
|
119
|
+
})), escape(renderInput(key, field, values()[key], setField, ctx)))
|
|
120
|
+
})), escape(createComponent(Show, {
|
|
121
|
+
get when() {
|
|
122
|
+
return versioned();
|
|
123
|
+
},
|
|
124
|
+
get fallback() {
|
|
125
|
+
return createComponent(Show, {
|
|
126
|
+
get when() {
|
|
127
|
+
return props.capabilities?.canUpdate !== false;
|
|
128
|
+
},
|
|
129
|
+
get children() {
|
|
130
|
+
return ssr(_tmpl$9$1, ssrAttribute("disabled", props.saving, true), escape(createComponent(Show, {
|
|
131
|
+
get when() {
|
|
132
|
+
return props.saving;
|
|
133
|
+
},
|
|
134
|
+
get fallback() {
|
|
135
|
+
return props.submitLabel ?? "Save";
|
|
136
|
+
},
|
|
137
|
+
get children() {
|
|
138
|
+
return ssr(_tmpl$2$3);
|
|
139
|
+
}
|
|
140
|
+
})));
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
get children() {
|
|
145
|
+
return [
|
|
146
|
+
ssr(_tmpl$3$1, ssrAttribute("disabled", props.draftActions?.saving, true), escape(createComponent(Show, {
|
|
147
|
+
get when() {
|
|
148
|
+
return props.draftActions?.saving;
|
|
149
|
+
},
|
|
150
|
+
get fallback() {
|
|
151
|
+
return props.draftActions?.saveDraftLabel ?? "Save draft";
|
|
152
|
+
},
|
|
153
|
+
get children() {
|
|
154
|
+
return ssr(_tmpl$2$3);
|
|
155
|
+
}
|
|
156
|
+
}))),
|
|
157
|
+
ssr(_tmpl$4$1, ssrAttribute("disabled", !props.draftActions?.canPublish || props.draftActions?.publishing, true), escape(createComponent(Show, {
|
|
158
|
+
get when() {
|
|
159
|
+
return props.draftActions?.publishing;
|
|
160
|
+
},
|
|
161
|
+
get fallback() {
|
|
162
|
+
return props.draftActions?.publishLabel ?? "Publish";
|
|
163
|
+
},
|
|
164
|
+
get children() {
|
|
165
|
+
return ssr(_tmpl$2$3);
|
|
166
|
+
}
|
|
167
|
+
}))),
|
|
168
|
+
createComponent(Show, {
|
|
169
|
+
get when() {
|
|
170
|
+
return props.draftActions?.onPreview;
|
|
171
|
+
},
|
|
172
|
+
get children() {
|
|
173
|
+
return ssr(_tmpl$5$1, ssrAttribute("disabled", !props.draftActions?.canPreview || props.draftActions?.previewing, true), escape(createComponent(Show, {
|
|
174
|
+
get when() {
|
|
175
|
+
return props.draftActions?.previewing;
|
|
176
|
+
},
|
|
177
|
+
get fallback() {
|
|
178
|
+
return props.draftActions?.previewLabel ?? "Preview";
|
|
179
|
+
},
|
|
180
|
+
get children() {
|
|
181
|
+
return ssr(_tmpl$2$3);
|
|
182
|
+
}
|
|
183
|
+
})));
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
})));
|
|
189
|
+
}
|
|
190
|
+
function renderInput(key, field, value, setField, ctx) {
|
|
191
|
+
switch (field.type) {
|
|
192
|
+
case "text": return ssr(_tmpl$0$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", escape(value ?? "", true), false), ssrAttribute("required", field.required, true));
|
|
193
|
+
case "select": return ssr(_tmpl$1$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", escape(value ?? "", true), false), ssrAttribute("required", field.required, true), escape(createComponent(For, {
|
|
194
|
+
get each() {
|
|
195
|
+
return field.options;
|
|
196
|
+
},
|
|
197
|
+
children: (option) => ssr(_tmpl$10$1, ssrAttribute("value", escape(option, true), false), escape(option))
|
|
198
|
+
})));
|
|
199
|
+
case "number": return ssr(_tmpl$11$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", escape(value ?? "", true), false), ssrAttribute("required", field.required, true));
|
|
200
|
+
case "date": return ssr(_tmpl$12$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", escape(formatDateValue(value), true), false));
|
|
201
|
+
case "checkbox": return ssr(_tmpl$13$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("checked", value ?? false, true));
|
|
202
|
+
case "upload": return renderUploadInput(key, field, value, setField, ctx);
|
|
203
|
+
case "relationship": return renderRelationshipInput(key, field, value, setField, ctx);
|
|
204
|
+
case "array": return renderArrayInput(key, field, value, setField, ctx);
|
|
205
|
+
case "richText": return createComponent(Suspense, {
|
|
206
|
+
get fallback() {
|
|
207
|
+
return ssr(_tmpl$2$3);
|
|
208
|
+
},
|
|
209
|
+
get children() {
|
|
210
|
+
return createComponent(RichTextEditor, {
|
|
211
|
+
id: key,
|
|
212
|
+
content: value,
|
|
213
|
+
onChange: (doc) => setField(key, doc)
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
default: return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function renderUploadInput(key, field, value, setField, ctx) {
|
|
221
|
+
const [uploading, setUploading] = createSignal(false);
|
|
222
|
+
const [uploadError, setUploadError] = createSignal();
|
|
223
|
+
return ssr(_tmpl$16, escape(createComponent(Show, {
|
|
224
|
+
when: value,
|
|
225
|
+
get children() {
|
|
226
|
+
return ssr(_tmpl$14$1, escape(value));
|
|
227
|
+
}
|
|
228
|
+
})), ssrAttribute("id", escape(key, true), false), ssrAttribute("required", field.required && !value, true), ssrAttribute("disabled", uploading(), true), escape(createComponent(Show, {
|
|
229
|
+
get when() {
|
|
230
|
+
return uploading();
|
|
231
|
+
},
|
|
232
|
+
get children() {
|
|
233
|
+
return ssr(_tmpl$2$3);
|
|
234
|
+
}
|
|
235
|
+
})), escape(createComponent(Show, {
|
|
236
|
+
get when() {
|
|
237
|
+
return uploadError();
|
|
238
|
+
},
|
|
239
|
+
get children() {
|
|
240
|
+
return ssr(_tmpl$15, escape(uploadError()));
|
|
241
|
+
}
|
|
242
|
+
})));
|
|
243
|
+
}
|
|
244
|
+
function renderRelationshipInput(key, field, value, setField, ctx) {
|
|
245
|
+
if (field.hasMany) return null;
|
|
246
|
+
const options = ctx.relationshipOptions?.[field.relationTo] ?? [];
|
|
247
|
+
return ssr(_tmpl$17, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", value != null ? escape(String(value), true) : "", false), ssrAttribute("required", field.required, true), escape(createComponent(For, {
|
|
248
|
+
each: options,
|
|
249
|
+
children: (option) => ssr(_tmpl$10$1, ssrAttribute("value", escape(option.id, true), false), escape(option.label))
|
|
250
|
+
})));
|
|
251
|
+
}
|
|
252
|
+
function renderArrayInput(key, field, value, setField, ctx) {
|
|
253
|
+
const items = () => Array.isArray(value) ? value : [];
|
|
254
|
+
function updateItem(index, itemKey, itemValue) {
|
|
255
|
+
const next = items().slice();
|
|
256
|
+
next[index] = {
|
|
257
|
+
...next[index],
|
|
258
|
+
[itemKey]: itemValue
|
|
259
|
+
};
|
|
260
|
+
setField(key, next);
|
|
261
|
+
}
|
|
262
|
+
function fieldsForItem(item) {
|
|
263
|
+
const base = Object.entries(field.fields);
|
|
264
|
+
const discriminator = field.discriminator;
|
|
265
|
+
if (!discriminator) return base;
|
|
266
|
+
const variantValue = item[discriminator.key];
|
|
267
|
+
const variantFields = typeof variantValue === "string" ? discriminator.variants[variantValue] : void 0;
|
|
268
|
+
return variantFields ? [...base, ...Object.entries(variantFields)] : base;
|
|
269
|
+
}
|
|
270
|
+
return ssr(_tmpl$18, escape(createComponent(For, {
|
|
271
|
+
get each() {
|
|
272
|
+
return items();
|
|
273
|
+
},
|
|
274
|
+
children: (item, index) => ssr(_tmpl$19, escape(createComponent(For, {
|
|
275
|
+
get each() {
|
|
276
|
+
return fieldsForItem(item);
|
|
277
|
+
},
|
|
278
|
+
children: ([itemKey, itemField]) => {
|
|
279
|
+
const inputId = `${key}.${index()}.${itemKey}`;
|
|
280
|
+
return ssr(_tmpl$8$1, ssrAttribute("for", escape(inputId, true), false), escape(itemKey), escape(createComponent(Show, {
|
|
281
|
+
get when() {
|
|
282
|
+
return itemField.required;
|
|
283
|
+
},
|
|
284
|
+
get children() {
|
|
285
|
+
return ssr(_tmpl$7$1);
|
|
286
|
+
}
|
|
287
|
+
})), escape(renderInput(inputId, itemField, item[itemKey], (_, v) => updateItem(index(), itemKey, v), ctx)));
|
|
288
|
+
}
|
|
289
|
+
})))
|
|
290
|
+
})), escape(key));
|
|
291
|
+
}
|
|
292
|
+
function formatDateValue(value) {
|
|
293
|
+
if (!value) return "—";
|
|
294
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
295
|
+
return Number.isNaN(date.getTime()) ? "—" : date.toLocaleString();
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
//#region src/tanstack-start/create.tsx
|
|
299
|
+
var _tmpl$$3 = [
|
|
300
|
+
"<div class=\"flex flex-col gap-4\"><h1 class=\"text-xl font-semibold\">",
|
|
301
|
+
"</h1>",
|
|
302
|
+
"</div>"
|
|
303
|
+
];
|
|
304
|
+
/**
|
|
305
|
+
* Builds a create-page component for a collection. See
|
|
306
|
+
* `createCollectionListPage`'s doc comment for the same rationale on
|
|
307
|
+
* keeping navigation in the route file rather than this package.
|
|
308
|
+
*/
|
|
309
|
+
function createCollectionCreatePage(options) {
|
|
310
|
+
return function CollectionCreatePage() {
|
|
311
|
+
const queryClient = useQueryClient();
|
|
312
|
+
const [error, setError] = createSignal();
|
|
313
|
+
const create = createMutation(() => ({
|
|
314
|
+
mutationFn: options.createFn,
|
|
315
|
+
onSuccess: (created) => {
|
|
316
|
+
queryClient.invalidateQueries({ queryKey: options.invalidateQueryKey });
|
|
317
|
+
options.onCreated?.(created);
|
|
318
|
+
},
|
|
319
|
+
onError: (e) => setError(e.message)
|
|
320
|
+
}));
|
|
321
|
+
return ssr(_tmpl$$3, escape(options.label ?? `New ${options.collection.slug}`), escape(createComponent(CollectionEdit, {
|
|
322
|
+
get config() {
|
|
323
|
+
return options.collection;
|
|
324
|
+
},
|
|
325
|
+
get submitLabel() {
|
|
326
|
+
return options.submitLabel ?? "Create";
|
|
327
|
+
},
|
|
328
|
+
get error() {
|
|
329
|
+
return error();
|
|
330
|
+
},
|
|
331
|
+
onSubmit: (values) => create.mutate(values),
|
|
332
|
+
get onUploadFile() {
|
|
333
|
+
return options.onUploadFile;
|
|
334
|
+
}
|
|
335
|
+
})));
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region src/tanstack-start/edit.tsx
|
|
340
|
+
var _tmpl$$2 = ["<button type=\"button\" class=\"btn btn-error btn-outline btn-sm self-start\">", "</button>"], _tmpl$2$2 = [
|
|
341
|
+
"<div class=\"flex flex-col gap-4\"><h1 class=\"text-xl font-semibold\">",
|
|
342
|
+
"</h1>",
|
|
343
|
+
"",
|
|
344
|
+
"</div>"
|
|
345
|
+
];
|
|
346
|
+
/**
|
|
347
|
+
* Builds an edit-page component for a collection — fetch, update, and
|
|
348
|
+
* delete, all wired together, plus a router-level unsaved-changes guard
|
|
349
|
+
* (`useBlocker`) driven by `CollectionEdit`'s `onDirtyChange`. See
|
|
350
|
+
* `createCollectionListPage`'s doc comment for the rationale on keeping
|
|
351
|
+
* navigation in the route file.
|
|
352
|
+
*/
|
|
353
|
+
function createCollectionEditPage(options) {
|
|
354
|
+
return function CollectionEditPage() {
|
|
355
|
+
const queryClient = useQueryClient();
|
|
356
|
+
const [error, setError] = createSignal();
|
|
357
|
+
const [dirty, setDirty] = createSignal(false);
|
|
358
|
+
const [latestDraftId, setLatestDraftId] = createSignal();
|
|
359
|
+
useBlocker({
|
|
360
|
+
shouldBlockFn: () => dirty(),
|
|
361
|
+
enableBeforeUnload: () => dirty()
|
|
362
|
+
});
|
|
363
|
+
const row = createQuery(() => ({
|
|
364
|
+
queryKey: options.queryKey(),
|
|
365
|
+
queryFn: options.queryFn
|
|
366
|
+
}));
|
|
367
|
+
const update = createMutation(() => ({
|
|
368
|
+
mutationFn: options.updateFn,
|
|
369
|
+
onSuccess: () => {
|
|
370
|
+
setError(void 0);
|
|
371
|
+
queryClient.invalidateQueries({ queryKey: options.invalidateQueryKey });
|
|
372
|
+
},
|
|
373
|
+
onError: (e) => setError(e.message)
|
|
374
|
+
}));
|
|
375
|
+
createMutation(() => ({
|
|
376
|
+
mutationFn: options.deleteFn,
|
|
377
|
+
onSuccess: () => {
|
|
378
|
+
queryClient.invalidateQueries({ queryKey: options.invalidateQueryKey });
|
|
379
|
+
options.onDeleted?.();
|
|
380
|
+
},
|
|
381
|
+
onError: (e) => setError(e.message)
|
|
382
|
+
}));
|
|
383
|
+
const saveDraft = createMutation(() => ({
|
|
384
|
+
mutationFn: (values) => options.draftActions?.saveDraftFn(values) ?? Promise.reject(/* @__PURE__ */ new Error("No draftActions configured")),
|
|
385
|
+
onSuccess: (draft) => {
|
|
386
|
+
setError(void 0);
|
|
387
|
+
setLatestDraftId(draft.id);
|
|
388
|
+
},
|
|
389
|
+
onError: (e) => setError(e.message)
|
|
390
|
+
}));
|
|
391
|
+
const publish = createMutation(() => ({
|
|
392
|
+
mutationFn: () => {
|
|
393
|
+
const versionId = latestDraftId();
|
|
394
|
+
if (versionId === void 0 || !options.draftActions) return Promise.reject(/* @__PURE__ */ new Error("No draft saved yet"));
|
|
395
|
+
return options.draftActions.publishFn(versionId);
|
|
396
|
+
},
|
|
397
|
+
onSuccess: () => {
|
|
398
|
+
setError(void 0);
|
|
399
|
+
queryClient.invalidateQueries({ queryKey: options.invalidateQueryKey });
|
|
400
|
+
},
|
|
401
|
+
onError: (e) => setError(e.message)
|
|
402
|
+
}));
|
|
403
|
+
const preview = createMutation(() => ({
|
|
404
|
+
mutationFn: () => {
|
|
405
|
+
const versionId = latestDraftId();
|
|
406
|
+
if (versionId === void 0 || !options.draftActions?.previewFn) return Promise.reject(/* @__PURE__ */ new Error("No draft saved yet"));
|
|
407
|
+
return options.draftActions.previewFn(versionId);
|
|
408
|
+
},
|
|
409
|
+
onSuccess: ({ url }) => {
|
|
410
|
+
setError(void 0);
|
|
411
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
412
|
+
},
|
|
413
|
+
onError: (e) => setError(e.message)
|
|
414
|
+
}));
|
|
415
|
+
return ssr(_tmpl$2$2, escape(options.label ?? `Edit ${options.collection.slug}`), escape(createComponent(Show, {
|
|
416
|
+
get when() {
|
|
417
|
+
return row.data;
|
|
418
|
+
},
|
|
419
|
+
get children() {
|
|
420
|
+
return createComponent(CollectionEdit, {
|
|
421
|
+
get config() {
|
|
422
|
+
return options.collection;
|
|
423
|
+
},
|
|
424
|
+
get initialValues() {
|
|
425
|
+
return row.data ?? void 0;
|
|
426
|
+
},
|
|
427
|
+
get submitLabel() {
|
|
428
|
+
return options.submitLabel ?? "Save changes";
|
|
429
|
+
},
|
|
430
|
+
get error() {
|
|
431
|
+
return error();
|
|
432
|
+
},
|
|
433
|
+
get saving() {
|
|
434
|
+
return update.isPending;
|
|
435
|
+
},
|
|
436
|
+
onSubmit: (values) => update.mutate(values),
|
|
437
|
+
get onUploadFile() {
|
|
438
|
+
return options.onUploadFile;
|
|
439
|
+
},
|
|
440
|
+
onDirtyChange: setDirty,
|
|
441
|
+
get capabilities() {
|
|
442
|
+
return options.capabilities?.();
|
|
443
|
+
},
|
|
444
|
+
get draftActions() {
|
|
445
|
+
return options.draftActions && {
|
|
446
|
+
onSaveDraft: (values) => saveDraft.mutate(values),
|
|
447
|
+
onPublish: () => publish.mutate(),
|
|
448
|
+
onPreview: options.draftActions.previewFn ? () => preview.mutate() : void 0,
|
|
449
|
+
saving: saveDraft.isPending,
|
|
450
|
+
publishing: publish.isPending,
|
|
451
|
+
previewing: preview.isPending,
|
|
452
|
+
canPublish: latestDraftId() !== void 0,
|
|
453
|
+
canPreview: latestDraftId() !== void 0,
|
|
454
|
+
saveDraftLabel: options.draftActions.saveDraftLabel,
|
|
455
|
+
publishLabel: options.draftActions.publishLabel,
|
|
456
|
+
previewLabel: options.draftActions.previewLabel
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
})), escape(createComponent(Show, {
|
|
462
|
+
get when() {
|
|
463
|
+
return options.capabilities?.()?.canDelete !== false;
|
|
464
|
+
},
|
|
465
|
+
get children() {
|
|
466
|
+
return ssr(_tmpl$$2, escape(options.deleteLabel ?? `Delete ${options.collection.slug}`));
|
|
467
|
+
}
|
|
468
|
+
})));
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region src/CollectionList.tsx
|
|
473
|
+
var _tmpl$$1 = ["<button type=\"button\" class=\"btn btn-outline btn-sm\">", "</button>"], _tmpl$2$1 = [
|
|
474
|
+
"<div class=\"join\"><select aria-label=\"Sort by\" class=\"select select-sm join-item\"",
|
|
475
|
+
">",
|
|
476
|
+
"</select><select aria-label=\"Sort direction\" class=\"select select-sm join-item\"",
|
|
477
|
+
"><option value=\"asc\">Ascending</option><option value=\"desc\">Descending</option></select></div>"
|
|
478
|
+
], _tmpl$3 = "<th></th>", _tmpl$4 = [
|
|
479
|
+
"<table class=\"table hidden md:table\"><thead><tr>",
|
|
480
|
+
"",
|
|
481
|
+
"</tr></thead><tbody>",
|
|
482
|
+
"</tbody></table>"
|
|
483
|
+
], _tmpl$5 = ["<div class=\"flex flex-col gap-2 md:hidden\">", "</div>"], _tmpl$6 = [
|
|
484
|
+
"<div class=\"bg-base-100 sticky bottom-0 flex items-center justify-between gap-2 border-t py-2\"><button type=\"button\" class=\"btn btn-sm\"",
|
|
485
|
+
">Prev</button><span class=\"text-sm opacity-70\">Page ",
|
|
486
|
+
"</span><button type=\"button\" class=\"btn btn-sm\"",
|
|
487
|
+
">Next</button></div>"
|
|
488
|
+
], _tmpl$7 = [
|
|
489
|
+
"<div class=\"flex flex-col gap-3\"><div class=\"flex flex-wrap items-center justify-between gap-2\">",
|
|
490
|
+
"",
|
|
491
|
+
"</div>",
|
|
492
|
+
"",
|
|
493
|
+
"</div>"
|
|
494
|
+
], _tmpl$8 = [
|
|
495
|
+
"<option",
|
|
496
|
+
">",
|
|
497
|
+
"</option>"
|
|
498
|
+
], _tmpl$9 = ["<p class=\"text-sm opacity-70\">No ", " yet.</p>"], _tmpl$0 = ["<th>", "</th>"], _tmpl$1 = ["<td><input type=\"checkbox\" class=\"checkbox checkbox-sm\"", "></td>"], _tmpl$10 = [
|
|
499
|
+
"<tr",
|
|
500
|
+
">",
|
|
501
|
+
"",
|
|
502
|
+
"</tr>"
|
|
503
|
+
], _tmpl$11 = ["<td>", "</td>"], _tmpl$12 = ["<input type=\"checkbox\" class=\"checkbox checkbox-sm mt-1\"", ">"], _tmpl$13 = [
|
|
504
|
+
"<div class=\"card bg-base-200 cursor-pointer p-3\" role=\"button\" tabindex=\"0\"><div class=\"flex items-start gap-3\">",
|
|
505
|
+
"<div class=\"flex flex-1 flex-col gap-1\">",
|
|
506
|
+
"</div></div></div>"
|
|
507
|
+
], _tmpl$14 = [
|
|
508
|
+
"<div class=\"flex justify-between gap-2 text-sm\"><span class=\"opacity-60\">",
|
|
509
|
+
"</span><span class=\"text-right\">",
|
|
510
|
+
"</span></div>"
|
|
511
|
+
];
|
|
512
|
+
function listableFields(config) {
|
|
513
|
+
const excluded = new Set([
|
|
514
|
+
"richText",
|
|
515
|
+
"array",
|
|
516
|
+
"relationship"
|
|
517
|
+
]);
|
|
518
|
+
return Object.entries(config.fields).filter(([key, field]) => key !== "id" && !excluded.has(field.type));
|
|
519
|
+
}
|
|
520
|
+
function formatCellValue(value) {
|
|
521
|
+
if (value === null || value === void 0) return "—";
|
|
522
|
+
if (value instanceof Date) return value.toLocaleDateString();
|
|
523
|
+
return String(value);
|
|
524
|
+
}
|
|
525
|
+
function rowId(row) {
|
|
526
|
+
return typeof row.id === "number" ? row.id : void 0;
|
|
527
|
+
}
|
|
528
|
+
function CollectionList(props) {
|
|
529
|
+
const columns = () => listableFields(props.config);
|
|
530
|
+
const [selectMode, setSelectMode] = createSignal(false);
|
|
531
|
+
return ssr(_tmpl$7, escape(createComponent(Show, {
|
|
532
|
+
get when() {
|
|
533
|
+
return props.selectable;
|
|
534
|
+
},
|
|
535
|
+
get children() {
|
|
536
|
+
return ssr(_tmpl$$1, selectMode() ? "Done" : "Select");
|
|
537
|
+
}
|
|
538
|
+
})), escape(createComponent(Show, {
|
|
539
|
+
get when() {
|
|
540
|
+
return props.onSortChange;
|
|
541
|
+
},
|
|
542
|
+
get children() {
|
|
543
|
+
return ssr(_tmpl$2$1, ssrAttribute("value", escape(props.sortField ?? "", true), false), escape(createComponent(For, {
|
|
544
|
+
get each() {
|
|
545
|
+
return columns();
|
|
546
|
+
},
|
|
547
|
+
children: ([key]) => ssr(_tmpl$8, ssrAttribute("value", escape(key, true), false), escape(key))
|
|
548
|
+
})), ssrAttribute("value", escape(props.sortDirection ?? "asc", true), false));
|
|
549
|
+
}
|
|
550
|
+
})), escape(createComponent(Show, {
|
|
551
|
+
get when() {
|
|
552
|
+
return props.rows.length > 0;
|
|
553
|
+
},
|
|
554
|
+
get fallback() {
|
|
555
|
+
return ssr(_tmpl$9, escape(props.config.slug));
|
|
556
|
+
},
|
|
557
|
+
get children() {
|
|
558
|
+
return [ssr(_tmpl$4, escape(createComponent(Show, {
|
|
559
|
+
get when() {
|
|
560
|
+
return selectMode();
|
|
561
|
+
},
|
|
562
|
+
get children() {
|
|
563
|
+
return ssr(_tmpl$3);
|
|
564
|
+
}
|
|
565
|
+
})), escape(createComponent(For, {
|
|
566
|
+
get each() {
|
|
567
|
+
return columns();
|
|
568
|
+
},
|
|
569
|
+
children: ([key]) => ssr(_tmpl$0, escape(key))
|
|
570
|
+
})), escape(createComponent(For, {
|
|
571
|
+
get each() {
|
|
572
|
+
return props.rows;
|
|
573
|
+
},
|
|
574
|
+
children: (row) => ssr(_tmpl$10, ssrAttribute("class", props.onRowClick || selectMode() ? "cursor-pointer hover" : escape(void 0, true), false), escape(createComponent(Show, {
|
|
575
|
+
get when() {
|
|
576
|
+
return selectMode();
|
|
577
|
+
},
|
|
578
|
+
get children() {
|
|
579
|
+
return ssr(_tmpl$1, ssrAttribute("checked", rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false), true));
|
|
580
|
+
}
|
|
581
|
+
})), escape(createComponent(For, {
|
|
582
|
+
get each() {
|
|
583
|
+
return columns();
|
|
584
|
+
},
|
|
585
|
+
children: ([key]) => ssr(_tmpl$11, escape(formatCellValue(row[key])))
|
|
586
|
+
})))
|
|
587
|
+
}))), ssr(_tmpl$5, escape(createComponent(For, {
|
|
588
|
+
get each() {
|
|
589
|
+
return props.rows;
|
|
590
|
+
},
|
|
591
|
+
children: (row) => ssr(_tmpl$13, escape(createComponent(Show, {
|
|
592
|
+
get when() {
|
|
593
|
+
return selectMode();
|
|
594
|
+
},
|
|
595
|
+
get children() {
|
|
596
|
+
return ssr(_tmpl$12, ssrAttribute("checked", rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false), true));
|
|
597
|
+
}
|
|
598
|
+
})), escape(createComponent(For, {
|
|
599
|
+
get each() {
|
|
600
|
+
return columns();
|
|
601
|
+
},
|
|
602
|
+
children: ([key]) => ssr(_tmpl$14, escape(key), escape(formatCellValue(row[key])))
|
|
603
|
+
})))
|
|
604
|
+
})))];
|
|
605
|
+
}
|
|
606
|
+
})), escape(createComponent(Show, {
|
|
607
|
+
get when() {
|
|
608
|
+
return props.page !== void 0 && props.pageSize !== void 0;
|
|
609
|
+
},
|
|
610
|
+
get children() {
|
|
611
|
+
return ssr(_tmpl$6, ssrAttribute("disabled", (props.page ?? 1) <= 1, true), escape(props.page), ssrAttribute("disabled", props.totalCount !== void 0 ? (props.page ?? 1) * (props.pageSize ?? 0) >= props.totalCount : props.rows.length < (props.pageSize ?? 0), true));
|
|
612
|
+
}
|
|
613
|
+
})));
|
|
614
|
+
}
|
|
615
|
+
//#endregion
|
|
616
|
+
//#region src/tanstack-start/list.tsx
|
|
617
|
+
var _tmpl$ = [
|
|
618
|
+
"<div class=\"flex flex-col gap-4\"><div class=\"flex items-center justify-between\"><h1 class=\"text-xl font-semibold\">",
|
|
619
|
+
"</h1>",
|
|
620
|
+
"</div>",
|
|
621
|
+
"</div>"
|
|
622
|
+
], _tmpl$2 = "<div class=\"loading loading-spinner\"></div>";
|
|
623
|
+
/**
|
|
624
|
+
* Builds a list-view page component for a collection — paginated/sortable
|
|
625
|
+
* query, loading state, and the generic table/card list, wired together.
|
|
626
|
+
* The returned component is meant to be passed directly as a route's
|
|
627
|
+
* `component`:
|
|
628
|
+
*
|
|
629
|
+
* ```tsx
|
|
630
|
+
* export const Route = createFileRoute('/admin/pages/')({
|
|
631
|
+
* component: createCollectionListPage({
|
|
632
|
+
* collection: pagesCollection,
|
|
633
|
+
* label: 'Pages',
|
|
634
|
+
* queryKey: ['pages'],
|
|
635
|
+
* queryFn: (params) => getPages({ data: params }),
|
|
636
|
+
* newHref: '/admin/pages/new',
|
|
637
|
+
* newLabel: 'New page',
|
|
638
|
+
* onRowClick: (row) => navigate({ to: '/admin/pages/$pageId', params: { pageId: String(row.id) } }),
|
|
639
|
+
* }),
|
|
640
|
+
* })
|
|
641
|
+
* ```
|
|
642
|
+
*
|
|
643
|
+
* Navigation stays in the route file (via `onRowClick`/`newHref` as plain
|
|
644
|
+
* strings) rather than this package calling `useNavigate()` itself —
|
|
645
|
+
* TanStack Router's route-typing is generated per-app, so a generic
|
|
646
|
+
* package can't produce a correctly-typed `navigate()` call for routes
|
|
647
|
+
* it doesn't know about.
|
|
648
|
+
*/
|
|
649
|
+
function createCollectionListPage(options) {
|
|
650
|
+
return function CollectionListPage() {
|
|
651
|
+
const pageSize = options.pageSize ?? 20;
|
|
652
|
+
const [page, setPage] = createSignal(1);
|
|
653
|
+
const [sortField, setSortField] = createSignal(void 0);
|
|
654
|
+
const [sortDirection, setSortDirection] = createSignal("asc");
|
|
655
|
+
const result = createQuery(() => ({
|
|
656
|
+
queryKey: [
|
|
657
|
+
...options.queryKey,
|
|
658
|
+
page(),
|
|
659
|
+
sortField(),
|
|
660
|
+
sortDirection()
|
|
661
|
+
],
|
|
662
|
+
queryFn: () => options.queryFn({
|
|
663
|
+
page: page(),
|
|
664
|
+
pageSize,
|
|
665
|
+
sortField: sortField(),
|
|
666
|
+
sortDirection: sortDirection()
|
|
667
|
+
})
|
|
668
|
+
}));
|
|
669
|
+
function handleSortChange(field, direction) {
|
|
670
|
+
setSortField(field);
|
|
671
|
+
setSortDirection(direction);
|
|
672
|
+
setPage(1);
|
|
673
|
+
}
|
|
674
|
+
return ssr(_tmpl$, escape(options.label ?? options.collection.slug), escape(createComponent(Show, {
|
|
675
|
+
get when() {
|
|
676
|
+
return options.newHref && options.capabilities?.()?.canCreate !== false;
|
|
677
|
+
},
|
|
678
|
+
get children() {
|
|
679
|
+
return createComponent(Link, {
|
|
680
|
+
get to() {
|
|
681
|
+
return options.newHref;
|
|
682
|
+
},
|
|
683
|
+
"class": "btn btn-primary btn-sm",
|
|
684
|
+
get children() {
|
|
685
|
+
return options.newLabel ?? `New ${options.collection.slug}`;
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
})), escape(createComponent(Show, {
|
|
690
|
+
get when() {
|
|
691
|
+
return !result.isLoading;
|
|
692
|
+
},
|
|
693
|
+
get fallback() {
|
|
694
|
+
return ssr(_tmpl$2);
|
|
695
|
+
},
|
|
696
|
+
get children() {
|
|
697
|
+
return createComponent(CollectionList, {
|
|
698
|
+
get config() {
|
|
699
|
+
return options.collection;
|
|
700
|
+
},
|
|
701
|
+
get rows() {
|
|
702
|
+
return result.data?.rows ?? [];
|
|
703
|
+
},
|
|
704
|
+
get onRowClick() {
|
|
705
|
+
return options.onRowClick;
|
|
706
|
+
},
|
|
707
|
+
get page() {
|
|
708
|
+
return page();
|
|
709
|
+
},
|
|
710
|
+
pageSize,
|
|
711
|
+
get totalCount() {
|
|
712
|
+
return result.data?.total;
|
|
713
|
+
},
|
|
714
|
+
onPageChange: setPage,
|
|
715
|
+
get sortField() {
|
|
716
|
+
return sortField();
|
|
717
|
+
},
|
|
718
|
+
get sortDirection() {
|
|
719
|
+
return sortDirection();
|
|
720
|
+
},
|
|
721
|
+
onSortChange: handleSortChange
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
})));
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
//#endregion
|
|
728
|
+
export { createCollectionCreatePage, createCollectionEditPage, createCollectionListPage };
|
|
729
|
+
|
|
730
|
+
//# sourceMappingURL=server.js.map
|