@ai-matrx/records-ui 0.56.0 → 0.57.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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.57.0
4
+
5
+ **The builders are usable where a person actually reaches them: a 384px rail.**
6
+
7
+ The first browser walk (lane BUILDERS, Ironline Fitness, 2026-09-21) pressed
8
+ "Build the form" on a real gym's members table and got a preview of an empty
9
+ form and **no controls at all**. `FormBuilder` was authored as two desktop
10
+ columns — controls left, live preview in a `w-96` aside right — and the rail it
11
+ is mounted in is itself `w-96`, so the fixed-width preview took the entire rail
12
+ and squeezed the controls to nothing. The screen looked like a builder and could
13
+ not build.
14
+
15
+ A viewport breakpoint cannot fix that: the viewport was 1680px wide while the
16
+ container was 384px. Every split in these four screens is now a **container
17
+ query**, so they are the same screen in a rail, a dialog or a full page:
18
+
19
+ * `FormBuilder` stacks to one column and its preview goes full-width below the
20
+ controls until the component itself is wide enough for two (`@3xl`).
21
+ * `BookingBuilder`, `PortalBuilder` and `DigestScheduler` drop their two-column
22
+ grids and fixed-width inputs to one column under `@md`.
23
+
24
+ **Consumer action:** none. The host must already scan this package's `dist` for
25
+ Tailwind classes (`@source "…/@ai-matrx/records-ui/dist"`), which matrx-frontend
26
+ does; the container variants are generated from there like every other class.
27
+
3
28
  ## 0.56.0
4
29
 
5
30
  **A condition the builder cannot draw is said in words, not blanked.**
package/dist/index.cjs CHANGED
@@ -8955,7 +8955,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
8955
8955
  const all = tables.data ?? [];
8956
8956
  const missingTie = ticked.filter((e) => e.namesVia.trim() === "");
8957
8957
  const ready = clientTableId !== null && ticked.length > 0 && missingTie.length === 0;
8958
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: (0, import_design_system30.cn)("flex flex-col gap-3", className), children: [
8958
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: (0, import_design_system30.cn)("@container flex flex-col gap-3", className), children: [
8959
8959
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("header", { className: "flex items-center gap-2", children: [
8960
8960
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h3", { className: "text-sm font-medium", children: existing ? "Portal" : "New client portal" }),
8961
8961
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1" }),
@@ -9096,7 +9096,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
9096
9096
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
9097
9097
  import_design_system30.BasicInput,
9098
9098
  {
9099
- className: "h-8 w-56",
9099
+ className: "h-8 w-full @md:w-56",
9100
9100
  value: inviteEmail,
9101
9101
  onChange: (e) => setInviteEmail(e.target.value)
9102
9102
  }
@@ -9107,7 +9107,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
9107
9107
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
9108
9108
  import_design_system30.BasicInput,
9109
9109
  {
9110
- className: "h-8 w-80",
9110
+ className: "h-8 w-full @md:w-80",
9111
9111
  placeholder: "the record id",
9112
9112
  value: inviteRecordId,
9113
9113
  onChange: (e) => setInviteRecordId(e.target.value)
@@ -9804,7 +9804,7 @@ function DigestScheduler({
9804
9804
  setPreview(answered.data);
9805
9805
  }
9806
9806
  if (views === null && !error) return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Skeleton, { className: (0, import_design_system33.cn)("h-56 w-full", className) });
9807
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("flex flex-col gap-3", className), children: [
9807
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("@container flex flex-col gap-3", className), children: [
9808
9808
  /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("header", { className: "flex items-center gap-2", children: [
9809
9809
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { className: "text-sm font-medium", children: "Send this on a schedule" }),
9810
9810
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1" }),
@@ -9839,7 +9839,7 @@ function DigestScheduler({
9839
9839
  ),
9840
9840
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children: "The first choice saves what is on screen as a view, so the summary and the screen stay the same thing." })
9841
9841
  ] }),
9842
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
9842
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid grid-cols-1 gap-2 @md:grid-cols-2", children: [
9843
9843
  /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
9844
9844
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "How often" }),
9845
9845
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
@@ -10580,7 +10580,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
10580
10580
  if (!rights.admin) {
10581
10581
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: (0, import_design_system36.cn)("text-xs text-muted-foreground", className), children: rights.why("structure") });
10582
10582
  }
10583
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: (0, import_design_system36.cn)("flex min-h-0 gap-3", className), children: [
10583
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: (0, import_design_system36.cn)("@container flex min-h-0 flex-col gap-3 @3xl:flex-row", className), children: [
10584
10584
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-2 overflow-auto", children: [
10585
10585
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-1 overflow-x-auto", role: "group", "aria-label": "Forms", children: [
10586
10586
  forms.map((form) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
@@ -10741,7 +10741,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
10741
10741
  ] })
10742
10742
  ] })
