@drawnagency/primitives 0.1.88 → 0.1.90

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 (124) hide show
  1. package/dist/{chunk-75P6HWPN.js → chunk-5BM2Y3NJ.js} +5 -3
  2. package/dist/{chunk-OEL57NYV.js → chunk-AGWE2LJG.js} +26 -2
  3. package/dist/{chunk-DRCPDOW3.js → chunk-CZ3YXGK5.js} +59 -0
  4. package/dist/{chunk-PTVY3Q7P.js → chunk-KBQNJZUX.js} +1 -1
  5. package/dist/{chunk-XPUBUR64.js → chunk-KMQZYORS.js} +28 -2
  6. package/dist/{chunk-WA3HFN54.js → chunk-MK7YB2A4.js} +1 -1
  7. package/dist/{chunk-EO7K45GV.js → chunk-NV4R6VHN.js} +1 -1
  8. package/dist/{chunk-XDG2K6UT.js → chunk-SIYQ37QY.js} +13 -5
  9. package/dist/{chunk-NEDOJHHR.js → chunk-XKRQMTE4.js} +11 -2
  10. package/dist/{chunk-SK6GGTTO.js → chunk-XUIJHYKI.js} +3 -3
  11. package/dist/{chunk-H2FENAQH.js → chunk-ZLG7S54V.js} +242 -83
  12. package/dist/components/chat/ChatPanel.d.ts +20 -3
  13. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  14. package/dist/components/chat/ChatWidget.d.ts +7 -1
  15. package/dist/components/chat/ChatWidget.d.ts.map +1 -1
  16. package/dist/components/chat/chat-history.d.ts +24 -0
  17. package/dist/components/chat/chat-history.d.ts.map +1 -0
  18. package/dist/components/editor/AudienceIndicator.d.ts +6 -0
  19. package/dist/components/editor/AudienceIndicator.d.ts.map +1 -1
  20. package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -1
  21. package/dist/components/editor/ColSpanControl.d.ts.map +1 -1
  22. package/dist/components/editor/DragHandle.d.ts +3 -1
  23. package/dist/components/editor/DragHandle.d.ts.map +1 -1
  24. package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
  25. package/dist/components/editor/StatusIndicator.d.ts +7 -0
  26. package/dist/components/editor/StatusIndicator.d.ts.map +1 -1
  27. package/dist/components/editor/index.js +100 -78
  28. package/dist/components/primitives/index.js +5 -5
  29. package/dist/components/sections/Container/Container.d.ts +3 -2
  30. package/dist/components/sections/Container/Container.d.ts.map +1 -1
  31. package/dist/components/sections/Container/ContainerSettingsForm.d.ts +4 -2
  32. package/dist/components/sections/Container/ContainerSettingsForm.d.ts.map +1 -1
  33. package/dist/components/sections/Container/index.d.ts +8 -2
  34. package/dist/components/sections/Container/index.d.ts.map +1 -1
  35. package/dist/components/sections/SectionLayout.d.ts +3 -1
  36. package/dist/components/sections/SectionLayout.d.ts.map +1 -1
  37. package/dist/components/sections/ViewRenderer.d.ts +3 -1
  38. package/dist/components/sections/ViewRenderer.d.ts.map +1 -1
  39. package/dist/components/sections/all-sections.d.ts +8 -2
  40. package/dist/components/sections/all-sections.d.ts.map +1 -1
  41. package/dist/components/sections/brand-guide.js +5 -5
  42. package/dist/components/sections/core-sections.d.ts +8 -2
  43. package/dist/components/sections/core-sections.d.ts.map +1 -1
  44. package/dist/components/sections/register-schemas.js +8 -8
  45. package/dist/components/sections/register.js +8 -8
  46. package/dist/components/shared/Navigation.d.ts +6 -1
  47. package/dist/components/shared/Navigation.d.ts.map +1 -1
  48. package/dist/components/shared/Tooltip.d.ts +8 -1
  49. package/dist/components/shared/Tooltip.d.ts.map +1 -1
  50. package/dist/components/shell/AudiencePreviewMenu.d.ts +7 -0
  51. package/dist/components/shell/AudiencePreviewMenu.d.ts.map +1 -0
  52. package/dist/components/shell/AuthoringDefaultsMenu.d.ts +10 -0
  53. package/dist/components/shell/AuthoringDefaultsMenu.d.ts.map +1 -0
  54. package/dist/components/shell/EditorContext.d.ts +3 -0
  55. package/dist/components/shell/EditorContext.d.ts.map +1 -1
  56. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  57. package/dist/components/shell/MediaLibraryContext.d.ts +3 -1
  58. package/dist/components/shell/MediaLibraryContext.d.ts.map +1 -1
  59. package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
  60. package/dist/hooks/useBuildStatus.d.ts.map +1 -1
  61. package/dist/hooks/useMediaPipeline.d.ts +5 -1
  62. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  63. package/dist/index.js +17 -5
  64. package/dist/lib/authoring-defaults.d.ts +17 -0
  65. package/dist/lib/authoring-defaults.d.ts.map +1 -0
  66. package/dist/lib/chatbot.d.ts +10 -0
  67. package/dist/lib/chatbot.d.ts.map +1 -0
  68. package/dist/lib/container-grid.d.ts +6 -0
  69. package/dist/lib/container-grid.d.ts.map +1 -1
  70. package/dist/lib/contrast.d.ts +5 -0
  71. package/dist/lib/contrast.d.ts.map +1 -1
  72. package/dist/lib/index.d.ts +2 -1
  73. package/dist/lib/index.d.ts.map +1 -1
  74. package/dist/lib/index.js +11 -3
  75. package/dist/lib/migrate-sections-transform.js +1 -1
  76. package/dist/media/compose-preview.d.ts +23 -0
  77. package/dist/media/compose-preview.d.ts.map +1 -0
  78. package/dist/media/index.d.ts +1 -0
  79. package/dist/media/index.d.ts.map +1 -1
  80. package/dist/media/index.js +4 -2
  81. package/dist/media/preview-inputs.d.ts +31 -0
  82. package/dist/media/preview-inputs.d.ts.map +1 -0
  83. package/dist/schemas/index.js +4 -2
  84. package/dist/schemas/media.d.ts +2 -0
  85. package/dist/schemas/media.d.ts.map +1 -1
  86. package/dist/schemas/site-config.d.ts +18 -0
  87. package/dist/schemas/site-config.d.ts.map +1 -1
  88. package/package.json +1 -1
  89. package/src/components/chat/ChatPanel.tsx +437 -65
  90. package/src/components/chat/ChatWidget.tsx +90 -32
  91. package/src/components/chat/chat-history.ts +105 -0
  92. package/src/components/editor/AudienceIndicator.tsx +50 -37
  93. package/src/components/editor/ChildBlockWrapper.tsx +8 -7
  94. package/src/components/editor/ColSpanControl.tsx +14 -11
  95. package/src/components/editor/DragHandle.tsx +5 -2
  96. package/src/components/editor/PagesModal.tsx +10 -10
  97. package/src/components/editor/SectionWrapper.tsx +32 -21
  98. package/src/components/editor/StatusIndicator.tsx +37 -24
  99. package/src/components/sections/Container/Container.tsx +185 -43
  100. package/src/components/sections/Container/ContainerSettingsForm.tsx +64 -24
  101. package/src/components/sections/Container/index.tsx +45 -20
  102. package/src/components/sections/SectionLayout.tsx +13 -3
  103. package/src/components/sections/ViewRenderer.tsx +11 -2
  104. package/src/components/shared/Navigation.tsx +18 -5
  105. package/src/components/shared/Tooltip.tsx +18 -2
  106. package/src/components/shell/AudiencePreviewMenu.tsx +73 -0
  107. package/src/components/shell/AuthoringDefaultsMenu.tsx +54 -0
  108. package/src/components/shell/EditorContext.tsx +5 -1
  109. package/src/components/shell/EditorShell.tsx +130 -13
  110. package/src/components/shell/MediaLibraryContext.tsx +1 -1
  111. package/src/components/shell/SiteSettingsChatbot.tsx +49 -1
  112. package/src/hooks/useBuildStatus.ts +35 -4
  113. package/src/hooks/useMediaPipeline.ts +7 -3
  114. package/src/lib/authoring-defaults.ts +42 -0
  115. package/src/lib/chatbot.ts +30 -0
  116. package/src/lib/container-grid.ts +14 -0
  117. package/src/lib/contrast.ts +12 -0
  118. package/src/lib/index.ts +2 -1
  119. package/src/lib/migrate-sections-transform.ts +5 -3
  120. package/src/media/compose-preview.ts +90 -0
  121. package/src/media/index.ts +1 -0
  122. package/src/media/preview-inputs.ts +77 -0
  123. package/src/schemas/media.ts +3 -0
  124. package/src/schemas/site-config.ts +27 -2
