@drawnagency/primitives 0.1.110 → 0.1.112

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 (188) hide show
  1. package/dist/{chunk-3GAG6ZXB.js → chunk-3SZNUCXI.js} +8 -4
  2. package/dist/chunk-4I5OO5UB.js +785 -0
  3. package/dist/{chunk-ALMEC3XN.js → chunk-5KNXTMUC.js} +22 -18
  4. package/dist/{chunk-OUYB2GCW.js → chunk-BR4MIPTM.js} +1 -57
  5. package/dist/chunk-CXZ5YJG4.js +85 -0
  6. package/dist/{chunk-RA5IOFPY.js → chunk-DNY72JZN.js} +16 -38
  7. package/dist/{chunk-7MI3HCOF.js → chunk-EPWBPIV6.js} +10 -6
  8. package/dist/chunk-FV7JQRCN.js +94 -0
  9. package/dist/{chunk-UVIYI4J6.js → chunk-HSXMOS5Q.js} +15 -2
  10. package/dist/chunk-IIDKW7AV.js +41 -0
  11. package/dist/chunk-IINIZBQB.js +204 -0
  12. package/dist/chunk-MM7KZS5C.js +30 -0
  13. package/dist/{chunk-VCCNKTFD.js → chunk-OGGZ5AXT.js} +3 -31
  14. package/dist/{chunk-XQMDWXD6.js → chunk-P3ZNCHW7.js} +1 -1
  15. package/dist/chunk-QQ3S3P5P.js +38 -0
  16. package/dist/{chunk-ELQ4C677.js → chunk-TALRVOGO.js} +9 -44
  17. package/dist/chunk-VAYZJKVR.js +209 -0
  18. package/dist/{chunk-OTDA6KWL.js → chunk-VLPELTPI.js} +1 -1
  19. package/dist/{chunk-7WQJ57XG.js → chunk-VT3PYGVW.js} +68 -260
  20. package/dist/chunk-WUJ3XNFI.js +62 -0
  21. package/dist/{chunk-NXGIHSL5.js → chunk-Z2LO4PSQ.js} +11 -91
  22. package/dist/collab/rebase.js +1 -1
  23. package/dist/components/chat/ChatComposer.d.ts +25 -0
  24. package/dist/components/chat/ChatComposer.d.ts.map +1 -0
  25. package/dist/components/chat/ChatPanel.d.ts +5 -4
  26. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  27. package/dist/components/chat/markdown.d.ts +14 -0
  28. package/dist/components/chat/markdown.d.ts.map +1 -0
  29. package/dist/components/editor/index.js +16 -11
  30. package/dist/components/primitives/EditablePlainText.d.ts.map +1 -1
  31. package/dist/components/primitives/index.js +15 -10
  32. package/dist/components/sections/brand-guide.js +11 -9
  33. package/dist/components/sections/register-schemas.js +19 -14
  34. package/dist/components/sections/register.js +19 -14
  35. package/dist/components/shell/AudienceChips.d.ts +10 -0
  36. package/dist/components/shell/AudienceChips.d.ts.map +1 -0
  37. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  38. package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
  39. package/dist/components/shell/SiteSettingsDecks.d.ts +13 -0
  40. package/dist/components/shell/SiteSettingsDecks.d.ts.map +1 -0
  41. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  42. package/dist/deck/DeckComponentView.d.ts +13 -0
  43. package/dist/deck/DeckComponentView.d.ts.map +1 -0
  44. package/dist/deck/DeckPlayer.d.ts +26 -0
  45. package/dist/deck/DeckPlayer.d.ts.map +1 -0
  46. package/dist/deck/DeckSlideView.d.ts +17 -0
  47. package/dist/deck/DeckSlideView.d.ts.map +1 -0
  48. package/dist/deck/DeckStage.d.ts +16 -0
  49. package/dist/deck/DeckStage.d.ts.map +1 -0
  50. package/dist/deck/components/DeckImage.d.ts +14 -0
  51. package/dist/deck/components/DeckImage.d.ts.map +1 -0
  52. package/dist/deck/components/DeckImageGrid.d.ts +27 -0
  53. package/dist/deck/components/DeckImageGrid.d.ts.map +1 -0
  54. package/dist/deck/components/DeckRichText.d.ts +22 -0
  55. package/dist/deck/components/DeckRichText.d.ts.map +1 -0
  56. package/dist/deck/components/DeckVideo.d.ts +15 -0
  57. package/dist/deck/components/DeckVideo.d.ts.map +1 -0
  58. package/dist/deck/editing.d.ts +50 -0
  59. package/dist/deck/editing.d.ts.map +1 -0
  60. package/dist/deck/flip.d.ts +11 -0
  61. package/dist/deck/flip.d.ts.map +1 -0
  62. package/dist/deck/index.d.ts +24 -0
  63. package/dist/deck/index.d.ts.map +1 -0
  64. package/dist/deck/index.js +53 -0
  65. package/dist/deck/layouts/CenteredTextLayout.d.ts +12 -0
  66. package/dist/deck/layouts/CenteredTextLayout.d.ts.map +1 -0
  67. package/dist/deck/layouts/ColumnSplitLayout.d.ts +14 -0
  68. package/dist/deck/layouts/ColumnSplitLayout.d.ts.map +1 -0
  69. package/dist/deck/layouts/FullBleedImageLayout.d.ts +14 -0
  70. package/dist/deck/layouts/FullBleedImageLayout.d.ts.map +1 -0
  71. package/dist/deck/media.d.ts +33 -0
  72. package/dist/deck/media.d.ts.map +1 -0
  73. package/dist/deck/tokens.d.ts +22 -0
  74. package/dist/deck/tokens.d.ts.map +1 -0
  75. package/dist/deck/useStageScale.d.ts +10 -0
  76. package/dist/deck/useStageScale.d.ts.map +1 -0
  77. package/dist/deck-builder/DeckBuilderApp.d.ts +30 -0
  78. package/dist/deck-builder/DeckBuilderApp.d.ts.map +1 -0
  79. package/dist/deck-builder/DeckBuilderTopBar.d.ts +24 -0
  80. package/dist/deck-builder/DeckBuilderTopBar.d.ts.map +1 -0
  81. package/dist/deck-builder/DeckChatPanel.d.ts +45 -0
  82. package/dist/deck-builder/DeckChatPanel.d.ts.map +1 -0
  83. package/dist/deck-builder/DeckEditor.d.ts +37 -0
  84. package/dist/deck-builder/DeckEditor.d.ts.map +1 -0
  85. package/dist/deck-builder/DeckLibrary.d.ts +22 -0
  86. package/dist/deck-builder/DeckLibrary.d.ts.map +1 -0
  87. package/dist/deck-builder/DeckSlideSurface.d.ts +31 -0
  88. package/dist/deck-builder/DeckSlideSurface.d.ts.map +1 -0
  89. package/dist/deck-builder/deck-api.d.ts +76 -0
  90. package/dist/deck-builder/deck-api.d.ts.map +1 -0
  91. package/dist/deck-builder/deck-chat-client.d.ts +44 -0
  92. package/dist/deck-builder/deck-chat-client.d.ts.map +1 -0
  93. package/dist/deck-builder/deck-chat-history.d.ts +10 -0
  94. package/dist/deck-builder/deck-chat-history.d.ts.map +1 -0
  95. package/dist/deck-builder/index.d.ts +13 -0
  96. package/dist/deck-builder/index.d.ts.map +1 -0
  97. package/dist/deck-builder/index.js +1505 -0
  98. package/dist/deck-builder/starter-deck.d.ts +23 -0
  99. package/dist/deck-builder/starter-deck.d.ts.map +1 -0
  100. package/dist/deck-builder/types.d.ts +29 -0
  101. package/dist/deck-builder/types.d.ts.map +1 -0
  102. package/dist/deck-builder/useSortableSlide.d.ts +29 -0
  103. package/dist/deck-builder/useSortableSlide.d.ts.map +1 -0
  104. package/dist/index.js +70 -63
  105. package/dist/lib/deck-access.d.ts +86 -0
  106. package/dist/lib/deck-access.d.ts.map +1 -0
  107. package/dist/lib/deck-access.js +58 -0
  108. package/dist/lib/deck-dexie.d.ts +88 -0
  109. package/dist/lib/deck-dexie.d.ts.map +1 -0
  110. package/dist/lib/deck-dexie.js +22 -0
  111. package/dist/lib/deck-edit.d.ts +67 -0
  112. package/dist/lib/deck-edit.d.ts.map +1 -0
  113. package/dist/lib/deck-media-assets.d.ts +27 -0
  114. package/dist/lib/deck-media-assets.d.ts.map +1 -0
  115. package/dist/lib/deck-media-assets.js +25 -0
  116. package/dist/lib/deck-media-refs.d.ts +35 -0
  117. package/dist/lib/deck-media-refs.d.ts.map +1 -0
  118. package/dist/lib/deck-media-refs.js +36 -0
  119. package/dist/lib/deck-tool.d.ts +25 -0
  120. package/dist/lib/deck-tool.d.ts.map +1 -0
  121. package/dist/lib/deck-tool.js +58 -0
  122. package/dist/lib/index-ops.js +2 -2
  123. package/dist/lib/index.js +17 -12
  124. package/dist/lib/nav-progress.d.ts +14 -0
  125. package/dist/lib/nav-progress.d.ts.map +1 -0
  126. package/dist/lib/nav.d.ts.map +1 -1
  127. package/dist/media/index.js +3 -3
  128. package/dist/schemas/deck-meta.d.ts +85 -0
  129. package/dist/schemas/deck-meta.d.ts.map +1 -0
  130. package/dist/schemas/deck-meta.js +64 -0
  131. package/dist/schemas/deck.d.ts +954 -0
  132. package/dist/schemas/deck.d.ts.map +1 -0
  133. package/dist/schemas/deck.js +65 -0
  134. package/dist/schemas/index.js +39 -37
  135. package/dist/schemas/site-config.d.ts +13 -1
  136. package/dist/schemas/site-config.d.ts.map +1 -1
  137. package/package.json +37 -1
  138. package/src/components/chat/ChatComposer.tsx +100 -0
  139. package/src/components/chat/ChatPanel.tsx +20 -69
  140. package/src/components/chat/markdown.ts +32 -0
  141. package/src/components/primitives/EditablePlainText.tsx +11 -1
  142. package/src/components/shell/AudienceChips.tsx +30 -0
  143. package/src/components/shell/EditorShell.tsx +12 -0
  144. package/src/components/shell/SiteSettingsChatbot.tsx +1 -18
  145. package/src/components/shell/SiteSettingsDecks.tsx +41 -0
  146. package/src/components/shell/SiteSettingsModal.tsx +11 -0
  147. package/src/deck/DeckComponentView.tsx +28 -0
  148. package/src/deck/DeckPlayer.tsx +166 -0
  149. package/src/deck/DeckSlideView.tsx +38 -0
  150. package/src/deck/DeckStage.tsx +39 -0
  151. package/src/deck/components/DeckImage.tsx +38 -0
  152. package/src/deck/components/DeckImageGrid.tsx +254 -0
  153. package/src/deck/components/DeckRichText.tsx +111 -0
  154. package/src/deck/components/DeckVideo.tsx +81 -0
  155. package/src/deck/editing.tsx +201 -0
  156. package/src/deck/flip.ts +70 -0
  157. package/src/deck/index.ts +30 -0
  158. package/src/deck/layouts/CenteredTextLayout.tsx +29 -0
  159. package/src/deck/layouts/ColumnSplitLayout.tsx +69 -0
  160. package/src/deck/layouts/FullBleedImageLayout.tsx +58 -0
  161. package/src/deck/media.tsx +46 -0
  162. package/src/deck/tokens.ts +57 -0
  163. package/src/deck/useStageScale.ts +44 -0
  164. package/src/deck-builder/DeckBuilderApp.tsx +572 -0
  165. package/src/deck-builder/DeckBuilderTopBar.tsx +62 -0
  166. package/src/deck-builder/DeckChatPanel.tsx +334 -0
  167. package/src/deck-builder/DeckEditor.tsx +258 -0
  168. package/src/deck-builder/DeckLibrary.tsx +195 -0
  169. package/src/deck-builder/DeckSlideSurface.tsx +55 -0
  170. package/src/deck-builder/deck-api.ts +177 -0
  171. package/src/deck-builder/deck-chat-client.ts +129 -0
  172. package/src/deck-builder/deck-chat-history.ts +62 -0
  173. package/src/deck-builder/index.ts +12 -0
  174. package/src/deck-builder/starter-deck.ts +86 -0
  175. package/src/deck-builder/types.ts +24 -0
  176. package/src/deck-builder/useSortableSlide.ts +102 -0
  177. package/src/lib/deck-access.ts +132 -0
  178. package/src/lib/deck-dexie.ts +190 -0
  179. package/src/lib/deck-edit.ts +196 -0
  180. package/src/lib/deck-media-assets.ts +57 -0
  181. package/src/lib/deck-media-refs.ts +67 -0
  182. package/src/lib/deck-tool.ts +95 -0
  183. package/src/lib/nav-progress.ts +108 -0
  184. package/src/lib/nav.ts +21 -1
  185. package/src/schemas/deck-meta.ts +88 -0
  186. package/src/schemas/deck.ts +478 -0
  187. package/src/schemas/index.ts +4 -0
  188. package/src/schemas/site-config.ts +24 -1