10743
10743
  ] }),
10744
- draft ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("aside", { className: "w-96 shrink-0 overflow-auto rounded border p-2", children: [
10744
+ draft ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("aside", { className: "w-full shrink-0 overflow-auto rounded border p-2 @3xl:w-96", children: [
10745
10745
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("h4", { className: "px-1 text-sm font-medium", children: draft.name }),
10746
10746
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FormRunner, { form: draft, preview: true })
10747
10747
  ] }) : null
@@ -12507,195 +12507,200 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
12507
12507
  }
12508
12508
  const url = formId ? `${publicOrigin}${(0, import_records9.bookingPath)(formId)}` : null;
12509
12509
  const shown = offer ?? null;
12510
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: (0, import_design_system45.cn)("flex flex-col gap-3", className), children: [
12511
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("header", { className: "flex items-center gap-2", children: [
12512
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h3", { className: "text-sm font-medium", children: existing ? "Booking page" : "New booking page" }),
12513
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex-1" }),
12514
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" }),
12515
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
12516
- ] }),
12517
- error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RefusalNotice, { error }) : null,
12518
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12519
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What it is called" }),
12520
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.BasicInput, { value: title, onChange: (e) => setTitle(e.target.value) })
12521
- ] }),
12522
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
12523
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12524
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How long one appointment is" }),
12525
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12526
- "select",
12527
- {
12528
- className: "h-9 rounded border bg-background px-2 text-sm",
12529
- value: minutes,
12530
- onChange: (e) => setMinutes(Number(e.target.value)),
12531
- children: LENGTHS.map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
12532
- n,
12533
- " minutes"
12534
- ] }, n))
12535
- }
12536
- )
12537
- ] }),
12538
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12539
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Gap kept after each one" }),
12540
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12541
- "select",
12542
- {
12543
- className: "h-9 rounded border bg-background px-2 text-sm",
12544
- value: buffer,
12545
- onChange: (e) => setBuffer(Number(e.target.value)),
12546
- children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "No gap \u2014 back to back" : `${n} minutes` }, n))
12547
- }
12548
- )
12549
- ] }),
12550
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12551
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Earliest somebody may book" }),
12552
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12553
- "select",
12554
- {
12555
- className: "h-9 rounded border bg-background px-2 text-sm",
12556
- value: lead,
12557
- onChange: (e) => setLead(Number(e.target.value)),
12558
- children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "Right away" : n === 1440 ? "A day from now" : `${n / 60} hour${n === 60 ? "" : "s"} from now` }, n))
12559
- }
12560
- )
12510
+ return (
12511
+ // THE RAIL IS 384px WIDE AND THE VIEWPORT IS NOT (walk 1, 2026-09-21):
12512
+ // every split below is a CONTAINER query, so this screen is the same
12513
+ // screen in a rail, a dialog and a full page.
12514
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: (0, import_design_system45.cn)("@container flex flex-col gap-3", className), children: [
12515
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("header", { className: "flex items-center gap-2", children: [
12516
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h3", { className: "text-sm font-medium", children: existing ? "Booking page" : "New booking page" }),
12517
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex-1" }),
12518
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" }),
12519
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
12561
12520
  ] }),
12521
+ error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RefusalNotice, { error }) : null,
12562
12522
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12563
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Most in one day" }),
12564
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12565
- import_design_system45.BasicInput,
12566
- {
12567
- type: "number",
12568
- min: 1,
12569
- value: perDay,
12570
- onChange: (e) => setPerDay(Math.max(1, Number(e.target.value) || 1))
12571
- }
12572
- )
12523
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What it is called" }),
12524
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.BasicInput, { value: title, onChange: (e) => setTitle(e.target.value) })
12573
12525
  ] }),
