@vertebr/react 0.10.0 → 0.11.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.
Files changed (39) hide show
  1. package/dist/components/admin/AddonEditor.d.ts.map +1 -1
  2. package/dist/components/admin/AddonEditor.js +10 -8
  3. package/dist/components/admin/AdminContent.d.ts.map +1 -1
  4. package/dist/components/admin/AdminContent.js +55 -7
  5. package/dist/components/admin/AdminSaveBar.d.ts.map +1 -1
  6. package/dist/components/admin/AdminSaveBar.js +6 -1
  7. package/dist/components/admin/AdminSyncPage.d.ts.map +1 -1
  8. package/dist/components/admin/AdminSyncPage.js +50 -6
  9. package/dist/components/admin/PagePreviewPane.d.ts +3 -1
  10. package/dist/components/admin/PagePreviewPane.d.ts.map +1 -1
  11. package/dist/components/admin/PagePreviewPane.js +41 -9
  12. package/dist/components/admin/SyncPreviewFrame.d.ts +22 -0
  13. package/dist/components/admin/SyncPreviewFrame.d.ts.map +1 -0
  14. package/dist/components/admin/SyncPreviewFrame.js +135 -0
  15. package/dist/components/config/DatetimeInput.d.ts +15 -0
  16. package/dist/components/config/DatetimeInput.d.ts.map +1 -0
  17. package/dist/components/config/DatetimeInput.js +287 -0
  18. package/dist/components/config/EnumInput.d.ts.map +1 -1
  19. package/dist/components/config/EnumInput.js +4 -4
  20. package/dist/components/config/EnumListInput.d.ts.map +1 -1
  21. package/dist/components/config/EnumListInput.js +13 -3
  22. package/dist/components/config/RevisionHistory.d.ts +4 -0
  23. package/dist/components/config/RevisionHistory.d.ts.map +1 -1
  24. package/dist/components/config/RevisionHistory.js +63 -8
  25. package/dist/components/config/form/ConfigField.d.ts.map +1 -1
  26. package/dist/components/config/form/ConfigField.js +2 -1
  27. package/dist/components/config/form/ConfigForm.d.ts +1 -1
  28. package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
  29. package/dist/components/config/form/ConfigForm.js +54 -9
  30. package/dist/components/config/form/types.d.ts +9 -0
  31. package/dist/components/config/form/types.d.ts.map +1 -1
  32. package/dist/hooks/useSaveBar.d.ts +6 -0
  33. package/dist/hooks/useSaveBar.d.ts.map +1 -1
  34. package/dist/styles/form.css +452 -17
  35. package/dist/styles/page-preview.css +84 -0
  36. package/dist/styles/select.css +23 -0
  37. package/dist/styles/sync.css +388 -4
  38. package/dist/themes/light.css +27 -0
  39. package/package.json +3 -1
@@ -7,7 +7,7 @@ import { useToast } from "../../../hooks/useToast";
7
7
  import { buildZodSchema, groupFields, withSpecVisibility, withSpecVisibilityValues, } from "./helpers";
8
8
  import { RecordConfigForm } from "./RecordConfigForm";
9
9
  import { SettingsConfigForm } from "./SettingsConfigForm";
10
- export function ConfigForm({ schema, value, onSave, submitLabel, variant = "config", uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, onChange, hideActions, client, canWrite = true, }) {
10
+ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "config", uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, onChange, hideActions, client, canWrite = true, revisionsEnabled = false, onPublish, canPublish = false, }) {
11
11
  const { register, clear } = useSaveBar();
12
12
  const { push: pushToast } = useToast();
13
13
  const editorSchema = useMemo(() => (variant === "record" ? withSpecVisibility(schema) : schema), [schema, variant]);
@@ -18,14 +18,21 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
18
18
  const groups = useMemo(() => groupFields(editorSchema, variant), [editorSchema, variant]);
19
19
  const [status, setStatus] = useState(null);
20
20
  const [tone, setTone] = useState();
21
+ const [publishing, setPublishing] = useState(false);
21
22
  const form = useForm({
22
23
  resolver: zodResolver(zodSchema),
23
24
  defaultValues: editorValue,
24
25
  });
25
26
  const watched = useWatch({ control: form.control });
26
27
  useEffect(() => {
27
- onChange?.((watched ?? {}));
28
- }, [watched, onChange]);
28
+ if (!onChange)
29
+ return;
30
+ const subscription = form.watch((values) => {
31
+ onChange((values ?? {}));
32
+ });
33
+ onChange((form.getValues() ?? {}));
34
+ return () => subscription.unsubscribe();
35
+ }, [form, onChange]);
29
36
  useEffect(() => {
30
37
  form.reset(editorValue);
31
38
  }, [editorValue, form]);