@@ -1,34 +1,24 @@
1
1
  import {
2
2
  brandGuideSectionDefs,
3
- duplicateChildAt,
4
- isSpacer,
5
- occupiedColumns,
6
3
  pluralize,
7
- removeChildAt,
8
- setChildColSpan,
9
4
  stripHtmlToPlainText,
10
- trimTrailingSpacers,
11
5
  truncate
12
- } from "./chunk-NXGIHSL5.js";
6
+ } from "./chunk-Z2LO4PSQ.js";
13
7
  import {
14
8
  DeleteButton,
15
9
  DragHandle,
16
- Kbd,
17
- Popover,
18
- PopoverItem,
19
10
  SettingsButton,
20
11
  SettingsForm,
21
- Tooltip,
22
12
  buildBlockDragData,
23
13
  buildBlockDropData,
24
14
  canDropBlock,
25
15
  isBlockDragData
26
- } from "./chunk-7WQJ57XG.js";
16
+ } from "./chunk-VT3PYGVW.js";
27
17
  import {
28
18
  EditableRichText,
29
19
  defineHeadingSection,
30
20
  useSanitizedHtml
31
- } from "./chunk-7MI3HCOF.js";
21
+ } from "./chunk-EPWBPIV6.js";
32
22
  import {
33
23
  EditablePlainText,
34
24
  ImageDropZone,
@@ -38,18 +28,28 @@ import {
38
28
  containerGridClass,
39
29
  masonryColumnsClass,
40
30
  spacerHiddenClass
41
- } from "./chunk-3GAG6ZXB.js";
31
+ } from "./chunk-3SZNUCXI.js";
42
32
  import {
43
33
  useMediaLibrary,
44
34
  useResolvedMedia
45
- } from "./chunk-ELQ4C677.js";
35
+ } from "./chunk-TALRVOGO.js";
36
+ import {
37
+ Kbd,
38
+ Popover,
39
+ PopoverItem,
40
+ Tooltip
41
+ } from "./chunk-IINIZBQB.js";
46
42
  import {
47
43
  embedUrl
48
44
  } from "./chunk-Y4JQGO6G.js";