12574
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12575
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How far ahead the page offers" }),
12576
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12577
- "select",
12578
- {
12579
- className: "h-9 rounded border bg-background px-2 text-sm",
12580
- value: days,
12581
- onChange: (e) => setDays(Number(e.target.value)),
12582
- children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
12583
- n,
12584
- " days"
12585
- ] }, n))
12586
- }
12587
- )
12588
- ] })
12589
- ] }),
12590
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
12591
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Hours you are free" }),
12592
- windows.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
12593
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex w-20 items-center gap-1.5 text-xs", children: [
12526
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid grid-cols-1 gap-2 @md:grid-cols-2", children: [
12527
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12528
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How long one appointment is" }),
12594
12529
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12595
- import_design_system45.Checkbox,
12530
+ "select",
12596
12531
  {
12597
- checked: w.on,
12598
- onCheckedChange: (on) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, on: Boolean(on) } : x))
12532
+ className: "h-9 rounded border bg-background px-2 text-sm",
12533
+ value: minutes,
12534
+ onChange: (e) => setMinutes(Number(e.target.value)),
12535
+ children: LENGTHS.map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
12536
+ n,
12537
+ " minutes"
12538
+ ] }, n))
12599
12539
  }
12600
- ),
12601
- DAYS[i]?.label
12540
+ )
12602
12541
  ] }),
12603
- w.on ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
12542
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12543
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Gap kept after each one" }),
12604
12544
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12605
- import_design_system45.BasicInput,
12545
+ "select",
12606
12546
  {
12607
- type: "time",
12608
- className: "h-8 w-28",
12609
- value: w.from,
12610
- onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, from: e.target.value } : x))
12547
+ className: "h-9 rounded border bg-background px-2 text-sm",
12548
+ value: buffer,
12549
+ onChange: (e) => setBuffer(Number(e.target.value)),
12550
+ children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "No gap \u2014 back to back" : `${n} minutes` }, n))
12611
12551
  }
12612
- ),
12613
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
12552
+ )
12553
+ ] }),
12554
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12555
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Earliest somebody may book" }),
12556
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12557
+ "select",
12558
+ {
12559
+ className: "h-9 rounded border bg-background px-2 text-sm",
12560
+ value: lead,
12561
+ onChange: (e) => setLead(Number(e.target.value)),
12562
+ children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "Right away" : n === 1440 ? "A day from now" : `${n / 60} hour${n === 60 ? "" : "s"} from now` }, n))
12563
+ }
12564
+ )
12565
+ ] }),
12566
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12567
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Most in one day" }),
12614
12568
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12615
12569
  import_design_system45.BasicInput,
12616
12570
  {
12617
- type: "time",
12618
- className: "h-8 w-28",
12619
- value: w.to,
12620
- onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, to: e.target.value } : x))
12571
+ type: "number",
12572
+ min: 1,
12573
+ value: perDay,
12574
+ onChange: (e) => setPerDay(Math.max(1, Number(e.target.value) || 1))
12621
12575
  }
12622
12576
  )