@@ -3,23 +3,25 @@ import {
3
3
  pluralize,
4
4
  stripHtmlToPlainText,
5
5
  truncate
6
- } from "./chunk-SK6GGTTO.js";
6
+ } from "./chunk-XUIJHYKI.js";
7
7
  import {
8
8
  DeleteButton,
9
9
  DragHandle,
10
+ Kbd,
10
11
  Popover,
11
12
  PopoverItem,
12
13
  SettingsButton,
13
14
  SettingsForm,
15
+ Tooltip,
14
16
  buildBlockDragData,
15
17
  buildBlockDropData,
16
18
  canDropBlock,
17
19
  isBlockDragData
18
- } from "./chunk-XDG2K6UT.js";
20
+ } from "./chunk-SIYQ37QY.js";
19
21
  import {
20
22
  EditableRichText,
21
23
  defineHeadingSection
22
- } from "./chunk-PTVY3Q7P.js";
24
+ } from "./chunk-KBQNJZUX.js";
23
25
  import {
24
26
  EditablePlainText,
25
27
  ImageDropZone,
@@ -27,12 +29,13 @@ import {
27
29
  MediaBlock,
28
30
  colSpanClass,
29
31
  containerGridClass,
32
+ masonryColumnsClass,
30
33
  spacerHiddenClass
31
- } from "./chunk-NEDOJHHR.js";
34
+ } from "./chunk-XKRQMTE4.js";
32
35
  import {
33
36
  useMediaLibrary,
34
37
  useResolvedMedia
35
- } from "./chunk-EO7K45GV.js";
38
+ } from "./chunk-NV4R6VHN.js";
36
39
  import {
37
40
  embedUrl
38
41
  } from "./chunk-Y4JQGO6G.js";
@@ -51,7 +54,7 @@ import {
51
54
  } from "./chunk-TZQPOR5A.js";