49
45
  import {
50
- DEFAULT_LINK,
51
- LinkValueSchema
52
- } from "./chunk-3ZRQ4G5F.js";
46
+ duplicateChildAt,
47
+ isSpacer,
48
+ occupiedColumns,
49
+ removeChildAt,
50
+ setChildColSpan,
51
+ trimTrailingSpacers
52
+ } from "./chunk-CXZ5YJG4.js";
53
53
  import {
54
54
  cn
55
55
  } from "./chunk-7EOSDFS3.js";
@@ -63,6 +63,10 @@ import {
63
63
  import {
64
64
  SingleMediaReferenceSchema
65
65
  } from "./chunk-GGXZZ77Z.js";
66
+ import {
67
+ DEFAULT_LINK,
68
+ LinkValueSchema
69
+ } from "./chunk-3ZRQ4G5F.js";
66
70
 
67
71
  // src/components/sections/LinkHeading/index.tsx
68
72
  import { Heading1 } from "lucide-react";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FormLabel,
3
3
  Input
4
- } from "./chunk-ELQ4C677.js";
4
+ } from "./chunk-TALRVOGO.js";
5
5
  import {
6
6
  cn
7
7
  } from "./chunk-7EOSDFS3.js";
@@ -130,63 +130,7 @@ function LinkField({ label, value, onChange }) {
130
130
  ] });