12623
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "not taking bookings" })
12624
- ] }, w.weekday))
12625
- ] }),
12626
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
12627
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What to ask the person booking" }),
12628
- askable.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "This table has no fields yet, so there is nothing a booking page could ask for. Add a field first \u2014 every question is one of this table's own fields." }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: askable.map((f) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex items-center gap-1.5 text-xs", children: [
12577
+ ] }),
12578
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12579
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How far ahead the page offers" }),
12580
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12581
+ "select",
12582
+ {
12583
+ className: "h-9 rounded border bg-background px-2 text-sm",
12584
+ value: days,
12585
+ onChange: (e) => setDays(Number(e.target.value)),
12586
+ children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
12587
+ n,
12588
+ " days"
12589
+ ] }, n))
12590
+ }
12591
+ )
12592
+ ] })
12593
+ ] }),
12594
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
12595
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Hours you are free" }),
12596
+ windows.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
12597
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex w-20 items-center gap-1.5 text-xs", children: [
12598
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12599
+ import_design_system45.Checkbox,
12600
+ {
12601
+ checked: w.on,
12602
+ onCheckedChange: (on) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, on: Boolean(on) } : x))
12603
+ }
12604
+ ),
12605
+ DAYS[i]?.label
12606
+ ] }),
12607
+ w.on ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
12608
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12609
+ import_design_system45.BasicInput,
12610
+ {
12611
+ type: "time",
12612
+ className: "h-8 w-28",
12613
+ value: w.from,
12614
+ onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, from: e.target.value } : x))
12615
+ }
12616
+ ),
12617
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
12618
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12619
+ import_design_system45.BasicInput,
12620
+ {
12621
+ type: "time",
12622
+ className: "h-8 w-28",
12623
+ value: w.to,
12624
+ onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, to: e.target.value } : x))
12625
+ }
12626
+ )
12627
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "not taking bookings" })
12628
+ ] }, w.weekday))
12629
+ ] }),
12630
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
12631
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What to ask the person booking" }),
12632
+ askable.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "This table has no fields yet, so there is nothing a booking page could ask for. Add a field first \u2014 every question is one of this table's own fields." }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: askable.map((f) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex items-center gap-1.5 text-xs", children: [
12633
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12634
+ import_design_system45.Checkbox,
12635
+ {
12636
+ checked: asked.includes(f.key),
12637
+ onCheckedChange: (on) => setAsked((prev) => on ? [...prev, f.key] : prev.filter((k) => k !== f.key))
12638
+ }
12639
+ ),
12640
+ fieldName(f)
12641
+ ] }, f.key)) }),
12642
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "The time, whether it is booked or cancelled, and who it is with are filled in by the store \u2014 a booking page cannot ask a visitor for any of the three." })
12643
+ ] }),
12644
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12645
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What they see after booking" }),
12646
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12647
+ import_design_system45.BasicTextarea,
12648
+ {
12649
+ rows: 2,
12650
+ value: confirmation,
12651
+ placeholder: "You're booked. We'll send a reminder the day before \u2014 reply to that message to move it.",
12652
+ onChange: (e) => setConfirmation(e.target.value)
12653
+ }
12654
+ )
12655
+ ] }),
12656
+ shown ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("p", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
12657
+ "Saved. The page offers ",
12658
+ shown.slot_minutes,
12659
+ "-minute appointments in ",
12660
+ shown.timezone,
12661
+ ", up to",
12662
+ " ",
12663
+ shown.max_per_day,
12664
+ " a day, ",
12665
+ shown.days,
12666
+ " days ahead",
12667
+ shown.buffer_minutes > 0 ? `, with ${shown.buffer_minutes} minutes between them` : "",
12668
+ ":",
12669
+ " ",
12670
+ shown.windows.map(
12671
+ (w) => `${DAYS.find((d) => d.weekday === w.weekday)?.label ?? w.weekday} ${w.from}\u2013${w.to}`
12672
+ ).join(", "),
12673
+ "."
12674
+ ] }) : null,
12675
+ url ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded-md border p-2.5", children: [
12676
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 break-all text-xs", children: url }),
12629
12677
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12630
- import_design_system45.Checkbox,
12678
+ import_design_system45.Button,
12631
12679
  {
12632
- checked: asked.includes(f.key),
12633
- onCheckedChange: (on) => setAsked((prev) => on ? [...prev, f.key] : prev.filter((k) => k !== f.key))
12680
+ size: "sm",
12681
+ variant: "outline",
12682
+ onClick: () => {
12683
+ void navigator.clipboard.writeText(url).then(() => {
12684
+ setCopied(true);
12685
+ window.setTimeout(() => setCopied(false), 1600);
12686
+ }).catch(() => setCopied(false));
12687
+ },
12688
+ children: copied ? "Copied" : "Copy link"
12634
12689
  }