52
55
  import {
53
56
  SingleMediaReferenceSchema
54
- } from "./chunk-XPUBUR64.js";
57
+ } from "./chunk-KMQZYORS.js";
55
58
  import {
56
59
  defineSection,
57
60
  getSection
@@ -483,14 +486,17 @@ import { CopyPlus } from "lucide-react";
483
486
  // src/components/editor/ColSpanControl.tsx
484
487
  import { useRef, useState } from "react";
485
488
  import { Columns3 } from "lucide-react";
486
- import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
489
+ import { Fragment, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
487
490
  function ColSpanControl({ colSpan, columns, onChange }) {
488
491
  const buttonRef = useRef(null);
489
492
  const [open, setOpen] = useState(false);
490
493
  if (columns <= 1) return null;
491
494
  const current = Math.min(Math.max(colSpan, 1), columns);
492
495
  return /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
493
- /* @__PURE__ */ jsx11(
496
+ /* @__PURE__ */ jsx11(Tooltip, { side: "right", content: /* @__PURE__ */ jsxs3(Fragment, { children: [
497
+ /* @__PURE__ */ jsx11(Kbd, { children: "Set" }),
498
+ " column span"
499
+ ] }), children: /* @__PURE__ */ jsx11(
494
500
  "button",
495
501
  {
496
502
  ref: buttonRef,
@@ -502,7 +508,7 @@ function ColSpanControl({ colSpan, columns, onChange }) {
502
508
  className: "pointer-events-auto inline-flex cursor-pointer items-center gap-1 rounded p-1 text-xs text-base-contrast-light hover:text-primary",
503
509
  children: /* @__PURE__ */ jsx11(Columns3, { size: 14 })
504
510
  }
505
- ),
511
+ ) }),
506
512
  /* @__PURE__ */ jsx11(Popover, { isOpen: open, onClose: () => setOpen(false), anchorRef: buttonRef, className: "min-w-28", children: /* @__PURE__ */ jsx11("ul", { role: "list", className: "py-1", children: Array.from({ length: columns }, (_, i) => i + 1).map((span) => /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs3(
507
513
  PopoverItem,
508
514
  {
@@ -522,7 +528,7 @@ function ColSpanControl({ colSpan, columns, onChange }) {
522
528
  }
523
529
 
524
530
  // src/components/editor/ChildBlockWrapper.tsx
525
- import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
531
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
526
532
  var ChildBlockWrapper = forwardRef(
527
533
  function ChildBlockWrapper2({
528
534
  label,
@@ -559,10 +565,16 @@ var ChildBlockWrapper = forwardRef(
559
565
  ),
560
566
  children: [
561
567
  /* @__PURE__ */ jsx12("span", { className: "sr-only", children: label }),
562
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DragHandle, { ref: dragHandleRef }) }),
568
+ /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DragHandle, { ref: dragHandleRef, tooltipSide: "right" }) }),
563
569
  /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
564
- hasSettings && onOpenSettings && /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(SettingsButton, { onClick: onOpenSettings }) }),
565
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(
570
+ hasSettings && onOpenSettings && /* @__PURE__ */ jsx12(Tooltip, { side: "right", className: "pointer-events-auto", content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
571
+ /* @__PURE__ */ jsx12(Kbd, { children: "Edit" }),
572
+ " settings"
573
+ ] }), children: /* @__PURE__ */ jsx12(SettingsButton, { onClick: onOpenSettings }) }),
574
+ /* @__PURE__ */ jsx12(Tooltip, { side: "right", className: "pointer-events-auto", content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
575
+ /* @__PURE__ */ jsx12(Kbd, { children: "Duplicate" }),
576
+ " block"
577
+ ] }), children: /* @__PURE__ */ jsx12(
566
578
  "button",
567
579
  {
568
580
  type: "button",
@@ -572,7 +584,10 @@ var ChildBlockWrapper = forwardRef(
572
584
  children: /* @__PURE__ */ jsx12(CopyPlus, { size: 16 })
573
585
  }
574
586
  ) }),
575
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DeleteButton, { onDelete }) })
587
+ /* @__PURE__ */ jsx12(Tooltip, { side: "right", className: "pointer-events-auto", content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
588
+ /* @__PURE__ */ jsx12(Kbd, { children: "Delete" }),
589
+ " block"
590
+ ] }), children: /* @__PURE__ */ jsx12(DeleteButton, { onDelete }) })
576
591
  ]
577
592
  }
578
593
  ),