131
131
  }
132
132
 
133
- // src/components/shared/Button.tsx
134
- import { forwardRef } from "react";
135
- import { jsx as jsx3 } from "react/jsx-runtime";
136
- var boxSize = {
137
- sm: "rounded px-3 py-1.5 text-xs font-medium",
138
- md: "rounded px-4 py-2 text-sm font-medium"
139
- };
140
- var ghostSize = {
141
- sm: "text-xs font-medium",
142
- md: "text-sm font-medium"
143
- };
144
- var variantClasses = {
145
- primary: "bg-base-contrast text-base-accent hover:bg-base-contrast/90",
146
- brand: "bg-primary text-primary-contrast hover:opacity-90",
147
- secondary: "border border-base-200 text-base-contrast hover:bg-base-accent",
148
- destructive: "border border-red-600 text-red-600 hover:bg-red-600 hover:text-white"
149
- };
150
- var ghostToneClasses = {
151
- neutral: "text-base-contrast-light hover:text-base-contrast",
152
- destructive: "text-red-600 hover:text-red-800"
153
- };
154
- var Button = forwardRef(function Button2({
155
- variant = "primary",
156
- size = "sm",
157
- tone = "neutral",
158
- fullWidth = false,
159
- isLoading = false,
160
- loadingLabel,
161
- disabled,
162
- className,
163
- children,
164
- ...rest
165
- }, ref) {
166
- const isGhost = variant === "ghost";
167
- const resolvedDisabled = disabled || isLoading;
168
- const label = isLoading && loadingLabel ? loadingLabel : children;
169
- return /* @__PURE__ */ jsx3(
170
- "button",
171
- {
172
- ref,
173
- disabled: resolvedDisabled,
174
- className: cn(
175
- "inline-flex items-center justify-center transition-colors",
176
- isGhost ? ghostSize[size] : boxSize[size],
177
- isGhost ? ghostToneClasses[tone] : variantClasses[variant],
178
- fullWidth && "w-full",
179
- resolvedDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
180
- className
181
- ),
182
- ...rest,
183
- children: label
184
- }
185
- );
186
- });
187
-
188
133
  export {
189
- Button,
190
134
  PagesContext,
191
135
  usePages,
192
136
  Select,
@@ -0,0 +1,85 @@
1
+ // src/lib/insert-menu.ts
2
+ var PRESET_PREFIX = "__preset:";
3
+ var INSERT_MENU_ORDER = [
4
+ "container",
5
+ "link_heading",
6
+ "sub_heading",
7
+ "sub_sub_heading",
8
+ "prose",
9
+ "media",
10
+ "video",
11
+ "button",
12
+ "colors",
13
+ "document",
14
+ "icon_list",
15
+ `${PRESET_PREFIX}do_dont_list`,
16
+ "dodont_media"
17
+ ];
18
+
19
+ // src/lib/container-ops.ts
20
+ function getContainerChildren(block) {
21
+ const content = block.content;
22
+ return Array.isArray(content?.children) ? content.children : [];
23
+ }
24
+ function withChildren(container, children) {
25
+ return { ...container, content: { ...container.content, children } };
26
+ }
27
+ function containerColumns(container) {
28
+ const n = container.content?.columns;
29
+ return typeof n === "number" && n >= 1 ? n : 1;
30
+ }
31
+ function removeChildAt(container, index) {
32
+ const children = getContainerChildren(container);
33
+ if (index < 0 || index >= children.length) return { container, removed: null };
34
+ const next = [...children];
35
+ const [removed] = next.splice(index, 1);
36
+ return { container: withChildren(container, next), removed };
37
+ }
38
+ function duplicateChildAt(container, index, newId) {
39
+ const children = getContainerChildren(container);
40
+ if (index < 0 || index >= children.length) return container;
41
+ const clone = { ...JSON.parse(JSON.stringify(children[index])), id: newId() };
42
+ const next = [...children];
43
+ next.splice(index + 1, 0, clone);
44
+ return withChildren(container, next);
45
+ }
46
+ function setChildColSpan(container, index, span) {
47
+ const children = getContainerChildren(container);
48
+ if (index < 0 || index >= children.length) return container;
49
+ const clamped = Math.max(1, Math.min(span, containerColumns(container)));
50
+ const next = children.map((child, i) => {
51
+ if (i !== index) return child;
52
+ if (clamped <= 1) {
53
+ const { layout: _drop, ...rest } = child;
54
+ return rest;
55
+ }
56
+ return { ...child, layout: { ...child.layout, colSpan: clamped } };
57
+ });
58
+ return withChildren(container, next);
59
+ }
60
+ function effectiveSpan(child, columns) {
61
+ return isSpacer(child) ? 1 : Math.min(child.layout?.colSpan ?? 1, columns);
62
+ }
63
+ function isSpacer(child) {
64
+ return child.type === "spacer";
65
+ }
66
+ function occupiedColumns(children, columns) {
67
+ return children.reduce((sum, c) => sum + effectiveSpan(c, columns), 0);
68
+ }
69
+ function trimTrailingSpacers(container) {
70
+ const children = getContainerChildren(container);
71
+ let end = children.length;
72
+ while (end > 0 && isSpacer(children[end - 1])) end--;
73
+ if (end === children.length) return container;
74
+ return withChildren(container, children.slice(0, end));
75
+ }
76
+
77
+ export {
78
+ getContainerChildren,
79
+ removeChildAt,
80
+ duplicateChildAt,
81
+ setChildColSpan,
82
+ isSpacer,
83
+ occupiedColumns,
84
+ trimTrailingSpacers
85
+ };
@@ -1,3 +1,6 @@
1
+ import {
2
+ getContainerChildren
3
+ } from "./chunk-CXZ5YJG4.js";
1
4
  import {
2
5
  getSection
3
6
  } from "./chunk-FTPETWXE.js";
@@ -12,6 +15,17 @@ function toSectionId(text) {
12
15
  }
13
16
  return `section-${Math.abs(hash).toString(36)}`;
14
17
  }