12635
12690
  ),
12636
- fieldName(f)
12637
- ] }, f.key)) }),
12638
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "The time, whether it is booked or cancelled, and who it is with are filled in by the store \u2014 a booking page cannot ask a visitor for any of the three." })
12639
- ] }),
12640
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12641
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What they see after booking" }),
12642
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12643
- import_design_system45.BasicTextarea,
12644
- {
12645
- rows: 2,
12646
- value: confirmation,
12647
- placeholder: "You're booked. We'll send a reminder the day before \u2014 reply to that message to move it.",
12648
- onChange: (e) => setConfirmation(e.target.value)
12649
- }
12650
- )
12651
- ] }),
12652
- shown ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("p", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
12653
- "Saved. The page offers ",
12654
- shown.slot_minutes,
12655
- "-minute appointments in ",
12656
- shown.timezone,
12657
- ", up to",
12658
- " ",
12659
- shown.max_per_day,
12660
- " a day, ",
12661
- shown.days,
12662
- " days ahead",
12663
- shown.buffer_minutes > 0 ? `, with ${shown.buffer_minutes} minutes between them` : "",
12664
- ":",
12665
- " ",
12666
- shown.windows.map(
12667
- (w) => `${DAYS.find((d) => d.weekday === w.weekday)?.label ?? w.weekday} ${w.from}\u2013${w.to}`
12668
- ).join(", "),
12669
- "."
12670
- ] }) : null,
12671
- url ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded-md border p-2.5", children: [
12672
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 break-all text-xs", children: url }),
12673
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12674
- import_design_system45.Button,
12675
- {
12676
- size: "sm",
12677
- variant: "outline",
12678
- onClick: () => {
12679
- void navigator.clipboard.writeText(url).then(() => {
12680
- setCopied(true);
12681
- window.setTimeout(() => setCopied(false), 1600);
12682
- }).catch(() => setCopied(false));
12683
- },
12684
- children: copied ? "Copied" : "Copy link"
12685
- }
12686
- ),
12687
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12688
- import_design_system45.Button,
12689
- {
12690
- size: "sm",
12691
- disabled: publishing,
12692
- onClick: () => void publish(!(existing?.published_at && !existing.closed_at)),
12693
- children: publishing ? "\u2026" : existing?.published_at && !existing.closed_at ? "Unpublish" : "Publish"
12694
- }
12695
- ),
12696
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "w-full text-xs text-muted-foreground", children: existing?.published_at && !existing.closed_at ? "Open. Anyone with this link can book a time." : "Not open yet \u2014 the link does not take bookings until you publish it." })
12697
- ] }) : null
12698
- ] });
12691
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
12692
+ import_design_system45.Button,
12693
+ {
12694
+ size: "sm",
12695
+ disabled: publishing,
12696
+ onClick: () => void publish(!(existing?.published_at && !existing.closed_at)),
12697
+ children: publishing ? "\u2026" : existing?.published_at && !existing.closed_at ? "Unpublish" : "Publish"
12698
+ }
12699
+ ),
12700
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "w-full text-xs text-muted-foreground", children: existing?.published_at && !existing.closed_at ? "Open. Anyone with this link can book a time." : "Not open yet \u2014 the link does not take bookings until you publish it." })
12701
+ ] }) : null
12702
+ ] })
12703
+ );
12699
12704
  }
12700
12705
 
12701
12706
  // src/BookingSlots.tsx