@@ -34,18 +41,24 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
34
41
  setStatus(null);
35
42
  setTone(undefined);
36
43
  };
44
+ const saveLabel = submitLabel ?? (revisionsEnabled ? "Save draft" : "Save");
37
45
  const onSubmit = form.handleSubmit(async (data) => {
38
46
  if (!canWrite)
39
47
  return;
40
- setStatus("Saving…");
48
+ setStatus(revisionsEnabled ? "Saving draft…" : "Saving…");
41
49
  setTone(undefined);
42
50
  register({ saving: true, isDirty: true, visible: true });
43
51
  try {
44
52
  await onSave(data);
45
- setStatus("Saved");
53
+ const nextStatus = revisionsEnabled
54
+ ? "Draft saved — not live until you publish"
55
+ : "Saved";
56
+ setStatus(nextStatus);
46
57
  setTone("ok");
47
58
  form.reset(data);
48
- pushToast("Changes saved", "ok");
59
+ pushToast(revisionsEnabled
60
+ ? "Draft saved. Publish to update the live storefront."
61
+ : "Changes saved", "ok");
49
62
  }
50
63
  catch (error) {
51
64
  const message = error instanceof Error ? error.message : "Save failed";
@@ -57,22 +70,51 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
57
70
  register({ saving: false });
58
71
  }
59
72
  });
73
+ const handlePublish = async () => {
74
+ if (!onPublish || !canPublish)
75
+ return;
76
+ setPublishing(true);
77
+ setStatus("Publishing…");
78
+ setTone(undefined);
79
+ register({ publishing: true, visible: true });
80
+ try {
81
+ await onPublish();
82
+ setStatus("Published");
83
+ setTone("ok");
84
+ pushToast("Published to live storefront", "ok");
85
+ }
86
+ catch (error) {
87
+ const message = error instanceof Error ? error.message : "Publish failed";
88
+ setStatus(message);
89
+ setTone("danger");
90
+ pushToast(message, "danger");
91
+ }
92
+ finally {
93
+ setPublishing(false);
94
+ register({ publishing: false });
95
+ }
96
+ };
60
97
  const isDirty = form.formState.isDirty;
98
+ const showPublish = Boolean(revisionsEnabled && canPublish && onPublish);
61
99
  useEffect(() => {
62
100
  if (hideActions) {
63
101
  clear();
64
102
  return;
65
103
  }
66
104
  register({
67
- visible: isDirty,
105
+ visible: isDirty || Boolean(status) || showPublish,
68
106
  isDirty,
69
- saving: status === "Saving…",
107
+ saving: status === "Saving…" || status === "Saving draft…",
108
+ publishing,
70
109
  message: !canWrite && isDirty
71
110
  ? "Missing config.write capability"
72
111
  : (status ?? undefined),
73
112
  tone: !canWrite && isDirty ? "danger" : tone,
113
+ saveLabel,
74
114
  onSave: canWrite ? () => void onSubmit() : undefined,
75
115
  onDiscard,
116
+ publishLabel: "Publish",
117
+ onPublish: showPublish ? () => void handlePublish() : undefined,
76
118
  });
77
119
  return () => clear();
78
120
  }, [
@@ -85,6 +127,9 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
85
127
  register,
86
128
  clear,
87
129
  canWrite,
130
+ saveLabel,
131
+ showPublish,
132
+ publishing,
88
133
  ]);