18
+ function flattenForNav(sections) {
19
+ const flat = [];
20
+ const walk = (loaded) => {
21
+ flat.push(loaded);
22
+ for (const child of getContainerChildren(loaded.section)) {
23
+ walk({ section: child, meta: loaded.meta });
24
+ }
25
+ };
26
+ sections.forEach(walk);
27
+ return flat;
28
+ }
15
29
  function generateNavLinks(sections, registry) {
16
30
  const nav = [];
17
31
  let currentParent = null;
@@ -20,7 +34,7 @@ function generateNavLinks(sections, registry) {
20
34
  const def = registry ? registry.getSection(type) : getSection(type);
21
35
  return def?.navRole;
22
36
  };
23
- for (const { section, meta } of sections) {
37
+ for (const { section, meta } of flattenForNav(sections)) {
24
38
  const content = section.content;
25
39
  if (!content.heading) continue;
26
40
  const role = lookupRole(section.type);
@@ -66,43 +80,7 @@ function generateNavLinks(sections, registry) {
66
80
  return nav;
67
81
  }
68
82
 
69
- // src/lib/sanitize.ts
70
- var purifierPromise = null;
71
- var purifier = null;
72
- if (typeof window !== "undefined") {
73
- purifierPromise = import("dompurify").then((mod) => {
74
- const DOMPurify = mod.default ?? mod;
75
- purifier = (html) => DOMPurify.sanitize(html);
76
- return mod;
77
- });
78
- }
79
- var sanitizeCache = /* @__PURE__ */ new Map();
80
- var SANITIZE_CACHE_LIMIT = 500;
81
- function sanitizeHtml(html) {
82
- if (!html) return "";
83
- if (!purifier) return html;
84
- const cached = sanitizeCache.get(html);
85
- if (cached !== void 0) return cached;
86
- const clean = purifier(html);
87
- if (sanitizeCache.size >= SANITIZE_CACHE_LIMIT) {
88
- const oldest = sanitizeCache.keys().next().value;
89
- if (oldest !== void 0) sanitizeCache.delete(oldest);
90
- }
91
- sanitizeCache.set(html, clean);
92
- return clean;
93
- }
94
- function isSanitizerReady() {
95
- return typeof window === "undefined" || purifier !== null;
96
- }
97
- async function ensureSanitizer() {
98
- if (typeof window === "undefined") return;
99
- if (!purifier && purifierPromise) await purifierPromise;
100
- }
101
-
102
83
  export {
103
84
  toSectionId,
104
- generateNavLinks,
105
- sanitizeHtml,
106
- isSanitizerReady,
107
- ensureSanitizer
85
+ generateNavLinks
108
86
  };
@@ -1,16 +1,20 @@
1
1
  import {
2
2
  EditablePlainText
3
- } from "./chunk-3GAG6ZXB.js";
3
+ } from "./chunk-3SZNUCXI.js";
4
4
  import {
5
- Button,
6
5
  usePages
7
- } from "./chunk-OUYB2GCW.js";
6
+ } from "./chunk-BR4MIPTM.js";
7
+ import {
8
+ Button
9
+ } from "./chunk-WUJ3XNFI.js";
10
+ import {
11
+ toSectionId
12
+ } from "./chunk-DNY72JZN.js";
8
13
  import {
9
14
  ensureSanitizer,
10
15
  isSanitizerReady,
11
- sanitizeHtml,
12
- toSectionId
13
- } from "./chunk-RA5IOFPY.js";
16
+ sanitizeHtml
17
+ } from "./chunk-QQ3S3P5P.js";
14
18
  import {
15
19
  cn
16
20
  } from "./chunk-7EOSDFS3.js";