@@ -769,7 +784,6 @@ function ContainerChild({
769
784
  index,
770
785
  child,
771
786
  columns,
772
- flow,
773
787
  cellClass,
774
788
  label,
775
789
  hasSettings,
@@ -782,7 +796,8 @@ function ContainerChild({
782
796
  onColSpanChange,
783
797
  onOpenSettings,
784
798
  onChildContentChange,
785
- openModal
799
+ openModal,
800
+ allowedEdges = ROW_EDGES
786
801
  }) {
787
802
  const isContainer = Array.isArray(child.content?.children);
788
803
  const { dragRef, handleRef, closestEdge, isDragging } = useBlockDnd({
@@ -790,7 +805,7 @@ function ContainerChild({
790
805
  containerId,
791
806
  index,
792
807
  isContainer,
793
- allowedEdges: flow === "column" ? COL_EDGES : ROW_EDGES,
808
+ allowedEdges,
794
809
  enabled: true
795
810
  });
796
811
  return /* @__PURE__ */ jsx13(
@@ -858,11 +873,37 @@ function EmptyColumnCell({
858
873
  }
859
874
  );
860
875
  }
876
+ function MasonryDropZone({
877
+ containerId,
878
+ index,
879
+ testId
880
+ }) {
881
+ const { dropRef, closestEdge } = useBlockDropZone({
882
+ containerId,
883
+ index,
884
+ allowedEdges: COL_EDGES,
885
+ enabled: true
886
+ });
887
+ const active = closestEdge !== null;
888
+ return /* @__PURE__ */ jsx13(
889
+ "div",
890
+ {
891
+ ref: dropRef,
892
+ "data-masonry-dropzone": true,
893
+ "data-testid": testId,
894
+ className: cn(
895
+ "mb-8 flex min-h-20 items-center justify-center rounded-md border-2 border-dashed break-inside-avoid text-xs text-base-contrast-light/50",
896
+ active ? "border-primary" : "border-base-200"
897
+ ),
898
+ children: index === 0 ? "Empty container \u2014 drag items here or use the + button" : "Drop here to add"
899
+ }
900
+ );
901
+ }
861
902
  function newId() {
862
903
  return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `child-${Math.random().toString(36).slice(2)}-${Date.now()}`;
863
904
  }
864
905
  function Container({ content, isEditMode, onChange, openModal }) {
865
- const { columns, flow, childDefaults, children } = content.content;
906
+ const { layout, columns, equalizeRowHeight, childDefaults, children } = content.content;
866
907
  const editable = isEditMode && !!onChange;
867
908
  const container = {
868
909
  id: content.id ?? "container",
@@ -883,8 +924,104 @@ function Container({ content, isEditMode, onChange, openModal }) {
883
924
  "grid",
884
925
  "gap-8",
885
926
  containerGridClass[columns] ?? "grid-cols-1",
886
- flow === "column" && "grid-flow-col"
927
+ equalizeRowHeight && "items-stretch"
887
928
  );
929
+ const cellStretch = equalizeRowHeight ? "h-full [&>*]:h-full" : void 0;
930
+ function buildOnOpenSettings(child, index) {
931
+ const def = getSection(child.type);
932
+ if (!def) return void 0;
933
+ const hasSettings = !!(def.settings || def.settingsForm) && !!openModal;
934
+ if (!hasSettings || !openModal) return void 0;
935
+ const childOptions = "options" in child ? child.options : void 0;
936
+ return () => {
937
+ const childOpts = childOptions ?? {};
938
+ const childContent = child.content ?? {};
939
+ const seed = { ...childContent, ...childOpts };
940
+ const applyResult = (result) => updateChild(index, {
941
+ ...child,
942
+ content: { ...child.content, ...result.content },
943
+ options: { ...childOpts, ...result.options }
944
+ });
945
+ if (def.settingsForm) {
946
+ const CustomForm = def.settingsForm;
947
+ openModal(`${def.label} Settings`, /* @__PURE__ */ jsx13(CustomForm, { ...seed, onChange: applyResult }));
948
+ } else if (def.settings) {
949
+ openModal(
950
+ `${def.label} Settings`,
951
+ /* @__PURE__ */ jsx13(
952
+ SettingsForm,
953
+ {
954
+ schema: def.settings,
955
+ values: seed,
956
+ onChange: applyResult,
957
+ tabs: def.settingsTabs
958
+ }
959
+ )
960
+ );
961
+ }
962
+ };
963
+ }
964
+ if (layout === "masonry") {
965
+ const laidOut = children.map((child, index) => ({ child, index })).filter(({ child }) => !isSpacer(child));
966
+ const masonryClass = cn("gap-8", masonryColumnsClass[columns] ?? "columns-1");
967
+ if (!editable) {
968
+ if (laidOut.length === 0) return null;
969
+ return /* @__PURE__ */ jsx13("div", { className: "@container", children: /* @__PURE__ */ jsx13("div", { "data-masonry": true, className: masonryClass, children: laidOut.map(({ child, index }) => {
970
+ const def = getSection(child.type);
971
+ if (!def) return null;
972
+ const Child = def.component;
973
+ const childOptions = "options" in child ? child.options : void 0;
974
+ const mergedOptions = { ...childDefaults ?? {}, ...childOptions ?? {} };
975
+ return /* @__PURE__ */ jsx13(
976
+ "div",
977
+ {
978
+ "data-masonry-box": true,
979
+ "data-child-index": index,
980
+ className: "mb-8 break-inside-avoid",
981
+ children: /* @__PURE__ */ jsx13(Child, { content: child, options: mergedOptions, isEditMode })
982
+ },
983
+ child.id ?? index
984
+ );
985
+ }) }) });
986
+ }
987
+ if (laidOut.length === 0) {
988
+ return /* @__PURE__ */ jsx13("div", { className: "@container", children: /* @__PURE__ */ jsx13("div", { "data-masonry": true, className: masonryClass, children: /* @__PURE__ */ jsx13(MasonryDropZone, { containerId: container.id, index: 0, testId: "masonry-empty" }) }) });
989
+ }
990
+ return /* @__PURE__ */ jsx13("div", { className: "@container", children: /* @__PURE__ */ jsxs5("div", { "data-masonry": true, className: masonryClass, children: [
991
+ laidOut.map(({ child, index }, k) => {
992
+ const def = getSection(child.type);
993
+ if (!def) return null;
994
+ const childOptions = "options" in child ? child.options : void 0;
995
+ const mergedOptions = { ...childDefaults ?? {}, ...childOptions ?? {} };
996
+ const hasSettings = !!(def.settings || def.settingsForm) && !!openModal;
997
+ return /* @__PURE__ */ jsx13("div", { "data-masonry-box": true, className: "mb-8 break-inside-avoid", children: /* @__PURE__ */ jsx13(
998
+ ContainerChild,
999
+ {
1000
+ containerId: container.id,
1001
+ index,
1002
+ child,
1003
+ columns: 1,
1004
+ cellClass: void 0,
1005
+ label: def.label,
1006
+ hasSettings,
1007
+ mergedOptions,
1008
+ isEditMode,
1009
+ clearSectionChrome: k === 0,
1010
+ ChildComp: def.component,
1011
+ onDelete: () => emit(removeChildAt(container, index).container),
1012
+ onDuplicate: () => emit(duplicateChildAt(container, index, newId)),
1013
+ onColSpanChange: () => {
1014
+ },
1015
+ onOpenSettings: buildOnOpenSettings(child, index),
1016
+ onChildContentChange: (c) => updateChild(index, c),
1017
+ openModal,
1018
+ allowedEdges: COL_EDGES
1019
+ }
1020
+ ) }, child.id ?? index);
1021
+ }),
1022
+ /* @__PURE__ */ jsx13(MasonryDropZone, { containerId: container.id, index: children.length, testId: "masonry-append" })
1023
+ ] }) });
1024
+ }
888
1025
  if (!editable) {
889
1026
  return /* @__PURE__ */ jsx13("div", { className: "@container", children: /* @__PURE__ */ jsx13("div", { className: gridClass, children: children.map((child, index) => {
890
1027
  const def = getSection(child.type);
@@ -895,7 +1032,8 @@ function Container({ content, isEditMode, onChange, openModal }) {
895
1032
  const mergedOptions = { ...childDefaults ?? {}, ...childOptions ?? {} };
896
1033
  const cellClass = cn(
897
1034
  colSpanClass[columns]?.[Math.min(span, columns)] || void 0,
898
- child.type === "spacer" && spacerHiddenClass[columns]
1035
+ child.type === "spacer" && spacerHiddenClass[columns],
1036
+ cellStretch
899
1037
  );
900
1038
  return /* @__PURE__ */ jsx13("div", { className: cellClass, children: /* @__PURE__ */ jsx13(Child, { content: child, options: mergedOptions, isEditMode }) }, child.id ?? index);
901
1039
  }) }) });
@@ -924,38 +1062,12 @@ function Container({ content, isEditMode, onChange, openModal }) {
924
1062
  const span = child.layout?.colSpan ?? 1;
925
1063
  const childOptions = "options" in child ? child.options : void 0;
926
1064
  const mergedOptions = { ...childDefaults ?? {}, ...childOptions ?? {} };
927
- const cellClass = colSpanClass[columns]?.[Math.min(span, columns)] || void 0;
1065
+ const cellClass = cn(
1066
+ colSpanClass[columns]?.[Math.min(span, columns)] || void 0,
1067
+ cellStretch
1068
+ );
928
1069
  const hasSettings = !!(def.settings || def.settingsForm) && !!openModal;
929
- const onOpenSettings = hasSettings && openModal ? () => {
930
- const childOpts = childOptions ?? {};
931
- const childContent = child.content ?? {};
932
- const seed = { ...childContent, ...childOpts };
933
- const applyResult = (result) => updateChild(index, {
934
- ...child,
935
- content: { ...child.content, ...result.content },
936
- options: { ...childOpts, ...result.options }
937
- });
938
- if (def.settingsForm) {
939
- const CustomForm = def.settingsForm;
940
- openModal(
941
- `${def.label} Settings`,
942
- /* @__PURE__ */ jsx13(CustomForm, { ...seed, onChange: applyResult })
943
- );
944
- } else if (def.settings) {
945
- openModal(
946
- `${def.label} Settings`,
947
- /* @__PURE__ */ jsx13(
948
- SettingsForm,
949
- {
950
- schema: def.settings,
951
- values: seed,
952
- onChange: applyResult,
953
- tabs: def.settingsTabs
954
- }
955
- )
956
- );
957
- }
958
- } : void 0;
1070
+ const onOpenSettings = buildOnOpenSettings(child, index);
959
1071
  return /* @__PURE__ */ jsx13(
960
1072
  ContainerChild,
961
1073
  {
@@ -963,7 +1075,6 @@ function Container({ content, isEditMode, onChange, openModal }) {
963
1075
  index,
964
1076
  child,
965
1077
  columns,
966
- flow,
967
1078
  cellClass,
968
1079
  label: def.label,
969
1080
  hasSettings,
@@ -1014,12 +1125,17 @@ function inheritableSchema(children) {
1014
1125
  }
1015
1126
  function ContainerSettingsForm({
1016
1127
  columns = 1,
1017
- flow = "row",
1128
+ layout: layoutProp = "grid",
1129
+ equalizeRowHeight = false,
1018
1130
  childDefaults = {},
1019
1131
  children = [],
1020
1132
  onChange
1021
1133
  }) {
1022
- const [layout, setLayout] = useState3({ columns, flow });
1134
+ const [layout, setLayout] = useState3({
1135
+ layout: layoutProp,
1136
+ columns,
1137
+ equalizeRowHeight
1138
+ });
1023
1139
  const [defaults, setDefaults] = useState3(childDefaults);
1024
1140
  const childSchema = inheritableSchema(children);
1025
1141
  const hasChildDefaults = Object.keys(childSchema).length > 0;
@@ -1027,27 +1143,41 @@ function ContainerSettingsForm({
1027
1143
  onChange({ content: { ...nextLayout, childDefaults: nextDefaults }, options: {} });
1028
1144
  }
1029
1145
  const layoutSchema = {
1146
+ layout: {
1147
+ type: "select",
1148
+ label: "Layout",
1149
+ default: layout.layout,
1150
+ target: "content",
1151
+ options: [
1152
+ { label: "Grid", value: "grid" },
1153
+ { label: "Masonry (image gallery)", value: "masonry" }
1154
+ ]
1155
+ },
1030
1156
  columns: {
1031
1157
  type: "select",
1032
1158
  label: "Columns",
1033
1159
  default: String(layout.columns),
1034
1160
  target: "content",
1035
1161
  coerce: "number",
1036
- options: Array.from({ length: MAX_CONTAINER_COLUMNS }, (_, i) => ({
1037
- label: String(i + 1),
1038
- value: String(i + 1)
1039
- }))
1162
+ // Masonry's CSS multi-column flow needs at least 2 columns to read as a
1163
+ // gallery (1 column would just be a plain stack, same as grid), so floor
1164
+ // the options at 2 there; grid still allows 1 (a single-column stack).
1165
+ options: Array.from(
1166
+ { length: layout.layout === "masonry" ? MAX_CONTAINER_COLUMNS - 1 : MAX_CONTAINER_COLUMNS },
1167
+ (_, i) => {
1168
+ const n = layout.layout === "masonry" ? i + 2 : i + 1;
1169
+ return { label: String(n), value: String(n) };
1170
+ }
1171
+ )
1040
1172
  },
1041
- flow: {
1042
- type: "select",
1043
- label: "Flow",
1044
- default: layout.flow,
1045
- target: "content",
1046
- options: [
1047
- { label: "Rows (wrap across)", value: "row" },
1048
- { label: "Columns (fill down)", value: "column" }
1049
- ]
1050
- }
1173
+ ...layout.layout === "grid" ? {
1174
+ equalizeRowHeight: {
1175
+ type: "checkbox",
1176
+ label: "Equalize row height",
1177
+ default: layout.equalizeRowHeight,
1178
+ target: "content"
1179
+ }
1180
+ } : {}
1051
1181
  };
1052
1182
  return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-6", children: [
1053
1183
  /* @__PURE__ */ jsxs6("fieldset", { className: "flex flex-col gap-4", children: [
@@ -1056,16 +1186,23 @@ function ContainerSettingsForm({
1056
1186
  SettingsForm,
1057
1187
  {
1058
1188
  schema: layoutSchema,
1059
- values: { columns: String(layout.columns), flow: layout.flow },
1189
+ values: {
1190
+ layout: layout.layout,
1191
+ columns: String(layout.columns),
1192
+ equalizeRowHeight: layout.equalizeRowHeight
1193
+ },
1060
1194
  onChange: (result) => {
1061
1195
  const next = {
1196
+ layout: result.content.layout ?? layout.layout,
1062
1197
  columns: Number(result.content.columns ?? layout.columns),
1063
- flow: String(result.content.flow ?? layout.flow)
1198
+ equalizeRowHeight: result.content.equalizeRowHeight ?? layout.equalizeRowHeight
1064
1199
  };
1200
+ if (next.layout === "masonry" && next.columns < 2) next.columns = 2;
1065
1201
  setLayout(next);
1066
1202
  emit(next, defaults);
1067
1203
  }
1068
- }
1204
+ },
1205
+ layout.layout
1069
1206
  )
1070
1207
  ] }),
1071
1208
  hasChildDefaults && /* @__PURE__ */ jsxs6("fieldset", { className: "flex flex-col gap-4 border-t border-base-200 pt-4", children: [
@@ -1091,33 +1228,55 @@ import { jsx as jsx15 } from "react/jsx-runtime";
1091
1228
  var schema5 = z5.object({
1092
1229
  type: z5.literal("container"),
1093
1230
  content: z5.object({
1094
- columns: z5.number().int().min(1).max(MAX_CONTAINER_COLUMNS).describe("Number of columns in the grid. Children flow across this many columns.").default(1),
1095
- flow: z5.enum(["row", "column"]).describe(
1096
- "Layout direction: 'row' (children flow left-to-right across columns) or 'column' (stacked)."
1097
- ).default("row"),
1231
+ layout: z5.enum(["grid", "masonry"]).describe(
1232
+ "Layout engine: 'grid' arranges children in fixed columns with per-child column spans; 'masonry' flows children through a CSS multi-column gallery at their natural height (no column spans)."
1233
+ ).default("grid"),
1234
+ columns: z5.number().int().min(1).max(MAX_CONTAINER_COLUMNS).describe(
1235
+ "Grid: number of columns children flow across. Masonry: number of CSS multi-columns children flow through."
1236
+ ).default(1),
1237
+ equalizeRowHeight: z5.boolean().describe(
1238
+ "Grid only: stretch every child to the height of the tallest child in its row (best-effort \u2014 applies to children whose root element can stretch, e.g. media/cards). Ignored in masonry."
1239
+ ).default(false),
1098
1240
  childDefaults: z5.record(z5.string(), z5.unknown()).describe("Optional default option values applied to child sections (inheritable settings only).").optional(),
1099
1241
  // Recursive: children are full blocks. z.lazy defers evaluation to parse
1100
1242
  // time, by which point every section schema (incl. container) is registered.
1101
1243
  children: z5.array(z5.lazy(() => getSectionSchema())).default([])
1102
- }).transform((c) => ({
1103
- ...c,
1104
- children: c.children.map(
1105
- (child) => child.layout?.colSpan && child.layout.colSpan > c.columns ? { ...child, layout: { ...child.layout, colSpan: c.columns } } : child
1106
- )
1107
- }))
1244
+ }).transform((c) => {
1245
+ if (c.layout === "masonry") {
1246
+ return {
1247
+ ...c,
1248
+ children: c.children.map((child) => {
1249
+ if (child.layout === void 0) return child;
1250
+ const { layout: _drop, ...rest } = child;
1251
+ return rest;
1252
+ })
1253
+ };
1254
+ }
1255
+ return {
1256
+ ...c,
1257
+ children: c.children.map(
1258
+ (child) => child.layout?.colSpan && child.layout.colSpan > c.columns ? { ...child, layout: { ...child.layout, colSpan: c.columns } } : child
1259
+ )
1260
+ };
1261
+ })
1108
1262
  });
1109
1263
  var Container_default = defineSection({
1110
1264
  type: "container",
1111
1265
  label: "Container",
1112
1266
  icon: /* @__PURE__ */ jsx15(LayoutTemplate, { size: 18 }),
1113
1267
  schema: schema5,
1114
- authoringNote: "A layout wrapper that arranges child sections into columns/rows. Use to place blocks side by side or build multi-column layouts; set columns and add children.",
1268
+ authoringNote: "A layout wrapper for child sections. 'grid' arranges children into a fixed number of columns (each child can span multiple columns) with an optional equal-row-height toggle; 'masonry' flows children through a CSS multi-column gallery at their natural height (no column spans). Set layout, columns, and add children.",
1115
1269
  component: ({ content, onChange, isEditMode, openModal }) => /* @__PURE__ */ jsx15(Container, { content, isEditMode: !!isEditMode, onChange, openModal }),
1116
1270
  defaults: () => ({
1117
1271
  type: "container",
1118
- content: { columns: 1, flow: "row", children: [] }
1272
+ content: { layout: "grid", columns: 1, equalizeRowHeight: false, children: [] }
1119
1273
  }),
1120
1274
  getLabel: (content) => `Container (${pluralize(content.content.children.length, "item")})`,
1275
+ // Aggregate child thumbnails so the reorder-sections modal shows a stacked media
1276
+ // preview for a container (restores the retired media_grid preview). Each child is a
1277
+ // full section block; delegate to its own type's getThumbnails. The modal caps the
1278
+ // stack at 3 + a "+N" badge and resolves each imageId → src itself.
1279
+ getThumbnails: (content) => content.content.children.flatMap((child) => getSection(child.type)?.getThumbnails?.(child) ?? []),
1121
1280
  settingsForm: ContainerSettingsForm
1122
1281
  });
1123
1282
 
@@ -2,6 +2,11 @@ export interface ChatMessage {
2
2
  role: "user" | "assistant";
3
3
  content: string;
4
4
  }
5
+ /** How the conversation is framed on screen:
6
+ * - "floating": the compact anchored panel (/edit FAB + settings test chat)
7
+ * - "docked": full-height right sidebar (viewer, >=768px)
8
+ * - "sheet": bottom sheet (viewer, phones) */
9
+ export type ChatPanelMode = "floating" | "docked" | "sheet";
5
10
  /** Assistant markdown → sanitized HTML. Callers MUST gate on the sanitizer
6
11
  * having loaded (`mdReady`) — before then sanitizeHtml passes raw HTML
7
12
  * through, and model output is untrusted. Exported for tests. */
@@ -13,7 +18,7 @@ export declare function streamChat(body: {
13
18
  taskId?: string;
14
19
  draftChatbot?: unknown;
15
20
  simulateAudience?: string;
16
- }, onText: (text: string) => void): Promise<{
21
+ }, onText: (text: string) => void, signal?: AbortSignal): Promise<{
17
22
  ok: true;
18
23
  truncated: boolean;
19
24
  } | {
@@ -21,10 +26,14 @@ export declare function streamChat(body: {
21
26
  error: string;
22
27
  retryAfterMs?: number;
23
28
  }>;
24
- export default function ChatPanel({ open, onClose, siteName, tasks, isEditor, draftChatbot, simulateAudience, variant }: {
29
+ export default function ChatPanel({ open, onClose, siteName, botName, thinkingPhrases, tasks, isEditor, draftChatbot, simulateAudience, variant, mode, focusComposer, audience }: {
25
30
  open: boolean;
26
31
  onClose: () => void;
27
32
  siteName: string;
33
+ /** Resolved assistant display name (per-audience, server-side). */
34
+ botName: string;
35
+ /** Raw configured phrases; "…" appending + fallback happen here. */
36
+ thinkingPhrases?: string[];
28
37
  tasks: {
29
38
  id: string;
30
39
  label: string;
@@ -34,7 +43,15 @@ export default function ChatPanel({ open, onClose, siteName, tasks, isEditor, dr
34
43
  draftChatbot?: unknown;
35
44
  /** Configurator test panel only: preview this audience's prompt overlay. */
36
45
  simulateAudience?: string;
37
- /** Anchors the panel above its launcher: viewer corner FAB vs /edit FAB column. */
46
+ /** Floating mode only — anchors the panel above its launcher: viewer corner
47
+ * FAB vs /edit FAB column. */
38
48
  variant?: "viewer" | "editor";
49
+ mode?: ChatPanelMode;
50
+ /** Focus the composer when opened (explicit user open on desktop). Never
51
+ * used for the sheet — autofocusing there pops the keyboard over content. */
52
+ focusComposer?: boolean;
53
+ /** Viewer's audience (null for editor sessions) — tags history entries so
54
+ * the list never shows another audience's transcripts. */
55
+ audience?: string | null;
39
56
  }): import("react/jsx-runtime").JSX.Element | null;
40
57
  //# sourceMappingURL=ChatPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../../src/components/chat/ChatPanel.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAoB5E;;kEAEkE;AAClE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhD;AAcD,8EAA8E;AAC9E,wBAAsB,UAAU,CAC9B,IAAI,EAAE;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EACxH,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC7B,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyCjG;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAkB,EAAE,EAAE;IAClI,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC/B,kDA8JA"}
1
+ {"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../../src/components/chat/ChatPanel.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAE5E;;;kDAGkD;AAClD,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;AA8C5D;;kEAEkE;AAClE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhD;AAcD,8EAA8E;AAC9E,wBAAsB,UAAU,CAC9B,IAAI,EAAE;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EACxH,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6CjG;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAkB,EAAE,IAAiB,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE;IACxM,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;mCAC+B;IAC/B,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;kFAC8E;IAC9E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;+DAC2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,kDA8dA"}
@@ -1,5 +1,9 @@
1
1
  export interface ChatWidgetProps {
2
2
  siteName: string;
3
+ /** Resolved assistant display name (per-audience, resolved server-side). */
4
+ botName: string;
5
+ /** Configured waiting phrases ("…" appended in the panel). */
6
+ thinkingPhrases?: string[];
3
7
  /** Already audience-filtered server-side — never pass unfiltered config tasks. */
4
8
  tasks: {
5
9
  id: string;
@@ -9,6 +13,8 @@ export interface ChatWidgetProps {
9
13
  /** Editor-only: chat against the current (unsaved) chatbot config. */
10
14
  draftChatbot?: unknown;
11
15
  variant?: "viewer" | "editor";
16
+ /** Viewer's audience (null for editor sessions) — tags local chat history. */
17
+ audience?: string | null;
12
18
  }
13
- export default function ChatWidget({ siteName, tasks, isEditor, draftChatbot, variant }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
19
+ export default function ChatWidget({ siteName, botName, thinkingPhrases, tasks, isEditor, draftChatbot, variant, audience }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
14
20
  //# sourceMappingURL=ChatWidget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../../src/components/chat/ChatWidget.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC/B;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAkB,EAAE,EAAE,eAAe,2CA2ClH"}
1
+ {"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../../src/components/chat/ChatWidget.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,kFAAkF;IAClF,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAkB,EAAE,QAAQ,EAAE,EAAE,eAAe,2CAyFtJ"}
@@ -0,0 +1,24 @@
1
+ import type { ChatMessage } from "./ChatPanel";
2
+ export declare const HISTORY_RETENTION_DAYS = 30;
3
+ export declare const HISTORY_MAX_UNPINNED = 20;
4
+ export interface StoredConversation {
5
+ id: string;
6
+ title: string;
7
+ /** Audience tag ("editor" for editor sessions on viewer pages). */
8
+ audience: string;
9
+ pinned: boolean;
10
+ updatedAt: number;
11
+ messages: ChatMessage[];
12
+ }
13
+ /** Current audience's conversations: pinned first, then newest first. */
14
+ export declare function loadHistory(audience: string, now?: number): StoredConversation[];
15
+ /** Create/refresh a conversation's archive entry (preserves its pinned flag)
16
+ * and apply retention. No-ops on empty transcripts. */
17
+ export declare function upsertConversation(input: {
18
+ id: string;
19
+ audience: string;
20
+ messages: ChatMessage[];
21
+ }, now?: number): void;
22
+ export declare function setConversationPinned(id: string, pinned: boolean): void;
23
+ export declare function removeConversation(id: string): void;
24
+ //# sourceMappingURL=chat-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-history.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-history.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAIvC,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAyCD,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,kBAAkB,EAAE,CAKpF;AAED;wDACwD;AACxD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;CAAE,EAChE,GAAG,SAAa,GACf,IAAI,CAeN;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEnD"}
@@ -1,4 +1,10 @@
1
1
  import type { Audience } from "../../auth/types";
2
+ interface AudienceChecklistProps {
3
+ access: string[];
4
+ audiences: Audience[];
5
+ onToggle: (name: string) => void;
6
+ }
7
+ export declare function AudienceChecklist({ access, audiences, onToggle }: AudienceChecklistProps): import("react/jsx-runtime").JSX.Element;
2
8
  interface AudienceIndicatorProps {
3
9
  access: string[];
4
10
  audiences: Audience[];
@@ -1 +1 @@
1
- {"version":3,"file":"AudienceIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/AudienceIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,sBAAsB,2CAmElG"}
1
+ {"version":3,"file":"AudienceIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/AudienceIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,sBAAsB,2CAyCxF;AAED,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,sBAAsB,2CA+BlG"}