@thebes/cadmea 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
1
  import { createComponent, escape, ssr, ssrAttribute } from "solid-js/web";
2
2
  import { createMutation, createQuery, useQueryClient } from "@tanstack/solid-query";
3
- import { For, Index, Show, Suspense, createEffect, createSignal, lazy, onCleanup } from "solid-js";
3
+ import { For, Index, Show, Suspense, createEffect, createSignal, lazy, onCleanup, onMount } from "solid-js";
4
4
  import { createForm } from "@tanstack/solid-form";
5
- import { validateDocument } from "@thebes/cadmus/cms";
5
+ import { VISUAL_EDIT_MESSAGE, validateDocument } from "@thebes/cadmus/cms";
6
6
  import { Link, useBlocker } from "@tanstack/solid-router";
7
7
  import { createSolidTable, flexRender, getCoreRowModel } from "@tanstack/solid-table";
8
8
  //#region src/CollectionEdit.tsx
9
- 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 = [
9
+ var _tmpl$$5 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmpl$2$3 = "<span class=\"loading loading-spinner loading-sm\"></span>", _tmpl$3$3 = [
10
10
  "<button type=\"button\" class=\"btn flex-1\"",
11
11
  ">",
12
12
  "</button>"
13
- ], _tmpl$4$1 = [
13
+ ], _tmpl$4$2 = [
14
14
  "<button type=\"button\" class=\"btn btn-primary flex-1\"",
15
15
  ">",
16
16
  "</button>"
@@ -22,16 +22,17 @@ var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmp
22
22
  "<span class=\"text-base-content/60 self-center px-1 text-xs\" aria-live=\"polite\">",
23
23
  "",
24
24
  "</span>"
25
- ], _tmpl$7$1 = [
25
+ ], _tmpl$7$1 = "<div class=\"modal modal-open\" role=\"dialog\" aria-modal=\"true\"><div class=\"modal-box\"><h3 class=\"text-lg font-semibold\">Publish changes?</h3><p class=\"text-base-content/70 py-2 text-sm\">Your latest saved draft will go live on the site.</p><div class=\"modal-action\"><button type=\"button\" class=\"btn btn-ghost\">Cancel</button><button type=\"button\" class=\"btn btn-primary\">Publish</button></div></div><button type=\"button\" class=\"modal-backdrop\" aria-label=\"Cancel\"></button></div>", _tmpl$8$1 = [
26
26
  "<form class=\"flex flex-col gap-4\">",
27
27
  "",
28
28
  "<div class=\"bg-base-100 sticky bottom-0 flex gap-2 border-t py-3\">",
29
- "</div></form>"
30
- ], _tmpl$8$1 = [
29
+ "</div>",
30
+ "</form>"
31
+ ], _tmpl$9$1 = [
31
32
  "<fieldset class=\"border-base-300 rounded-box border p-4\"><legend class=\"px-2 text-sm font-semibold\">",
32
33
  "</legend>",
33
34
  "</fieldset>"
34
- ], _tmpl$9$1 = ["<div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">", "</div>"], _tmpl$0$1 = "<span class=\"text-error\"> *</span>", _tmpl$1$1 = ["<p class=\"text-base-content/60 mb-1 text-xs\">", "</p>"], _tmpl$10$1 = ["<p class=\"text-error mt-1 text-sm\" role=\"alert\">", "</p>"], _tmpl$11$1 = [
35
+ ], _tmpl$0$1 = ["<div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">", "</div>"], _tmpl$1$1 = "<span class=\"text-error\"> *</span>", _tmpl$10$1 = ["<p class=\"text-base-content/60 mb-1 text-xs\">", "</p>"], _tmpl$11$1 = ["<p class=\"text-error mt-1 text-sm\" role=\"alert\">", "</p>"], _tmpl$12$1 = [
35
36
  "<div class=\"",
36
37
  "\"><label class=\"label\"",
37
38
  ">",
@@ -40,37 +41,37 @@ var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmp
40
41
  "",
41
42
  "",
42
43
  "</div>"
43
- ], _tmpl$12$1 = [
44
+ ], _tmpl$13$1 = [
44
45
  "<input",
45
46
  " class=\"input\" type=\"text\"",
46
47
  "",
47
48
  ">"
48
- ], _tmpl$13$1 = [
49
+ ], _tmpl$14$1 = [
49
50
  "<select",
50
51
  " class=\"select\"",
51
52
  "",
52
53
  "",
53
54
  ">",
54
55
  "</select>"
55
- ], _tmpl$14$1 = [
56
+ ], _tmpl$15$1 = [
56
57
  "<option",
57
58
  ">",
58
59
  "</option>"
59
- ], _tmpl$15$1 = [
60
+ ], _tmpl$16 = [
60
61
  "<input",
61
62
  " class=\"input\" type=\"number\"",
62
63
  "",
63
64
  ">"
64
- ], _tmpl$16 = [
65
+ ], _tmpl$17 = [
65
66
  "<input",
66
67
  " class=\"input\" type=\"text\" readonly",
67
68
  ">"
68
- ], _tmpl$17 = [
69
+ ], _tmpl$18 = [
69
70
  "<input",
70
71
  " class=\"checkbox\" type=\"checkbox\"",
71
72
  "",
72
73
  ">"
73
- ], _tmpl$18 = ["<p class=\"text-sm opacity-70 break-all\">", "</p>"], _tmpl$19 = ["<p class=\"text-sm text-error\">", "</p>"], _tmpl$20 = [
74
+ ], _tmpl$19 = ["<p class=\"text-sm opacity-70 break-all\">", "</p>"], _tmpl$20 = ["<p class=\"text-sm text-error\">", "</p>"], _tmpl$21 = [
74
75
  "<div class=\"flex flex-col gap-2\">",
75
76
  "<input",
76
77
  " class=\"file-input\" type=\"file\"",
@@ -78,11 +79,11 @@ var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmp
78
79
  ">",
79
80
  "",
80
81
  "</div>"
81
- ], _tmpl$21 = ["<div class=\"mb-1 flex flex-wrap gap-1\">", "</div>"], _tmpl$22 = "<button type=\"button\" aria-label=\"Clear\" class=\"absolute top-2 right-2 cursor-pointer opacity-60\">×</button>", _tmpl$23 = [
82
+ ], _tmpl$22 = ["<div class=\"mb-1 flex flex-wrap gap-1\">", "</div>"], _tmpl$23 = "<button type=\"button\" aria-label=\"Clear\" class=\"absolute top-2 right-2 cursor-pointer opacity-60\">×</button>", _tmpl$24 = [
82
83
  "<div",
83
84
  " role=\"listbox\" class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex max-h-56 w-full flex-col overflow-auto border p-1 shadow\">",
84
85
  "</div>"
85
- ], _tmpl$24 = [
86
+ ], _tmpl$25 = [
86
87
  "<div class=\"relative\">",
87
88
  "<input",
88
89
  " type=\"text\" role=\"combobox\"",
@@ -91,27 +92,27 @@ var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmp
91
92
  ">",
92
93
  "",
93
94
  "</div>"
94
- ], _tmpl$25 = [
95
+ ], _tmpl$26 = [
95
96
  "<span class=\"badge badge-primary gap-1\">",
96
97
  "<button type=\"button\" aria-label=\"",
97
98
  "\" class=\"cursor-pointer\">×</button></span>"
98
- ], _tmpl$26 = [
99
+ ], _tmpl$27 = [
99
100
  "<button type=\"button\" role=\"option\"",
100
101
  " class=\"",
101
102
  "\">",
102
103
  "</button>"
103
- ], _tmpl$27 = ["<div role=\"menu\" class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex flex-col border p-1 shadow\">", "</div>"], _tmpl$28 = [
104
+ ], _tmpl$28 = ["<div role=\"menu\" class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex flex-col border p-1 shadow\">", "</div>"], _tmpl$29 = [
104
105
  "<div class=\"relative self-start\"><button type=\"button\" class=\"btn btn-outline btn-sm\" aria-haspopup=\"menu\"",
105
106
  ">Add block</button>",
106
107
  "</div>"
107
- ], _tmpl$29 = [
108
+ ], _tmpl$30 = [
108
109
  "<div class=\"form-control md:col-span-2\"><div class=\"label font-medium\">",
109
110
  "",
110
111
  "</div>",
111
112
  "<div class=\"flex flex-col gap-3\">",
112
113
  "",
113
114
  "</div></div>"
114
- ], _tmpl$30 = ["<span class=\"text-base-content/60 truncate text-sm\">", "</span>"], _tmpl$31 = ["<div class=\"flex flex-col gap-2\">", "</div>"], _tmpl$32 = [
115
+ ], _tmpl$31 = ["<span class=\"text-base-content/60 truncate text-sm\">", "</span>"], _tmpl$32 = ["<div class=\"flex flex-col gap-2\">", "</div>"], _tmpl$33 = [
115
116
  "<div class=\"card bg-base-200 flex flex-col gap-2 p-3\"><div class=\"flex items-center gap-2\"><button type=\"button\" class=\"btn btn-ghost btn-sm gap-2\"",
116
117
  "><span aria-hidden=\"true\">",
117
118
  "</span><span class=\"font-semibold\">",
@@ -120,7 +121,7 @@ var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmp
120
121
  ">↑</button><button type=\"button\" class=\"btn btn-ghost btn-xs\" aria-label=\"Move down\"",
121
122
  ">↓</button><button type=\"button\" class=\"btn btn-ghost btn-xs\" aria-label=\"Duplicate\">⧉</button><button type=\"button\" class=\"btn btn-ghost btn-xs text-error\" aria-label=\"Remove\">Remove</button></div></div>",
122
123
  "</div>"
123
- ], _tmpl$33 = ["<button type=\"button\" class=\"btn btn-outline btn-sm self-start\">Add ", "</button>"], _tmpl$34 = ["<i", " aria-hidden=\"true\"></i>"], _tmpl$35 = [
124
+ ], _tmpl$34 = ["<button type=\"button\" class=\"btn btn-outline btn-sm self-start\">Add ", "</button>"], _tmpl$35 = ["<i", " aria-hidden=\"true\"></i>"], _tmpl$36 = [
124
125
  "<button type=\"button\" role=\"menuitem\" class=\"flex items-center gap-2 rounded px-3 py-2 text-left\">",
125
126
  "",
126
127
  "</button>"
@@ -190,6 +191,7 @@ function CollectionEdit(props) {
190
191
  const fieldGroups = groupFields(editableFields(props.config));
191
192
  const versioned = () => props.config.versions?.drafts && props.draftActions;
192
193
  const [autosaveStatus, setAutosaveStatus] = createSignal("idle");
194
+ const [confirmingPublish, setConfirmingPublish] = createSignal(false);
193
195
  let autosaveTimer;
194
196
  createEffect(() => {
195
197
  const dirty = !isDefaultValue();
@@ -211,12 +213,12 @@ function CollectionEdit(props) {
211
213
  }, props.draftActions?.autosaveMs ?? 1500);
212
214
  });
213
215
  onCleanup(() => clearTimeout(autosaveTimer));
214
- return ssr(_tmpl$7$1, escape(createComponent(Show, {
216
+ return ssr(_tmpl$8$1, escape(createComponent(Show, {
215
217
  get when() {
216
218
  return props.error;
217
219
  },
218
220
  get children() {
219
- return ssr(_tmpl$$4, escape(props.error));
221
+ return ssr(_tmpl$$5, escape(props.error));
220
222
  }
221
223
  })), escape(createComponent(For, {
222
224
  each: fieldGroups,
@@ -235,7 +237,7 @@ function CollectionEdit(props) {
235
237
  });
236
238
  },
237
239
  get children() {
238
- return ssr(_tmpl$8$1, escape(group.name), escape(createComponent(FieldsGrid, {
240
+ return ssr(_tmpl$9$1, escape(group.name), escape(createComponent(FieldsGrid, {
239
241
  form,
240
242
  ctx,
241
243
  get fields() {
@@ -255,7 +257,7 @@ function CollectionEdit(props) {
255
257
  return props.capabilities?.canUpdate !== false;
256
258
  },
257
259
  get children() {
258
- return ssr(_tmpl$4$1, ssrAttribute("disabled", props.saving, true), escape(createComponent(Show, {
260
+ return ssr(_tmpl$4$2, ssrAttribute("disabled", props.saving, true), escape(createComponent(Show, {
259
261
  get when() {
260
262
  return props.saving;
261
263
  },
@@ -271,7 +273,7 @@ function CollectionEdit(props) {
271
273
  },
272
274
  get children() {
273
275
  return [
274
- ssr(_tmpl$3$1, ssrAttribute("disabled", props.draftActions?.saving, true), escape(createComponent(Show, {
276
+ ssr(_tmpl$3$3, ssrAttribute("disabled", props.draftActions?.saving, true), escape(createComponent(Show, {
275
277
  get when() {
276
278
  return props.draftActions?.saving;
277
279
  },
@@ -282,7 +284,7 @@ function CollectionEdit(props) {
282
284
  return ssr(_tmpl$2$3);
283
285
  }
284
286
  }))),
285
- ssr(_tmpl$4$1, ssrAttribute("disabled", !props.draftActions?.canPublish || props.draftActions?.publishing, true), escape(createComponent(Show, {
287
+ ssr(_tmpl$4$2, ssrAttribute("disabled", !props.draftActions?.canPublish || props.draftActions?.publishing, true), escape(createComponent(Show, {
286
288
  get when() {
287
289
  return props.draftActions?.publishing;
288
290
  },
@@ -331,10 +333,17 @@ function CollectionEdit(props) {
331
333
  })
332
334
  ];
333
335
  }
336
+ })), escape(createComponent(Show, {
337
+ get when() {
338
+ return confirmingPublish();
339
+ },
340
+ get children() {
341
+ return ssr(_tmpl$7$1);
342
+ }
334
343
  })));
335
344
  }
336
345
  function FieldsGrid(props) {
337
- return ssr(_tmpl$9$1, escape(createComponent(For, {
346
+ return ssr(_tmpl$0$1, escape(createComponent(For, {
338
347
  get each() {
339
348
  return props.fields;
340
349
  },
@@ -353,26 +362,26 @@ function renderField(form, ctx, name, field, label) {
353
362
  const spanClass = field.admin?.width === "half" ? "md:col-span-1" : "md:col-span-2";
354
363
  return createComponent(form.Field, {
355
364
  name,
356
- children: (fieldApi) => ssr(_tmpl$11$1, `form-control ${escape(spanClass, true)}`, ssrAttribute("for", escape(name, true), false), escape(label), escape(createComponent(Show, {
365
+ children: (fieldApi) => ssr(_tmpl$12$1, `form-control ${escape(spanClass, true)}`, ssrAttribute("for", escape(name, true), false), escape(label), escape(createComponent(Show, {
357
366
  get when() {
358
367
  return field.required;
359
368
  },
360
369
  get children() {
361
- return ssr(_tmpl$0$1);
370
+ return ssr(_tmpl$1$1);
362
371
  }
363
372
  })), escape(createComponent(Show, {
364
373
  get when() {
365
374
  return field.admin?.description;
366
375
  },
367
376
  get children() {
368
- return ssr(_tmpl$1$1, escape(field.admin?.description));
377
+ return ssr(_tmpl$10$1, escape(field.admin?.description));
369
378
  }
370
379
  })), escape(renderControl(ctx, name, field, fieldApi)), escape(createComponent(Show, {
371
380
  get when() {
372
381
  return (fieldApi().state.meta.errors?.length ?? 0) > 0;
373
382
  },
374
383
  get children() {
375
- return ssr(_tmpl$10$1, escape(fieldApi().state.meta.errors.filter(Boolean).join(", ")));
384
+ return ssr(_tmpl$11$1, escape(fieldApi().state.meta.errors.filter(Boolean).join(", ")));
376
385
  }
377
386
  })))
378
387
  });
@@ -392,16 +401,16 @@ function renderControl(ctx, name, field, fieldApi) {
392
401
  const readOnly = field.admin?.readOnly;
393
402
  const change = (v) => fieldApi().handleChange(v);
394
403
  switch (field.type) {
395
- case "text": return ssr(_tmpl$12$1, ssrAttribute("id", escape(name, true), false), ssrAttribute("placeholder", escape(field.admin?.placeholder, true), false) + ssrAttribute("readonly", escape(readOnly, true), false) + ssrAttribute("value", escape(fieldApi().state.value ?? "", true), false), ssrAttribute("required", field.required, true));
396
- case "select": return ssr(_tmpl$13$1, ssrAttribute("id", escape(name, true), false), ssrAttribute("value", escape(fieldApi().state.value ?? "", true), false), ssrAttribute("required", field.required, true), ssrAttribute("disabled", readOnly, true), escape(createComponent(For, {
404
+ case "text": return ssr(_tmpl$13$1, ssrAttribute("id", escape(name, true), false), ssrAttribute("placeholder", escape(field.admin?.placeholder, true), false) + ssrAttribute("readonly", escape(readOnly, true), false) + ssrAttribute("value", escape(fieldApi().state.value ?? "", true), false), ssrAttribute("required", field.required, true));
405
+ case "select": return ssr(_tmpl$14$1, ssrAttribute("id", escape(name, true), false), ssrAttribute("value", escape(fieldApi().state.value ?? "", true), false), ssrAttribute("required", field.required, true), ssrAttribute("disabled", readOnly, true), escape(createComponent(For, {
397
406
  get each() {
398
407
  return field.options;
399
408
  },
400
- children: (option) => ssr(_tmpl$14$1, ssrAttribute("value", escape(option, true), false), escape(option))
409
+ children: (option) => ssr(_tmpl$15$1, ssrAttribute("value", escape(option, true), false), escape(option))
401
410
  })));
402
- case "number": return ssr(_tmpl$15$1, ssrAttribute("id", escape(name, true), false), ssrAttribute("placeholder", escape(field.admin?.placeholder, true), false) + ssrAttribute("readonly", escape(readOnly, true), false) + ssrAttribute("value", escape(fieldApi().state.value ?? "", true), false), ssrAttribute("required", field.required, true));
403
- case "date": return ssr(_tmpl$16, ssrAttribute("id", escape(name, true), false), ssrAttribute("value", escape(formatDateValue(fieldApi().state.value), true), false));
404
- case "checkbox": return ssr(_tmpl$17, ssrAttribute("id", escape(name, true), false), ssrAttribute("disabled", readOnly, true), ssrAttribute("checked", fieldApi().state.value ?? false, true));
411
+ case "number": return ssr(_tmpl$16, ssrAttribute("id", escape(name, true), false), ssrAttribute("placeholder", escape(field.admin?.placeholder, true), false) + ssrAttribute("readonly", escape(readOnly, true), false) + ssrAttribute("value", escape(fieldApi().state.value ?? "", true), false), ssrAttribute("required", field.required, true));
412
+ case "date": return ssr(_tmpl$17, ssrAttribute("id", escape(name, true), false), ssrAttribute("value", escape(formatDateValue(fieldApi().state.value), true), false));
413
+ case "checkbox": return ssr(_tmpl$18, ssrAttribute("id", escape(name, true), false), ssrAttribute("disabled", readOnly, true), ssrAttribute("checked", fieldApi().state.value ?? false, true));
405
414
  case "upload": return createComponent(UploadControl, {
406
415
  name,
407
416
  field,
@@ -440,12 +449,12 @@ function UploadControl(props) {
440
449
  const [uploading, setUploading] = createSignal(false);
441
450
  const [uploadError, setUploadError] = createSignal();
442
451
  const value = () => props.fieldApi().state.value;
443
- return ssr(_tmpl$20, escape(createComponent(Show, {
452
+ return ssr(_tmpl$21, escape(createComponent(Show, {
444
453
  get when() {
445
454
  return value();
446
455
  },
447
456
  get children() {
448
- return ssr(_tmpl$18, escape(value()));
457
+ return ssr(_tmpl$19, escape(value()));
449
458
  }
450
459
  })), ssrAttribute("id", escape(props.name, true), false), ssrAttribute("required", props.field.required && !value(), true), ssrAttribute("disabled", uploading() || props.field.admin?.readOnly, true), escape(createComponent(Show, {
451
460
  get when() {
@@ -459,7 +468,7 @@ function UploadControl(props) {
459
468
  return uploadError();
460
469
  },
461
470
  get children() {
462
- return ssr(_tmpl$19, escape(uploadError()));
471
+ return ssr(_tmpl$20, escape(uploadError()));
463
472
  }
464
473
  })));
465
474
  }
@@ -481,16 +490,16 @@ function RelationshipField(props) {
481
490
  return props.options.filter((o) => o.label.toLowerCase().includes(q) && (!isMulti() || !selectedIds().includes(o.id)));
482
491
  };
483
492
  const singleLabel = () => selectedOptions()[0]?.label ?? "";
484
- return ssr(_tmpl$24, escape(createComponent(Show, {
493
+ return ssr(_tmpl$25, escape(createComponent(Show, {
485
494
  get when() {
486
495
  return isMulti() && selectedOptions().length > 0;
487
496
  },
488
497
  get children() {
489
- return ssr(_tmpl$21, escape(createComponent(For, {
498
+ return ssr(_tmpl$22, escape(createComponent(For, {
490
499
  get each() {
491
500
  return selectedOptions();
492
501
  },
493
- children: (option) => ssr(_tmpl$25, escape(option.label), `Remove ${escape(option.label, true)}`)
502
+ children: (option) => ssr(_tmpl$26, escape(option.label), `Remove ${escape(option.label, true)}`)
494
503
  })));
495
504
  }
496
505
  })), ssrAttribute("id", escape(props.name, true), false), ssrAttribute("aria-expanded", escape(open(), true), false) + ssrAttribute("aria-controls", escape(listId, true), false), ssrAttribute("required", props.field.required && selectedIds().length === 0, true), ssrAttribute("disabled", props.field.admin?.readOnly, true) + ssrAttribute("placeholder", escape(props.field.admin?.placeholder ?? "Search…", true), false) + ssrAttribute("value", open() || isMulti() ? escape(query(), true) : escape(singleLabel(), true), false), escape(createComponent(Show, {
@@ -498,18 +507,18 @@ function RelationshipField(props) {
498
507
  return !isMulti() && value() != null && !props.field.required;
499
508
  },
500
509
  get children() {
501
- return ssr(_tmpl$22);
510
+ return ssr(_tmpl$23);
502
511
  }
503
512
  })), escape(createComponent(Show, {
504
513
  get when() {
505
514
  return open() && filtered().length > 0;
506
515
  },
507
516
  get children() {
508
- return ssr(_tmpl$23, ssrAttribute("id", escape(listId, true), false), escape(createComponent(For, {
517
+ return ssr(_tmpl$24, ssrAttribute("id", escape(listId, true), false), escape(createComponent(For, {
509
518
  get each() {
510
519
  return filtered();
511
520
  },
512
- children: (option, i) => ssr(_tmpl$26, ssrAttribute("aria-selected", escape(selectedIds().includes(option.id), true), false), `rounded px-3 py-2 text-left ${i() === active() ? "bg-base-200" : ""}`, escape(option.label))
521
+ children: (option, i) => ssr(_tmpl$27, ssrAttribute("aria-selected", escape(selectedIds().includes(option.id), true), false), `rounded px-3 py-2 text-left ${i() === active() ? "bg-base-200" : ""}`, escape(option.label))
513
522
  })));
514
523
  }
515
524
  })));
@@ -551,19 +560,19 @@ function BlockEditor(props) {
551
560
  }
552
561
  return "";
553
562
  }
554
- return ssr(_tmpl$29, escape(props.label), escape(createComponent(Show, {
563
+ return ssr(_tmpl$30, escape(props.label), escape(createComponent(Show, {
555
564
  get when() {
556
565
  return props.field.required;
557
566
  },
558
567
  get children() {
559
- return ssr(_tmpl$0$1);
568
+ return ssr(_tmpl$1$1);
560
569
  }
561
570
  })), escape(createComponent(Show, {
562
571
  get when() {
563
572
  return props.field.admin?.description;
564
573
  },
565
574
  get children() {
566
- return ssr(_tmpl$1$1, escape(props.field.admin?.description));
575
+ return ssr(_tmpl$10$1, escape(props.field.admin?.description));
567
576
  }
568
577
  })), escape(createComponent(Index, {
569
578
  get each() {
@@ -571,19 +580,19 @@ function BlockEditor(props) {
571
580
  },
572
581
  children: (item, index) => {
573
582
  const isCollapsed = () => collapsed().has(index);
574
- return ssr(_tmpl$32, ssrAttribute("aria-expanded", !isCollapsed(), false), isCollapsed() ? "▸" : "▾", escape(blockTitle(item())), escape(createComponent(Show, {
583
+ return ssr(_tmpl$33, ssrAttribute("aria-expanded", !isCollapsed(), false), isCollapsed() ? "▸" : "▾", escape(blockTitle(item())), escape(createComponent(Show, {
575
584
  get when() {
576
585
  return isCollapsed() && blockSummary(item());
577
586
  },
578
587
  get children() {
579
- return ssr(_tmpl$30, escape(blockSummary(item())));
588
+ return ssr(_tmpl$31, escape(blockSummary(item())));
580
589
  }
581
590
  })), ssrAttribute("disabled", index === 0, true), ssrAttribute("disabled", index === items().length - 1, true), escape(createComponent(Show, {
582
591
  get when() {
583
592
  return !isCollapsed();
584
593
  },
585
594
  get children() {
586
- return ssr(_tmpl$31, escape(createComponent(For, {
595
+ return ssr(_tmpl$32, escape(createComponent(For, {
587
596
  get each() {
588
597
  return fieldsForItem(props.field, item());
589
598
  },
@@ -597,22 +606,22 @@ function BlockEditor(props) {
597
606
  return disc && variants.length > 0;
598
607
  },
599
608
  get fallback() {
600
- return ssr(_tmpl$33, escape(props.label));
609
+ return ssr(_tmpl$34, escape(props.label));
601
610
  },
602
611
  get children() {
603
- return ssr(_tmpl$28, ssrAttribute("aria-expanded", escape(menuOpen(), true), false), escape(createComponent(Show, {
612
+ return ssr(_tmpl$29, ssrAttribute("aria-expanded", escape(menuOpen(), true), false), escape(createComponent(Show, {
604
613
  get when() {
605
614
  return menuOpen();
606
615
  },
607
616
  get children() {
608
- return ssr(_tmpl$27, escape(createComponent(For, {
617
+ return ssr(_tmpl$28, escape(createComponent(For, {
609
618
  each: variants,
610
- children: (variant) => ssr(_tmpl$35, escape(createComponent(Show, {
619
+ children: (variant) => ssr(_tmpl$36, escape(createComponent(Show, {
611
620
  get when() {
612
621
  return disc?.variantsAdmin?.[variant]?.icon;
613
622
  },
614
623
  get children() {
615
- return ssr(_tmpl$34, ssrAttribute("class", escape(disc?.variantsAdmin?.[variant]?.icon, true), false));
624
+ return ssr(_tmpl$35, ssrAttribute("class", escape(disc?.variantsAdmin?.[variant]?.icon, true), false));
616
625
  }
617
626
  })), escape(variantLabel(disc, variant)))
618
627
  })));
@@ -636,7 +645,7 @@ function formatDateValue(value) {
636
645
  }
637
646
  //#endregion
638
647
  //#region src/tanstack-start/create.tsx
639
- var _tmpl$$3 = [
648
+ var _tmpl$$4 = [
640
649
  "<div class=\"flex flex-col gap-4\"><h1 class=\"text-xl font-semibold\">",
641
650
  "</h1>",
642
651
  "</div>"
@@ -658,7 +667,7 @@ function createCollectionCreatePage(options) {
658
667
  },
659
668
  onError: (e) => setError(e.message)
660
669
  }));
661
- return ssr(_tmpl$$3, escape(options.label ?? `New ${options.collection.slug}`), escape(createComponent(CollectionEdit, {
670
+ return ssr(_tmpl$$4, escape(options.label ?? `New ${options.collection.slug}`), escape(createComponent(CollectionEdit, {
662
671
  get config() {
663
672
  return options.collection;
664
673
  },
@@ -679,13 +688,44 @@ function createCollectionCreatePage(options) {
679
688
  };
680
689
  }
681
690
  //#endregion
691
+ //#region src/VisualEditingPane.tsx
692
+ var _tmpl$$3 = ["<iframe", "></iframe>"];
693
+ function originOf(url) {
694
+ try {
695
+ return new URL(url).origin;
696
+ } catch {
697
+ return;
698
+ }
699
+ }
700
+ function VisualEditingPane(props) {
701
+ onMount(() => {
702
+ const expected = props.allowedOrigin ?? originOf(props.src);
703
+ const handler = (event) => {
704
+ if (expected && event.origin !== expected) return;
705
+ const data = event.data;
706
+ if (data?.type === VISUAL_EDIT_MESSAGE && data.ref) props.onEdit?.(data.ref);
707
+ };
708
+ window.addEventListener("message", handler);
709
+ onCleanup(() => window.removeEventListener("message", handler));
710
+ });
711
+ createEffect(() => {
712
+ props.previewValues;
713
+ props.previewTarget;
714
+ });
715
+ return ssr(_tmpl$$3, ssrAttribute("src", escape(props.src, true), false) + ssrAttribute("title", escape(props.title ?? "Preview", true), false) + ssrAttribute("class", escape(props.class ?? "h-full w-full border-0", true), false));
716
+ }
717
+ //#endregion
682
718
  //#region src/tanstack-start/edit.tsx
683
719
  var _tmpl$$2 = ["<button type=\"button\" class=\"btn btn-error btn-outline btn-sm self-start\">", "</button>"], _tmpl$2$2 = [
684
720
  "<div class=\"flex flex-col gap-4\"><h1 class=\"text-xl font-semibold\">",
685
721
  "</h1>",
686
722
  "",
687
723
  "</div>"
688
- ];
724
+ ], _tmpl$3$2 = [
725
+ "<div class=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">",
726
+ "",
727
+ "</div>"
728
+ ], _tmpl$4$1 = ["<div class=\"lg:sticky lg:top-4 lg:h-[calc(100vh-2rem)]\">", "</div>"];
689
729
  /**
690
730
  * Builds an edit-page component for a collection — fetch, update, and
691
731
  * delete, all wired together, plus a router-level unsaved-changes guard
@@ -699,6 +739,7 @@ function createCollectionEditPage(options) {
699
739
  const [error, setError] = createSignal();
700
740
  const [dirty, setDirty] = createSignal(false);
701
741
  const [latestDraftId, setLatestDraftId] = createSignal();
742
+ const [previewValues, setPreviewValues] = createSignal({});
702
743
  useBlocker({
703
744
  shouldBlockFn: () => dirty(),
704
745
  enableBeforeUnload: () => dirty()
@@ -755,7 +796,7 @@ function createCollectionEditPage(options) {
755
796
  },
756
797
  onError: (e) => setError(e.message)
757
798
  }));
758
- return ssr(_tmpl$2$2, escape(options.label ?? `Edit ${options.collection.slug}`), escape(createComponent(Show, {
799
+ const EditorPane = () => ssr(_tmpl$2$2, escape(options.label ?? `Edit ${options.collection.slug}`), escape(createComponent(Show, {
759
800
  get when() {
760
801
  return row.data;
761
802
  },
@@ -784,6 +825,7 @@ function createCollectionEditPage(options) {
784
825
  return options.fieldWidgets;
785
826
  },
786
827
  onDirtyChange: setDirty,
828
+ onValuesChange: setPreviewValues,
787
829
  get capabilities() {
788
830
  return options.capabilities?.();
789
831
  },
@@ -799,7 +841,8 @@ function createCollectionEditPage(options) {
799
841
  canPreview: latestDraftId() !== void 0,
800
842
  saveDraftLabel: options.draftActions.saveDraftLabel,
801
843
  publishLabel: options.draftActions.publishLabel,
802
- previewLabel: options.draftActions.previewLabel
844
+ previewLabel: options.draftActions.previewLabel,
845
+ autosave: options.draftActions.autosave
803
846
  };
804
847
  }
805
848
  });
@@ -812,6 +855,40 @@ function createCollectionEditPage(options) {
812
855
  return ssr(_tmpl$$2, escape(options.deleteLabel ?? `Delete ${options.collection.slug}`));
813
856
  }
814
857
  })));
858
+ return createComponent(Show, {
859
+ get when() {
860
+ return options.preview;
861
+ },
862
+ get fallback() {
863
+ return createComponent(EditorPane, {});
864
+ },
865
+ get children() {
866
+ return ssr(_tmpl$3$2, escape(createComponent(EditorPane, {})), escape(createComponent(Show, {
867
+ get when() {
868
+ return options.preview?.url();
869
+ },
870
+ children: (url) => ssr(_tmpl$4$1, escape(createComponent(VisualEditingPane, {
871
+ get src() {
872
+ return url();
873
+ },
874
+ get allowedOrigin() {
875
+ return options.preview?.allowedOrigin?.();
876
+ },
877
+ get previewValues() {
878
+ return previewValues();
879
+ },
880
+ get previewTarget() {
881
+ return {
882
+ collection: options.collection.slug,
883
+ id: Number(row.data?.id)
884
+ };
885
+ },
886
+ "class": "border-base-300 rounded-box h-full w-full border",
887
+ title: "Live preview"
888
+ })))
889
+ })));
890
+ }
891
+ });
815
892
  };
816
893
  }
817
894
  //#endregion
@@ -821,7 +898,7 @@ var _tmpl$$1 = ["<button type=\"button\" class=\"btn btn-outline btn-sm\">", "</
821
898
  ">",
822
899
  "</select><select aria-label=\"Sort direction\" class=\"select select-sm join-item\"",
823
900
  "><option value=\"asc\">Ascending</option><option value=\"desc\">Descending</option></select></div>"
824
- ], _tmpl$3 = [
901
+ ], _tmpl$3$1 = [
825
902
  "<table class=\"table hidden md:table\"><thead>",
826
903
  "</thead><tbody>",
827
904
  "</tbody></table>"
@@ -840,7 +917,7 @@ var _tmpl$$1 = ["<button type=\"button\" class=\"btn btn-outline btn-sm\">", "</
840
917
  "<option",
841
918
  ">",
842
919
  "</option>"
843
- ], _tmpl$8 = ["<p class=\"text-sm opacity-70\">No ", " yet.</p>"], _tmpl$9 = "<th></th>", _tmpl$0 = [
920
+ ], _tmpl$8 = ["<div class=\"border-base-300 rounded-box flex flex-col items-center gap-1 border border-dashed py-12 text-center\"><p class=\"text-base-content/70 m-0\">No ", " yet.</p></div>"], _tmpl$9 = "<th></th>", _tmpl$0 = [
844
921
  "<tr>",
845
922
  "",
846
923
  "</tr>"
@@ -915,10 +992,10 @@ function CollectionList(props) {
915
992
  return props.rows.length > 0;
916
993
  },
917
994
  get fallback() {
918
- return ssr(_tmpl$8, escape(props.config.slug));
995
+ return props.emptyState ?? ssr(_tmpl$8, escape(props.config.slug));
919
996
  },
920
997
  get children() {
921
- return [ssr(_tmpl$3, escape(createComponent(For, {
998
+ return [ssr(_tmpl$3$1, escape(createComponent(For, {
922
999
  get each() {
923
1000
  return table.getHeaderGroups();
924
1001
  },
@@ -987,7 +1064,11 @@ var _tmpl$ = [
987
1064
  "</h1>",
988
1065
  "</div>",
989
1066
  "</div>"
990
- ], _tmpl$2 = "<div class=\"loading loading-spinner\"></div>";
1067
+ ], _tmpl$2 = "<div class=\"loading loading-spinner\"></div>", _tmpl$3 = [
1068
+ "<div class=\"border-base-300 rounded-box flex flex-col items-center gap-3 border border-dashed py-12 text-center\"><p class=\"text-base-content/70 m-0\">No ",
1069
+ " yet.</p>",
1070
+ "</div>"
1071
+ ];
991
1072
  /**
992
1073
  * Builds a list-view page component for a collection — paginated/sortable
993
1074
  * query, loading state, and the generic table/card list, wired together.
@@ -1069,6 +1150,24 @@ function createCollectionListPage(options) {
1069
1150
  get rows() {
1070
1151
  return result.data?.rows ?? [];
1071
1152
  },
1153
+ get emptyState() {
1154
+ return ssr(_tmpl$3, escape(options.label ?? options.collection.slug), escape(createComponent(Show, {
1155
+ get when() {
1156
+ return options.newHref && options.capabilities?.()?.canCreate !== false;
1157
+ },
1158
+ get children() {
1159
+ return createComponent(Link, {
1160
+ get to() {
1161
+ return options.newHref;
1162
+ },
1163
+ "class": "btn btn-primary btn-sm",
1164
+ get children() {
1165
+ return options.newLabel ?? `New ${options.collection.slug}`;
1166
+ }
1167
+ });
1168
+ }
1169
+ })));
1170
+ },
1072
1171
  get onRowClick() {
1073
1172
  return options.onRowClick;
1074
1173
  },