@@ -0,0 +1,94 @@
1
+ import {
2
+ serializeDeck
3
+ } from "./chunk-VAYZJKVR.js";
4
+
5
+ // src/lib/deck-dexie.ts
6
+ import Dexie from "dexie";
7
+ var DeckDraftDatabase = class extends Dexie {
8
+ drafts;
9
+ constructor(name) {
10
+ super(name);
11
+ this.version(1).stores({ drafts: "deckId" });
12
+ }
13
+ };
14
+ function databaseName(siteId, scope) {
15
+ return `brand-portal-decks-${siteId}-${scope}`;
16
+ }
17
+ var db = null;
18
+ function initDeckDraftStore(siteId, scope) {
19
+ const name = databaseName(siteId, scope);
20
+ if (db?.name === name) return;
21
+ db?.close();
22
+ db = new DeckDraftDatabase(name);
23
+ }
24
+ function getDb() {
25
+ if (!db) throw new Error("Deck draft store not initialized. Call initDeckDraftStore first.");
26
+ return db;
27
+ }
28
+ async function listDeckDrafts() {
29
+ const rows = await getDb().drafts.toArray();
30
+ return rows.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
31
+ }
32
+ async function getDeckDraft(deckId) {
33
+ return await getDb().drafts.get(deckId) ?? null;
34
+ }
35
+ async function putDeckDraft(deck) {
36
+ const db2 = getDb();
37
+ return db2.transaction("rw", db2.drafts, async () => {
38
+ const existing = await db2.drafts.get(deck.id);
39
+ const row = {
40
+ deckId: deck.id,
41
+ deck,
42
+ baseVersion: existing?.baseVersion ?? null,
43
+ publishedText: existing?.publishedText ?? null,
44
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
45
+ };
46
+ await db2.drafts.put(row);
47
+ return row;
48
+ });
49
+ }
50
+ async function markDeckDraftPublished(deck, version, updatedAt) {
51
+ const row = {
52
+ deckId: deck.id,
53
+ deck,
54
+ baseVersion: version,
55
+ publishedText: serializeDeck(deck),
56
+ updatedAt: updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
57
+ };
58
+ await getDb().drafts.put(row);
59
+ return row;
60
+ }
61
+ async function recordDeckPublish(deckId, publishedDeck, version) {
62
+ const db2 = getDb();
63
+ return db2.transaction("rw", db2.drafts, async () => {
64
+ const existing = await db2.drafts.get(deckId);
65
+ if (!existing) return null;
66
+ const row = {
67
+ ...existing,
68
+ baseVersion: version,
69
+ publishedText: serializeDeck(publishedDeck),
70
+ // "Now", as the previous implementation stamped: a publish is activity the
71
+ // deck grid should sort on, even though it did not change the body.
72
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
73
+ };
74
+ await db2.drafts.put(row);
75
+ return row;
76
+ });
77
+ }
78
+ async function deleteDeckDraft(deckId) {
79
+ await getDb().drafts.delete(deckId);
80
+ }
81
+ function hasUnpublishedChanges(row) {
82
+ return row.publishedText === null || serializeDeck(row.deck) !== row.publishedText;
83
+ }
84
+
85
+ export {
86
+ initDeckDraftStore,
87
+ listDeckDrafts,
88
+ getDeckDraft,
89
+ putDeckDraft,
90
+ markDeckDraftPublished,
91
+ recordDeckPublish,
92
+ deleteDeckDraft,
93
+ hasUnpublishedChanges
94
+ };
@@ -74,7 +74,7 @@ var SectionMetaSchema = z2.object({
74
74
  status: StatusSchema,
75
75
  access: z2.array(z2.string())
76
76
  });