89
134
  useEffect(() => {
90
135
  const onKeyDown = (event) => {
@@ -117,7 +162,7 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
117
162
  status,
118
163
  tone,
119
164
  onDiscard,
120
- submitLabel,
165
+ submitLabel: saveLabel,
121
166
  hideActions: true,
122
167
  };
123
168
  if (variant === "record") {
@@ -30,6 +30,15 @@ export type ConfigFormProps = {
30
30
  client?: VertebrClient;
31
31
  /** When false, save actions are disabled (missing write capability). */
32
32
  canWrite?: boolean;
33
+ /**
34
+ * When true, Save creates a draft (not live). Save bar labels and
35
+ * optional Publish action reflect that.
36
+ */
37
+ revisionsEnabled?: boolean;
38
+ /** Publish the current draft revision to live. */
39
+ onPublish?: () => Promise<void>;
40
+ /** Show Publish when a draft revision is available. */
41
+ canPublish?: boolean;
33
42
  };
34
43
  export type FieldEntry = [string, FieldSchema];
35
44
  export type FieldGroup = {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,aAAa,EACd,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,eAAe,EACf,eAAe,GAAG,eAAe,GAAG,iBAAiB,CACtD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,eAAe,EACf,OAAO,GAAG,cAAc,GAAG,aAAa,GAAG,gBAAgB,CAC5D,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,aAAa,EACd,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,eAAe,EACf,eAAe,GAAG,eAAe,GAAG,iBAAiB,CACtD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,eAAe,EACf,OAAO,GAAG,cAAc,GAAG,aAAa,GAAG,gBAAgB,CAC5D,CAAC"}
@@ -5,8 +5,14 @@ export type SaveBarState = {
5
5
  tone?: "ok" | "danger";
6
6
  isDirty: boolean;
7
7
  saving: boolean;
8
+ /** Primary save button label. @default "Save" */
9
+ saveLabel?: string;
8
10
  onSave?: () => void | Promise<void>;
9
11
  onDiscard?: () => void;
12
+ /** Optional publish action when revisions are enabled. */
13
+ publishLabel?: string;
14
+ onPublish?: () => void | Promise<void>;
15
+ publishing?: boolean;
10
16
  };
11
17
  type SaveBarContextValue = {
12
18
  state: SaveBarState;
@@ -1 +1 @@
1
- {"version":3,"file":"useSaveBar.d.ts","sourceRoot":"","sources":["../../src/hooks/useSaveBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAUF,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAuBpE;AAED,wBAAgB,UAAU,wBAMzB"}
1
+ {"version":3,"file":"useSaveBar.d.ts","sourceRoot":"","sources":["../../src/hooks/useSaveBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAUF,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAuBpE;AAED,wBAAgB,UAAU,wBAMzB"}
@@ -428,6 +428,372 @@
428
428
  background 140ms ease;
429
429
  }
430
430
 
431
+ .vertebr-datetime {
432
+ display: flex;
433
+ flex-direction: column;
434
+ gap: 0.45rem;
435
+ width: 100%;
436
+ }
437
+
438
+ .vertebr-datetime-shell {
439
+ display: flex;
440
+ align-items: stretch;
441
+ width: 100%;
442
+ min-height: 3.15rem;
443
+ border: 1px solid var(--vb-border);
444
+ border-radius: var(--vb-radius-sm);
445
+ background: var(--vb-bg);
446
+ overflow: hidden;
447
+ transition:
448
+ border-color 140ms ease,
449
+ box-shadow 140ms ease;
450
+ }
451
+
452
+ .vertebr-datetime-shell:focus-within,
453
+ .vertebr-datetime-shell:has([data-state="open"]) {
454
+ border-color: color-mix(in srgb, var(--vb-accent) 55%, var(--vb-border));
455
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--vb-accent) 18%, transparent);
456
+ }
457
+
458
+ .vertebr-datetime-cell {
459
+ appearance: none;
460
+ flex: 1 1 auto;
461
+ min-width: 0;
462
+ display: flex;
463
+ align-items: stretch;
464
+ gap: 0;
465
+ margin: 0;
466
+ padding: 0;
467
+ border: 0;
468
+ background: transparent;
469
+ color: inherit;
470
+ font: inherit;
471
+ text-align: left;
472
+ cursor: pointer;
473
+ user-select: none;
474
+ }
475
+
476
+ .vertebr-datetime-cell:disabled {
477
+ cursor: default;
478
+ opacity: 0.7;
479
+ }
480
+
481
+ .vertebr-datetime-cell:hover:not(:disabled) .vertebr-datetime-cell-inner {
482
+ background: color-mix(in srgb, var(--vb-surface-tint) 70%, transparent);
483
+ }
484
+
485
+ .vertebr-datetime-cell-inner {
486
+ display: flex;
487
+ align-items: center;
488
+ gap: 0.55rem;
489
+ flex: 1 1 0;
490
+ min-width: 0;
491
+ padding: 0.45rem 0.7rem;
492
+ }
493
+
494
+ .vertebr-datetime-icon {
495
+ flex: none;
496
+ color: var(--vb-text-muted);
497
+ }
498
+
499
+ .vertebr-datetime-cell-copy {
500
+ display: flex;
501
+ flex-direction: column;
502
+ gap: 0.08rem;
503
+ min-width: 0;
504
+ flex: 1 1 auto;
505
+ }
506
+
507
+ .vertebr-datetime-cell-label {
508
+ font-size: 0.68rem;
509
+ font-weight: 600;
510
+ letter-spacing: 0.06em;
511
+ text-transform: uppercase;
512
+ color: var(--vb-text-subtle);
513
+ line-height: 1;
514
+ }
515
+
516
+ .vertebr-datetime-value {
517
+ min-width: 0;
518
+ overflow: hidden;
519
+ text-overflow: ellipsis;
520
+ white-space: nowrap;
521
+ color: var(--vb-text);
522
+ font-size: 0.9rem;
523
+ font-variant-numeric: tabular-nums;
524
+ line-height: 1.35rem;
525
+ }
526
+
527
+ .vertebr-datetime-value[data-empty="true"] {
528
+ color: var(--vb-text-subtle);
529
+ }
530
+
531
+ .vertebr-datetime-divider {
532
+ flex: none;
533
+ width: 1px;
534
+ align-self: stretch;
535
+ margin: 0.55rem 0;
536
+ background: var(--vb-border);
537
+ }
538
+
539
+ .vertebr-datetime-clear {
540
+ appearance: none;
541
+ flex: none;
542
+ align-self: stretch;
543
+ margin: 0;
544
+ padding: 0 0.85rem;
545
+ border: 0;
546
+ border-left: 1px solid var(--vb-border);
547
+ background: color-mix(in srgb, var(--vb-surface-tint) 55%, transparent);
548
+ color: var(--vb-text-muted);
549
+ font: inherit;
550
+ font-size: 0.78rem;
551
+ font-weight: 500;
552
+ cursor: pointer;
553
+ }
554
+
555
+ .vertebr-datetime-clear:hover {
556
+ color: var(--vb-text);
557
+ background: var(--vb-surface-tint);
558
+ }
559
+
560
+ .vertebr-datetime-summary {
561
+ margin: 0;
562
+ font-size: 0.8rem;
563
+ color: var(--vb-text-muted);
564
+ font-variant-numeric: tabular-nums;
565
+ }
566
+
567
+ .vertebr-datetime-summary-empty {
568
+ color: var(--vb-text-subtle);
569
+ }
570
+
571
+ .vertebr-datetime-popover {
572
+ z-index: 70;
573
+ box-sizing: border-box;
574
+ width: min(20.5rem, calc(100vw - 1.5rem));
575
+ padding: 0.75rem;
576
+ border: 1px solid var(--vb-border-strong);
577
+ border-radius: var(--vb-radius);
578
+ background: var(--vb-bg-elevated);
579
+ color: var(--vb-text);
580
+ font-family: var(--vb-font);
581
+ box-shadow: var(--vb-shadow);
582
+ animation: vertebr-pop 120ms ease-out;
583
+ }
584
+
585
+ .vertebr-day-picker {
586
+ position: relative;
587
+ width: 100%;
588
+ }
589
+
590
+ .vertebr-day-picker-months,
591
+ .vertebr-day-picker-month {
592
+ position: relative;
593
+ width: 100%;
594
+ }
595
+
596
+ .vertebr-day-picker-caption {
597
+ display: flex;
598
+ align-items: center;
599
+ justify-content: center;
600
+ min-height: 2.25rem;
601
+ margin: 0 2.1rem 0.45rem;
602
+ }
603
+
604
+ .vertebr-day-picker-caption-label {
605
+ font-size: 0.9rem;
606
+ font-weight: 600;
607
+ }
608
+
609
+ .vertebr-day-picker-nav {
610
+ position: absolute;
611
+ inset: 0 0 auto;
612
+ height: 2.25rem;
613
+ pointer-events: none;
614
+ }
615
+
616
+ .vertebr-day-picker-nav-btn {
617
+ appearance: none;
618
+ position: absolute;
619
+ top: 0;
620
+ pointer-events: auto;
621
+ display: inline-flex;
622
+ align-items: center;
623
+ justify-content: center;
624
+ width: 1.85rem;
625
+ height: 1.85rem;
626
+ margin: 0;
627
+ padding: 0;
628
+ border: 1px solid var(--vb-border);
629
+ border-radius: var(--vb-radius-sm);
630
+ background: var(--vb-bg);
631
+ color: var(--vb-text-muted);
632
+ cursor: pointer;
633
+ }
634
+
635
+ .vertebr-day-picker-nav-btn:first-of-type {
636
+ left: 0;
637
+ }
638
+
639
+ .vertebr-day-picker-nav-btn:last-of-type {
640
+ right: 0;
641
+ }
642
+
643
+ .vertebr-day-picker-nav-btn:hover {
644
+ color: var(--vb-text);
645
+ background: var(--vb-bg-muted);
646
+ }
647
+
648
+ .vertebr-day-picker-grid {
649
+ width: 100%;
650
+ border-collapse: collapse;
651
+ table-layout: fixed;
652
+ }
653
+
654
+ .vertebr-day-picker-weekday {
655
+ padding: 0.35rem 0;
656
+ font-size: 0.68rem;
657
+ font-weight: 600;
658
+ letter-spacing: 0.04em;
659
+ text-transform: uppercase;
660
+ text-align: center;
661
+ color: var(--vb-text-subtle);
662
+ }
663
+
664
+ .vertebr-day-picker-day {
665
+ width: 14.28%;
666
+ height: 2.35rem;
667
+ padding: 0;
668
+ text-align: center;
669
+ vertical-align: middle;
670
+ }
671
+
672
+ .vertebr-day-picker-day-btn {
673
+ appearance: none;
674
+ display: inline-flex;
675
+ align-items: center;
676
+ justify-content: center;
677
+ width: 2.15rem;
678
+ height: 2.15rem;
679
+ margin: 0;
680
+ padding: 0;
681
+ border: 0;
682
+ border-radius: 999px;
683
+ background: transparent;
684
+ color: var(--vb-text);
685
+ font: inherit;
686
+ font-size: 0.85rem;
687
+ font-variant-numeric: tabular-nums;
688
+ cursor: pointer;
689
+ }
690
+
691
+ .vertebr-day-picker-day-btn:hover {
692
+ background: var(--vb-bg-hover);
693
+ }
694
+
695
+ .vertebr-day-picker-today .vertebr-day-picker-day-btn {
696
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--vb-accent) 45%, transparent);
697
+ }
698
+
699
+ .vertebr-day-picker-selected .vertebr-day-picker-day-btn,
700
+ .vertebr-day-picker-selected .vertebr-day-picker-day-btn:hover {
701
+ background: var(--vb-accent);
702
+ color: var(--vb-accent-contrast);
703
+ box-shadow: none;
704
+ }
705
+
706
+ .vertebr-day-picker-outside .vertebr-day-picker-day-btn {
707
+ color: var(--vb-text-subtle);
708
+ opacity: 0.55;
709
+ }
710
+
711
+ .vertebr-day-picker-disabled .vertebr-day-picker-day-btn,
712
+ .vertebr-day-picker-hidden .vertebr-day-picker-day-btn {
713
+ opacity: 0.35;
714
+ pointer-events: none;
715
+ }
716
+
717
+ .vertebr-datetime-time-row {
718
+ display: flex;
719
+ align-items: end;
720
+ gap: 0.45rem;
721
+ margin-top: 0.75rem;
722
+ padding-top: 0.75rem;
723
+ border-top: 1px solid var(--vb-border);
724
+ }
725
+
726
+ .vertebr-datetime-time-field {
727
+ display: flex;
728
+ flex-direction: column;
729
+ gap: 0.3rem;
730
+ flex: 1 1 0;
731
+ min-width: 0;
732
+ font-size: 0.68rem;
733
+ font-weight: 600;
734
+ letter-spacing: 0.06em;
735
+ text-transform: uppercase;
736
+ color: var(--vb-text-subtle);
737
+ }
738
+
739
+ .vertebr-datetime-time-field-meridiem {
740
+ flex: 0 0 4.5rem;
741
+ }
742
+
743
+ .vertebr-datetime-timezone {
744
+ margin-top: 0.55rem;
745
+ }
746
+
747
+ .vertebr-datetime-time-select {
748
+ appearance: none;
749
+ box-sizing: border-box;
750
+ width: 100%;
751
+ min-height: 2.35rem;
752
+ padding: 0.45rem 0.65rem;
753
+ border: 1px solid var(--vb-border);
754
+ border-radius: var(--vb-radius-sm);
755
+ background: var(--vb-bg);
756
+ color: var(--vb-text);
757
+ font: inherit;
758
+ font-size: 0.9rem;
759
+ font-variant-numeric: tabular-nums;
760
+ text-transform: none;
761
+ letter-spacing: normal;
762
+ font-weight: 500;
763
+ cursor: pointer;
764
+ }
765
+
766
+ .vertebr-datetime-time-select:focus-visible {
767
+ outline: none;
768
+ border-color: var(--vb-accent-dim);
769
+ box-shadow: 0 0 0 3px var(--vb-accent-soft);
770
+ }
771
+
772
+ .vertebr-datetime-time-sep {
773
+ flex: none;
774
+ padding-bottom: 0.55rem;
775
+ color: var(--vb-text-muted);
776
+ font-size: 1.1rem;
777
+ font-weight: 600;
778
+ }
779
+
780
+ @media (max-width: 520px) {
781
+ .vertebr-datetime-shell {
782
+ flex-wrap: wrap;
783
+ }
784
+
785
+ .vertebr-datetime-cell {
786
+ flex: 1 1 auto;
787
+ }
788
+
789
+ .vertebr-datetime-clear {
790
+ flex: 1 1 100%;
791
+ min-height: 2.2rem;
792
+ border-left: 0;
793
+ border-top: 1px solid var(--vb-border);
794
+ }
795
+ }
796
+
431
797
  .vertebr-field textarea {
432
798
  resize: vertical;
433
799
  min-height: 4.5rem;
@@ -784,15 +1150,22 @@
784
1150
  }
785
1151
 
786
1152
  .vertebr-switch {
787
- width: 40px;
788
- height: 22px;
1153
+ box-sizing: border-box;
1154
+ width: 2.5rem;
1155
+ height: 1.375rem;
789
1156
  background: var(--vb-bg-muted);
790
1157
  border-radius: 999px;
791
1158
  position: relative;
792
1159
  border: 1px solid var(--vb-border);
793
1160
  cursor: pointer;
794
1161
  flex: none;
795
- transition: background 140ms ease, border-color 140ms ease;
1162
+ display: inline-flex;
1163
+ align-items: center;
1164
+ justify-content: flex-start;
1165
+ padding: 0;
1166
+ transition:
1167
+ background 140ms ease,
1168
+ border-color 140ms ease;
796
1169
  }
797
1170
 
798
1171
  .vertebr-switch[data-state="checked"] {
@@ -802,17 +1175,22 @@
802
1175
 
803
1176
  .vertebr-switch-thumb {
804
1177
  display: block;
805
- width: 16px;
806
- height: 16px;
1178
+ box-sizing: border-box;
1179
+ width: 1rem;
1180
+ height: 1rem;
807
1181
  background: var(--vb-text);
808
1182
  border-radius: 999px;
809
- transform: translateX(2px);
810
- transition: transform 140ms ease, background 140ms ease;
811
- margin-top: 2px;
1183
+ position: absolute;
1184
+ top: 50%;
1185
+ left: 2px;
1186
+ transform: translateY(-50%);
1187
+ transition:
1188
+ left 140ms ease,
1189
+ background 140ms ease;
812
1190
  }
813
1191
 
814
1192
  .vertebr-switch[data-state="checked"] .vertebr-switch-thumb {
815
- transform: translateX(18px);
1193
+ left: calc(100% - 1rem - 2px);
816
1194
  background: var(--vb-accent);
817
1195
  }
818
1196
 
@@ -1075,14 +1453,49 @@
1075
1453
 
1076
1454
  /* ── Revision history ────────────────────────────────── */
1077
1455
 
1078
- .vertebr-revisions {
1079
- margin-top: 1.25rem;
1080
- padding-top: 1rem;
1081
- border-top: 1px solid var(--vb-border);
1456
+ .vertebr-revisions-trigger {
1457
+ appearance: none;
1458
+ display: inline-flex;
1459
+ align-items: center;
1460
+ gap: 0.4rem;
1461
+ height: 2rem;
1462
+ padding: 0 0.7rem;
1463
+ border: 1px solid var(--vb-border);
1464
+ border-radius: var(--vb-radius-sm, 8px);
1465
+ background: var(--vb-bg-elevated);
1466
+ color: var(--vb-text-secondary);
1467
+ font: inherit;
1468
+ font-size: var(--vb-font-size-100, 0.88rem);
1469
+ font-weight: var(--vb-font-weight-medium, 500);
1470
+ cursor: pointer;
1471
+ white-space: nowrap;
1472
+ transition:
1473
+ background 0.15s ease,
1474
+ color 0.15s ease,
1475
+ border-color 0.15s ease;
1476
+ }
1477
+
1478
+ .vertebr-revisions-trigger:hover {
1479
+ background: var(--vb-bg-hover);
1480
+ color: var(--vb-text);
1481
+ border-color: var(--vb-border-strong, var(--vb-border));
1482
+ }
1483
+
1484
+ .vertebr-revisions-trigger-count {
1485
+ display: inline-grid;
1486
+ place-items: center;
1487
+ min-width: 1.25rem;
1488
+ height: 1.25rem;
1489
+ padding: 0 0.3rem;
1490
+ border-radius: 999px;
1491
+ background: var(--vb-bg-muted);
1492
+ color: var(--vb-text-muted);
1493
+ font-family: var(--vb-mono);
1494
+ font-size: 0.68rem;
1082
1495
  }
1083
1496
 
1084
- .vertebr-revisions .vertebr-panel-head {
1085
- margin-bottom: 0.65rem;
1497
+ .vertebr-revisions-modal .vertebr-modal-body {
1498
+ gap: 0.75rem;
1086
1499
  }
1087
1500
 
1088
1501
  .vertebr-revisions-empty {
@@ -1108,17 +1521,24 @@
1108
1521
  padding: 0.55rem 0.65rem;
1109
1522
  border: 1px solid var(--vb-border);
1110
1523
  border-radius: 8px;
1111
- background: var(--vb-bg-elevated);
1524
+ background: var(--vb-bg-muted);
1112
1525
  }
1113
1526
 
1114
1527
  .vertebr-revisions-meta {
1115
1528
  display: flex;
1116
1529
  flex-wrap: wrap;
1117
1530
  align-items: baseline;
1118
- gap: 0.4rem 0.65rem;
1531
+ gap: 0.35rem 0.55rem;
1119
1532
  min-width: 0;
1120
1533
  }
1121
1534
 
1535
+ .vertebr-revisions-meta strong {
1536
+ overflow: hidden;
1537
+ text-overflow: ellipsis;
1538
+ white-space: nowrap;
1539
+ max-width: 16rem;
1540
+ }
1541
+
1122
1542
  .vertebr-revisions-meta [data-status] {
1123
1543
  font-family: var(--vb-mono);
1124
1544
  font-size: 0.68rem;
@@ -1135,7 +1555,22 @@
1135
1555
  color: var(--vb-warn, #9a6b2f);
1136
1556
  }
1137
1557
 
1558
+ .vertebr-revisions-meta [data-status="current"] {
1559
+ color: var(--vb-text);
1560
+ background: var(--vb-bg-elevated);
1561
+ border: 1px solid var(--vb-border);
1562
+ border-radius: 999px;
1563
+ padding: 0.05rem 0.4rem;
1564
+ letter-spacing: 0.04em;
1565
+ }
1566
+
1567
+ .vertebr-revisions-item[data-active="true"] {
1568
+ border-color: color-mix(in srgb, var(--vb-text) 22%, var(--vb-border));
1569
+ background: var(--vb-bg-elevated);
1570
+ }
1571
+
1138
1572
  .vertebr-revisions-when {
1573
+ flex-basis: 100%;
1139
1574
  font-size: 0.78rem;
1140
1575
  color: var(--vb-text-subtle);
1141
1576
  }