77
- var RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present", "print", "audiences"];
77
+ var RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present", "print", "audiences", "decks"];
78
78
  var PARSE_REJECTED_SLUGS = ["edit", "api", "login", "set-password", "404"];
79
79
  var PageStatusSchema = z2.enum(["live", "archived"]);
80
80
  var PageSchema = z2.object({
@@ -232,6 +232,15 @@ var ChatbotConfigSchema = z2.object({
232
232
  seen.add(t.id);
233
233
  }
234
234
  });
235
+ var DeckBuilderConfigSchema = z2.object({
236
+ // Audience names whose members may CREATE decks — a Deck Creator. Strict
237
+ // opt-in exactly like chatbot.audiences: [] = no viewer may build a deck.
238
+ // Editors are super-admins over decks and are never gated by this list.
239
+ // Gates: [...slug].astro's FAB, /decks, and POST /api/decks (canCreateDeck).
240
+ audiences: z2.array(z2.string()).default([]).describe(
241
+ "Audience names allowed to create decks in the Deck Builder. Strict opt-in \u2014 an empty list means no viewer can. Editors always can."
242
+ )
243
+ });
235
244
  var SiteConfigSchema = z2.object({
236
245
  siteName: z2.string().default("Brand Portal"),
237
246
  primaryColor: HexColorSchema.default("#009ca6"),
@@ -286,7 +295,10 @@ var SiteConfigSchema = z2.object({
286
295
  // Brand chatbot config (editor-owned; the platform kill switch lives in the
287
296
  // sites table, not here). Every field defaults so pre-existing
288
297
  // site-config.json files keep parsing.
289
- chatbot: ChatbotConfigSchema.default({ enabled: false, name: "Portal Assistant", audienceNames: {}, thinkingPhrases: [], systemPrompt: "", audiences: [], tasks: [], audiencePrompts: {} })
298
+ chatbot: ChatbotConfigSchema.default({ enabled: false, name: "Portal Assistant", audienceNames: {}, thinkingPhrases: [], systemPrompt: "", audiences: [], tasks: [], audiencePrompts: {} }),
299
+ // Deck Builder config (editor-owned). Defaults so pre-existing
300
+ // site-config.json files keep parsing — and the default is closed.
301
+ deckBuilder: DeckBuilderConfigSchema.default({ audiences: [] })
290
302
  });
291
303
 
292
304
  export {
@@ -305,5 +317,6 @@ export {
305
317
  normalizeSiteIndex,
306
318
  ChatbotTaskSchema,
307
319
  ChatbotConfigSchema,
320
+ DeckBuilderConfigSchema,
308
321
  SiteConfigSchema
309
322
  };
@@ -0,0 +1,41 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-7EOSDFS3.js";
4
+
5
+ // src/components/shared/IconButton.tsx
6
+ import { forwardRef } from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var sizeClasses = {
9
+ sm: "h-chrome-sm w-chrome-sm",
10
+ md: "h-chrome-md w-chrome-md",
11
+ lg: "h-chrome-lg w-chrome-lg"
12
+ };
13
+ var intentClasses = {
14
+ default: "text-base-contrast-light hover:text-base-contrast",
15
+ destructive: "text-destructive hover:text-destructive-hover",
16
+ primary: "text-primary/60 hover:text-primary"
17
+ };
18
+ var IconButton = forwardRef(
19
+ function IconButton2({ icon, label, size = "md", intent = "default", className, ...rest }, ref) {
20
+ return /* @__PURE__ */ jsx(
21
+ "button",
22
+ {
23
+ ref,
24
+ type: "button",
25
+ className: cn(
26
+ "cursor-pointer flex items-center justify-center rounded transition-colors",
27
+ sizeClasses[size],
28
+ intentClasses[intent],
29
+ className
30
+ ),
31
+ "aria-label": label,
32
+ ...rest,
33
+ children: icon
34
+ }
35
+ );
36
+ }
37
+ );
38
+
39
+ export {
40
+ IconButton
41
+ };