@drawnagency/primitives 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. package/README.md +28 -0
  2. package/dist/auth/cookies.d.ts +8 -0
  3. package/dist/auth/cookies.d.ts.map +1 -0
  4. package/dist/auth/cookies.js +44 -0
  5. package/dist/auth/errors.d.ts +8 -0
  6. package/dist/auth/errors.d.ts.map +1 -0
  7. package/dist/auth/errors.js +10 -0
  8. package/dist/auth/index.d.ts +5 -0
  9. package/dist/auth/index.d.ts.map +1 -0
  10. package/dist/auth/index.js +3 -0
  11. package/dist/auth/security.d.ts +13 -0
  12. package/dist/auth/security.d.ts.map +1 -0
  13. package/dist/auth/security.js +48 -0
  14. package/dist/auth/types.d.ts +64 -0
  15. package/dist/auth/types.d.ts.map +1 -0
  16. package/dist/auth/types.js +1 -0
  17. package/dist/components/brandguide/ColorSwatchSettings.d.ts +8 -0
  18. package/dist/components/brandguide/ColorSwatchSettings.d.ts.map +1 -0
  19. package/dist/components/brandguide/ColorSwatchSettings.js +10 -0
  20. package/dist/components/brandguide/Colors.d.ts +15 -0
  21. package/dist/components/brandguide/Colors.d.ts.map +1 -0
  22. package/dist/components/brandguide/Colors.js +79 -0
  23. package/dist/components/brandguide/DoDontList.d.ts +16 -0
  24. package/dist/components/brandguide/DoDontList.d.ts.map +1 -0
  25. package/dist/components/brandguide/DoDontList.js +22 -0
  26. package/dist/components/brandguide/DoDontMediaGrid.d.ts +16 -0
  27. package/dist/components/brandguide/DoDontMediaGrid.d.ts.map +1 -0
  28. package/dist/components/brandguide/DoDontMediaGrid.js +5 -0
  29. package/dist/components/editor/AudiencePicker.d.ts +9 -0
  30. package/dist/components/editor/AudiencePicker.d.ts.map +1 -0
  31. package/dist/components/editor/AudiencePicker.js +24 -0
  32. package/dist/components/editor/DeleteButton.d.ts +6 -0
  33. package/dist/components/editor/DeleteButton.d.ts.map +1 -0
  34. package/dist/components/editor/DeleteButton.js +6 -0
  35. package/dist/components/editor/DragHandle.d.ts +2 -0
  36. package/dist/components/editor/DragHandle.d.ts.map +1 -0
  37. package/dist/components/editor/DragHandle.js +8 -0
  38. package/dist/components/editor/InsertButton.d.ts +7 -0
  39. package/dist/components/editor/InsertButton.d.ts.map +1 -0
  40. package/dist/components/editor/InsertButton.js +7 -0
  41. package/dist/components/editor/SectionWrapper.d.ts +3 -0
  42. package/dist/components/editor/SectionWrapper.d.ts.map +1 -0
  43. package/dist/components/editor/SectionWrapper.js +135 -0
  44. package/dist/components/editor/SettingsButton.d.ts +6 -0
  45. package/dist/components/editor/SettingsButton.d.ts.map +1 -0
  46. package/dist/components/editor/SettingsButton.js +6 -0
  47. package/dist/components/editor/SettingsForm.d.ts +13 -0
  48. package/dist/components/editor/SettingsForm.d.ts.map +1 -0
  49. package/dist/components/editor/SettingsForm.js +64 -0
  50. package/dist/components/editor/StatusBadge.d.ts +7 -0
  51. package/dist/components/editor/StatusBadge.d.ts.map +1 -0
  52. package/dist/components/editor/StatusBadge.js +10 -0
  53. package/dist/components/editor/StatusPicker.d.ts +9 -0
  54. package/dist/components/editor/StatusPicker.d.ts.map +1 -0
  55. package/dist/components/editor/StatusPicker.js +30 -0
  56. package/dist/components/editor/index.d.ts +8 -0
  57. package/dist/components/editor/index.d.ts.map +1 -0
  58. package/dist/components/editor/index.js +7 -0
  59. package/dist/components/primitives/CustomParagraph.d.ts +2 -0
  60. package/dist/components/primitives/CustomParagraph.d.ts.map +1 -0
  61. package/dist/components/primitives/CustomParagraph.js +24 -0
  62. package/dist/components/primitives/EditableGrid.d.ts +19 -0
  63. package/dist/components/primitives/EditableGrid.d.ts.map +1 -0
  64. package/dist/components/primitives/EditableGrid.js +90 -0
  65. package/dist/components/primitives/EditableList.d.ts +15 -0
  66. package/dist/components/primitives/EditableList.d.ts.map +1 -0
  67. package/dist/components/primitives/EditableList.js +54 -0
  68. package/dist/components/primitives/EditablePlainText.d.ts +12 -0
  69. package/dist/components/primitives/EditablePlainText.d.ts.map +1 -0
  70. package/dist/components/primitives/EditablePlainText.js +52 -0
  71. package/dist/components/primitives/EditableRichText.d.ts +11 -0
  72. package/dist/components/primitives/EditableRichText.d.ts.map +1 -0
  73. package/dist/components/primitives/EditableRichText.js +86 -0
  74. package/dist/components/primitives/HeadingSection.d.ts +10 -0
  75. package/dist/components/primitives/HeadingSection.d.ts.map +1 -0
  76. package/dist/components/primitives/HeadingSection.js +7 -0
  77. package/dist/components/primitives/IconPicker.d.ts +9 -0
  78. package/dist/components/primitives/IconPicker.d.ts.map +1 -0
  79. package/dist/components/primitives/IconPicker.js +21 -0
  80. package/dist/components/primitives/LinkPopover.d.ts +8 -0
  81. package/dist/components/primitives/LinkPopover.d.ts.map +1 -0
  82. package/dist/components/primitives/LinkPopover.js +48 -0
  83. package/dist/components/primitives/MediaSettingsForms.d.ts +19 -0
  84. package/dist/components/primitives/MediaSettingsForms.d.ts.map +1 -0
  85. package/dist/components/primitives/MediaSettingsForms.js +42 -0
  86. package/dist/components/primitives/ResolvedMedia.d.ts +8 -0
  87. package/dist/components/primitives/ResolvedMedia.d.ts.map +1 -0
  88. package/dist/components/primitives/ResolvedMedia.js +9 -0
  89. package/dist/components/primitives/RichTextToolbar.d.ts +9 -0
  90. package/dist/components/primitives/RichTextToolbar.d.ts.map +1 -0
  91. package/dist/components/primitives/RichTextToolbar.js +26 -0
  92. package/dist/components/primitives/tiptap-presets.d.ts +4 -0
  93. package/dist/components/primitives/tiptap-presets.d.ts.map +1 -0
  94. package/dist/components/primitives/tiptap-presets.js +44 -0
  95. package/dist/components/primitives/useEditableCollection.d.ts +19 -0
  96. package/dist/components/primitives/useEditableCollection.d.ts.map +1 -0
  97. package/dist/components/primitives/useEditableCollection.js +61 -0
  98. package/dist/components/primitives/useEditablePlainText.d.ts +14 -0
  99. package/dist/components/primitives/useEditablePlainText.d.ts.map +1 -0
  100. package/dist/components/primitives/useEditablePlainText.js +27 -0
  101. package/dist/components/primitives/useEditableRichText.d.ts +16 -0
  102. package/dist/components/primitives/useEditableRichText.d.ts.map +1 -0
  103. package/dist/components/primitives/useEditableRichText.js +52 -0
  104. package/dist/components/sections/Button/CTAButton.d.ts +11 -0
  105. package/dist/components/sections/Button/CTAButton.d.ts.map +1 -0
  106. package/dist/components/sections/Button/CTAButton.js +18 -0
  107. package/dist/components/sections/Button/index.d.ts +11 -0
  108. package/dist/components/sections/Button/index.d.ts.map +1 -0
  109. package/dist/components/sections/Button/index.js +28 -0
  110. package/dist/components/sections/Colors/index.d.ts +22 -0
  111. package/dist/components/sections/Colors/index.d.ts.map +1 -0
  112. package/dist/components/sections/Colors/index.js +34 -0
  113. package/dist/components/sections/DoDontList/index.d.ts +21 -0
  114. package/dist/components/sections/DoDontList/index.d.ts.map +1 -0
  115. package/dist/components/sections/DoDontList/index.js +33 -0
  116. package/dist/components/sections/DoDontMediaGrid/index.d.ts +55 -0
  117. package/dist/components/sections/DoDontMediaGrid/index.d.ts.map +1 -0
  118. package/dist/components/sections/DoDontMediaGrid/index.js +41 -0
  119. package/dist/components/sections/IconList/IconList.d.ts +20 -0
  120. package/dist/components/sections/IconList/IconList.d.ts.map +1 -0
  121. package/dist/components/sections/IconList/IconList.js +131 -0
  122. package/dist/components/sections/IconList/IconListSettings.d.ts +11 -0
  123. package/dist/components/sections/IconList/IconListSettings.d.ts.map +1 -0
  124. package/dist/components/sections/IconList/IconListSettings.js +22 -0
  125. package/dist/components/sections/IconList/index.d.ts +17 -0
  126. package/dist/components/sections/IconList/index.d.ts.map +1 -0
  127. package/dist/components/sections/IconList/index.js +27 -0
  128. package/dist/components/sections/LinkHeading/index.d.ts +8 -0
  129. package/dist/components/sections/LinkHeading/index.d.ts.map +1 -0
  130. package/dist/components/sections/LinkHeading/index.js +15 -0
  131. package/dist/components/sections/MediaGrid/MediaGrid.d.ts +17 -0
  132. package/dist/components/sections/MediaGrid/MediaGrid.d.ts.map +1 -0
  133. package/dist/components/sections/MediaGrid/MediaGrid.js +62 -0
  134. package/dist/components/sections/MediaGrid/index.d.ts +55 -0
  135. package/dist/components/sections/MediaGrid/index.d.ts.map +1 -0
  136. package/dist/components/sections/MediaGrid/index.js +35 -0
  137. package/dist/components/sections/Prose/Prose.d.ts +8 -0
  138. package/dist/components/sections/Prose/Prose.d.ts.map +1 -0
  139. package/dist/components/sections/Prose/Prose.js +11 -0
  140. package/dist/components/sections/Prose/index.d.ts +8 -0
  141. package/dist/components/sections/Prose/index.d.ts.map +1 -0
  142. package/dist/components/sections/Prose/index.js +15 -0
  143. package/dist/components/sections/SectionLayout.d.ts +11 -0
  144. package/dist/components/sections/SectionLayout.d.ts.map +1 -0
  145. package/dist/components/sections/SectionLayout.js +15 -0
  146. package/dist/components/sections/SplitContent/SplitContent.d.ts +11 -0
  147. package/dist/components/sections/SplitContent/SplitContent.d.ts.map +1 -0
  148. package/dist/components/sections/SplitContent/SplitContent.js +31 -0
  149. package/dist/components/sections/SplitContent/SplitContentSettings.d.ts +9 -0
  150. package/dist/components/sections/SplitContent/SplitContentSettings.d.ts.map +1 -0
  151. package/dist/components/sections/SplitContent/SplitContentSettings.js +17 -0
  152. package/dist/components/sections/SplitContent/index.d.ts +13 -0
  153. package/dist/components/sections/SplitContent/index.d.ts.map +1 -0
  154. package/dist/components/sections/SplitContent/index.js +27 -0
  155. package/dist/components/sections/SubHeading/index.d.ts +9 -0
  156. package/dist/components/sections/SubHeading/index.d.ts.map +1 -0
  157. package/dist/components/sections/SubHeading/index.js +18 -0
  158. package/dist/components/sections/SubSubHeading/index.d.ts +9 -0
  159. package/dist/components/sections/SubSubHeading/index.d.ts.map +1 -0
  160. package/dist/components/sections/SubSubHeading/index.js +18 -0
  161. package/dist/components/sections/ViewRenderer.d.ts +8 -0
  162. package/dist/components/sections/ViewRenderer.d.ts.map +1 -0
  163. package/dist/components/sections/ViewRenderer.js +13 -0
  164. package/dist/components/sections/register-schemas.d.ts +2 -0
  165. package/dist/components/sections/register-schemas.d.ts.map +1 -0
  166. package/dist/components/sections/register-schemas.js +15 -0
  167. package/dist/components/sections/register.d.ts +2 -0
  168. package/dist/components/sections/register.d.ts.map +1 -0
  169. package/dist/components/sections/register.js +15 -0
  170. package/dist/components/shared/Button.d.ts +15 -0
  171. package/dist/components/shared/Button.d.ts.map +1 -0
  172. package/dist/components/shared/Button.js +27 -0
  173. package/dist/components/shared/Checkbox.d.ts +14 -0
  174. package/dist/components/shared/Checkbox.d.ts.map +1 -0
  175. package/dist/components/shared/Checkbox.js +10 -0
  176. package/dist/components/shared/ColorPicker.d.ts +9 -0
  177. package/dist/components/shared/ColorPicker.d.ts.map +1 -0
  178. package/dist/components/shared/ColorPicker.js +5 -0
  179. package/dist/components/shared/ErrorBoundary.d.ts +24 -0
  180. package/dist/components/shared/ErrorBoundary.d.ts.map +1 -0
  181. package/dist/components/shared/ErrorBoundary.js +30 -0
  182. package/dist/components/shared/FontPicker.d.ts +8 -0
  183. package/dist/components/shared/FontPicker.d.ts.map +1 -0
  184. package/dist/components/shared/FontPicker.js +190 -0
  185. package/dist/components/shared/FormLabel.d.ts +8 -0
  186. package/dist/components/shared/FormLabel.d.ts.map +1 -0
  187. package/dist/components/shared/FormLabel.js +5 -0
  188. package/dist/components/shared/IconButton.d.ts +12 -0
  189. package/dist/components/shared/IconButton.d.ts.map +1 -0
  190. package/dist/components/shared/IconButton.js +16 -0
  191. package/dist/components/shared/Input.d.ts +8 -0
  192. package/dist/components/shared/Input.d.ts.map +1 -0
  193. package/dist/components/shared/Input.js +8 -0
  194. package/dist/components/shared/Navigation.d.ts +9 -0
  195. package/dist/components/shared/Navigation.d.ts.map +1 -0
  196. package/dist/components/shared/Navigation.js +71 -0
  197. package/dist/components/shared/PasswordInput.d.ts +13 -0
  198. package/dist/components/shared/PasswordInput.d.ts.map +1 -0
  199. package/dist/components/shared/PasswordInput.js +11 -0
  200. package/dist/components/shared/Popover.d.ts +12 -0
  201. package/dist/components/shared/Popover.d.ts.map +1 -0
  202. package/dist/components/shared/Popover.js +33 -0
  203. package/dist/components/shared/PopoverItem.d.ts +7 -0
  204. package/dist/components/shared/PopoverItem.d.ts.map +1 -0
  205. package/dist/components/shared/PopoverItem.js +6 -0
  206. package/dist/components/shared/Select.d.ts +16 -0
  207. package/dist/components/shared/Select.d.ts.map +1 -0
  208. package/dist/components/shared/Select.js +9 -0
  209. package/dist/components/shared/Textarea.d.ts +8 -0
  210. package/dist/components/shared/Textarea.d.ts.map +1 -0
  211. package/dist/components/shared/Textarea.js +8 -0
  212. package/dist/components/shared/Toggle.d.ts +10 -0
  213. package/dist/components/shared/Toggle.d.ts.map +1 -0
  214. package/dist/components/shared/Toggle.js +5 -0
  215. package/dist/components/shared/Tooltip.d.ts +12 -0
  216. package/dist/components/shared/Tooltip.d.ts.map +1 -0
  217. package/dist/components/shared/Tooltip.js +8 -0
  218. package/dist/components/shared/icons.d.ts +17 -0
  219. package/dist/components/shared/icons.d.ts.map +1 -0
  220. package/dist/components/shared/icons.js +23 -0
  221. package/dist/components/shell/AudienceAddForm.d.ts +11 -0
  222. package/dist/components/shell/AudienceAddForm.d.ts.map +1 -0
  223. package/dist/components/shell/AudienceAddForm.js +43 -0
  224. package/dist/components/shell/AudienceRow.d.ts +15 -0
  225. package/dist/components/shell/AudienceRow.d.ts.map +1 -0
  226. package/dist/components/shell/AudienceRow.js +74 -0
  227. package/dist/components/shell/EditorContext.d.ts +14 -0
  228. package/dist/components/shell/EditorContext.d.ts.map +1 -0
  229. package/dist/components/shell/EditorContext.js +24 -0
  230. package/dist/components/shell/EditorLoginForm.d.ts +13 -0
  231. package/dist/components/shell/EditorLoginForm.d.ts.map +1 -0
  232. package/dist/components/shell/EditorLoginForm.js +46 -0
  233. package/dist/components/shell/EditorModal.d.ts +13 -0
  234. package/dist/components/shell/EditorModal.d.ts.map +1 -0
  235. package/dist/components/shell/EditorModal.js +43 -0
  236. package/dist/components/shell/EditorModalContext.d.ts +16 -0
  237. package/dist/components/shell/EditorModalContext.d.ts.map +1 -0
  238. package/dist/components/shell/EditorModalContext.js +20 -0
  239. package/dist/components/shell/EditorShell.d.ts +22 -0
  240. package/dist/components/shell/EditorShell.d.ts.map +1 -0
  241. package/dist/components/shell/EditorShell.js +483 -0
  242. package/dist/components/shell/MediaLibraryContext.d.ts +14 -0
  243. package/dist/components/shell/MediaLibraryContext.d.ts.map +1 -0
  244. package/dist/components/shell/MediaLibraryContext.js +5 -0
  245. package/dist/components/shell/MediaLibraryModal.d.ts +14 -0
  246. package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -0
  247. package/dist/components/shell/MediaLibraryModal.js +145 -0
  248. package/dist/components/shell/ProcessingIndicator.d.ts +7 -0
  249. package/dist/components/shell/ProcessingIndicator.d.ts.map +1 -0
  250. package/dist/components/shell/ProcessingIndicator.js +15 -0
  251. package/dist/components/shell/SectionSkeleton.d.ts +9 -0
  252. package/dist/components/shell/SectionSkeleton.d.ts.map +1 -0
  253. package/dist/components/shell/SectionSkeleton.js +22 -0
  254. package/dist/components/shell/SectionTypePicker.d.ts +14 -0
  255. package/dist/components/shell/SectionTypePicker.d.ts.map +1 -0
  256. package/dist/components/shell/SectionTypePicker.js +15 -0
  257. package/dist/components/shell/SiteSettingsDisplay.d.ts +8 -0
  258. package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -0
  259. package/dist/components/shell/SiteSettingsDisplay.js +28 -0
  260. package/dist/components/shell/SiteSettingsModal.d.ts +24 -0
  261. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -0
  262. package/dist/components/shell/SiteSettingsModal.js +40 -0
  263. package/dist/components/shell/SiteSettingsUsers.d.ts +9 -0
  264. package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -0
  265. package/dist/components/shell/SiteSettingsUsers.js +87 -0
  266. package/dist/components/shell/SiteSettingsViewerAccess.d.ts +9 -0
  267. package/dist/components/shell/SiteSettingsViewerAccess.d.ts.map +1 -0
  268. package/dist/components/shell/SiteSettingsViewerAccess.js +94 -0
  269. package/dist/components/shell/ViewerLoginForm.d.ts +10 -0
  270. package/dist/components/shell/ViewerLoginForm.d.ts.map +1 -0
  271. package/dist/components/shell/ViewerLoginForm.js +40 -0
  272. package/dist/data/google-fonts.json +7718 -0
  273. package/dist/hooks/index.d.ts +7 -0
  274. package/dist/hooks/index.d.ts.map +1 -0
  275. package/dist/hooks/index.js +6 -0
  276. package/dist/hooks/useActiveHeadings.d.ts +7 -0
  277. package/dist/hooks/useActiveHeadings.d.ts.map +1 -0
  278. package/dist/hooks/useActiveHeadings.js +99 -0
  279. package/dist/hooks/useEditorPersistence.d.ts +13 -0
  280. package/dist/hooks/useEditorPersistence.d.ts.map +1 -0
  281. package/dist/hooks/useEditorPersistence.js +73 -0
  282. package/dist/hooks/useEditorPublish.d.ts +24 -0
  283. package/dist/hooks/useEditorPublish.d.ts.map +1 -0
  284. package/dist/hooks/useEditorPublish.js +145 -0
  285. package/dist/hooks/useFocusTrap.d.ts +3 -0
  286. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  287. package/dist/hooks/useFocusTrap.js +51 -0
  288. package/dist/hooks/useMediaPipeline.d.ts +65 -0
  289. package/dist/hooks/useMediaPipeline.d.ts.map +1 -0
  290. package/dist/hooks/useMediaPipeline.js +253 -0
  291. package/dist/hooks/useResolvedMedia.d.ts +9 -0
  292. package/dist/hooks/useResolvedMedia.d.ts.map +1 -0
  293. package/dist/hooks/useResolvedMedia.js +39 -0
  294. package/dist/index.d.ts +5 -0
  295. package/dist/index.d.ts.map +1 -0
  296. package/dist/index.js +4 -0
  297. package/dist/lib/cn.d.ts +3 -0
  298. package/dist/lib/cn.d.ts.map +1 -0
  299. package/dist/lib/cn.js +5 -0
  300. package/dist/lib/contrast.d.ts +2 -0
  301. package/dist/lib/contrast.d.ts.map +1 -0
  302. package/dist/lib/contrast.js +11 -0
  303. package/dist/lib/dexie.d.ts +41 -0
  304. package/dist/lib/dexie.d.ts.map +1 -0
  305. package/dist/lib/dexie.js +236 -0
  306. package/dist/lib/events.d.ts +12 -0
  307. package/dist/lib/events.d.ts.map +1 -0
  308. package/dist/lib/events.js +15 -0
  309. package/dist/lib/google-fonts.d.ts +2 -0
  310. package/dist/lib/google-fonts.d.ts.map +1 -0
  311. package/dist/lib/google-fonts.js +11 -0
  312. package/dist/lib/grid.d.ts +2 -0
  313. package/dist/lib/grid.d.ts.map +1 -0
  314. package/dist/lib/grid.js +7 -0
  315. package/dist/lib/icons.d.ts +9 -0
  316. package/dist/lib/icons.d.ts.map +1 -0
  317. package/dist/lib/icons.js +27 -0
  318. package/dist/lib/index.d.ts +13 -0
  319. package/dist/lib/index.d.ts.map +1 -0
  320. package/dist/lib/index.js +12 -0
  321. package/dist/lib/loader.d.ts +28 -0
  322. package/dist/lib/loader.d.ts.map +1 -0
  323. package/dist/lib/loader.js +57 -0
  324. package/dist/lib/nav.d.ts +15 -0
  325. package/dist/lib/nav.d.ts.map +1 -0
  326. package/dist/lib/nav.js +58 -0
  327. package/dist/lib/registry.d.ts +110 -0
  328. package/dist/lib/registry.d.ts.map +1 -0
  329. package/dist/lib/registry.js +64 -0
  330. package/dist/lib/safeRedirect.d.ts +7 -0
  331. package/dist/lib/safeRedirect.d.ts.map +1 -0
  332. package/dist/lib/safeRedirect.js +11 -0
  333. package/dist/lib/sanitize.d.ts +2 -0
  334. package/dist/lib/sanitize.d.ts.map +1 -0
  335. package/dist/lib/sanitize.js +6 -0
  336. package/dist/lib/timestamp.d.ts +2 -0
  337. package/dist/lib/timestamp.d.ts.map +1 -0
  338. package/dist/lib/timestamp.js +28 -0
  339. package/dist/media/github.d.ts +3 -0
  340. package/dist/media/github.d.ts.map +1 -0
  341. package/dist/media/github.js +60 -0
  342. package/dist/media/index.d.ts +8 -0
  343. package/dist/media/index.d.ts.map +1 -0
  344. package/dist/media/index.js +9 -0
  345. package/dist/media/queue.d.ts +74 -0
  346. package/dist/media/queue.d.ts.map +1 -0
  347. package/dist/media/queue.js +116 -0
  348. package/dist/media/resolve.d.ts +14 -0
  349. package/dist/media/resolve.d.ts.map +1 -0
  350. package/dist/media/resolve.js +50 -0
  351. package/dist/media/types.d.ts +42 -0
  352. package/dist/media/types.d.ts.map +1 -0
  353. package/dist/media/types.js +1 -0
  354. package/dist/media/utils.d.ts +7 -0
  355. package/dist/media/utils.d.ts.map +1 -0
  356. package/dist/media/utils.js +41 -0
  357. package/dist/media/videoPoster.d.ts +6 -0
  358. package/dist/media/videoPoster.d.ts.map +1 -0
  359. package/dist/media/videoPoster.js +44 -0
  360. package/dist/media/worker.d.ts +36 -0
  361. package/dist/media/worker.d.ts.map +1 -0
  362. package/dist/media/worker.js +73 -0
  363. package/dist/schemas/audience.d.ts +12 -0
  364. package/dist/schemas/audience.d.ts.map +1 -0
  365. package/dist/schemas/audience.js +19 -0
  366. package/dist/schemas/auth.d.ts +36 -0
  367. package/dist/schemas/auth.d.ts.map +1 -0
  368. package/dist/schemas/auth.js +22 -0
  369. package/dist/schemas/index.d.ts +8 -0
  370. package/dist/schemas/index.d.ts.map +1 -0
  371. package/dist/schemas/index.js +7 -0
  372. package/dist/schemas/media-grid-options.d.ts +8 -0
  373. package/dist/schemas/media-grid-options.d.ts.map +1 -0
  374. package/dist/schemas/media-grid-options.js +7 -0
  375. package/dist/schemas/media.d.ts +63 -0
  376. package/dist/schemas/media.d.ts.map +1 -0
  377. package/dist/schemas/media.js +28 -0
  378. package/dist/schemas/sections.d.ts +12 -0
  379. package/dist/schemas/sections.d.ts.map +1 -0
  380. package/dist/schemas/sections.js +12 -0
  381. package/dist/schemas/shared.d.ts +98 -0
  382. package/dist/schemas/shared.d.ts.map +1 -0
  383. package/dist/schemas/shared.js +71 -0
  384. package/dist/schemas/site-config.d.ts +48 -0
  385. package/dist/schemas/site-config.d.ts.map +1 -0
  386. package/dist/schemas/site-config.js +26 -0
  387. package/package.json +57 -0
  388. package/src/auth/cookies.ts +51 -0
  389. package/src/auth/errors.ts +10 -0
  390. package/src/auth/index.ts +15 -0
  391. package/src/auth/security.ts +44 -0
  392. package/src/auth/types.ts +61 -0
  393. package/src/components/brandguide/ColorSwatchSettings.tsx +34 -0
  394. package/src/components/brandguide/Colors.tsx +277 -0
  395. package/src/components/brandguide/DoDontList.tsx +67 -0
  396. package/src/components/brandguide/DoDontMediaGrid.tsx +19 -0
  397. package/src/components/editor/AudiencePicker.tsx +103 -0
  398. package/src/components/editor/DeleteButton.tsx +18 -0
  399. package/src/components/editor/DragHandle.tsx +18 -0
  400. package/src/components/editor/InsertButton.tsx +22 -0
  401. package/src/components/editor/SectionWrapper.tsx +279 -0
  402. package/src/components/editor/SettingsButton.tsx +17 -0
  403. package/src/components/editor/SettingsForm.tsx +159 -0
  404. package/src/components/editor/StatusBadge.tsx +30 -0
  405. package/src/components/editor/StatusPicker.tsx +86 -0
  406. package/src/components/editor/index.ts +7 -0
  407. package/src/components/primitives/CustomParagraph.ts +25 -0
  408. package/src/components/primitives/EditableGrid.tsx +260 -0
  409. package/src/components/primitives/EditableList.tsx +160 -0
  410. package/src/components/primitives/EditablePlainText.tsx +99 -0
  411. package/src/components/primitives/EditableRichText.tsx +132 -0
  412. package/src/components/primitives/HeadingSection.tsx +25 -0
  413. package/src/components/primitives/IconPicker.tsx +60 -0
  414. package/src/components/primitives/LinkPopover.tsx +109 -0
  415. package/src/components/primitives/MediaSettingsForms.tsx +109 -0
  416. package/src/components/primitives/ResolvedMedia.tsx +36 -0
  417. package/src/components/primitives/RichTextToolbar.tsx +149 -0
  418. package/src/components/primitives/tiptap-presets.ts +50 -0
  419. package/src/components/primitives/useEditableCollection.ts +104 -0
  420. package/src/components/primitives/useEditablePlainText.ts +49 -0
  421. package/src/components/primitives/useEditableRichText.ts +74 -0
  422. package/src/components/sections/Button/CTAButton.tsx +50 -0
  423. package/src/components/sections/Button/index.tsx +37 -0
  424. package/src/components/sections/Colors/index.tsx +45 -0
  425. package/src/components/sections/DoDontList/index.tsx +43 -0
  426. package/src/components/sections/DoDontMediaGrid/index.tsx +53 -0
  427. package/src/components/sections/IconList/IconList.tsx +462 -0
  428. package/src/components/sections/IconList/IconListSettings.tsx +81 -0
  429. package/src/components/sections/IconList/index.tsx +36 -0
  430. package/src/components/sections/LinkHeading/index.tsx +24 -0
  431. package/src/components/sections/MediaGrid/MediaGrid.tsx +219 -0
  432. package/src/components/sections/MediaGrid/index.tsx +47 -0
  433. package/src/components/sections/Prose/Prose.tsx +34 -0
  434. package/src/components/sections/Prose/index.tsx +18 -0
  435. package/src/components/sections/SectionLayout.tsx +31 -0
  436. package/src/components/sections/SplitContent/SplitContent.tsx +77 -0
  437. package/src/components/sections/SplitContent/SplitContentSettings.tsx +42 -0
  438. package/src/components/sections/SplitContent/index.tsx +36 -0
  439. package/src/components/sections/SubHeading/index.tsx +27 -0
  440. package/src/components/sections/SubSubHeading/index.tsx +27 -0
  441. package/src/components/sections/ViewRenderer.tsx +29 -0
  442. package/src/components/sections/register-schemas.ts +16 -0
  443. package/src/components/sections/register.ts +16 -0
  444. package/src/components/shared/Button.tsx +77 -0
  445. package/src/components/shared/Checkbox.tsx +73 -0
  446. package/src/components/shared/ColorPicker.tsx +28 -0
  447. package/src/components/shared/ErrorBoundary.tsx +92 -0
  448. package/src/components/shared/FontPicker.tsx +300 -0
  449. package/src/components/shared/FormLabel.tsx +18 -0
  450. package/src/components/shared/IconButton.tsx +45 -0
  451. package/src/components/shared/Input.tsx +34 -0
  452. package/src/components/shared/Navigation.tsx +196 -0
  453. package/src/components/shared/PasswordInput.tsx +64 -0
  454. package/src/components/shared/Popover.tsx +61 -0
  455. package/src/components/shared/PopoverItem.tsx +24 -0
  456. package/src/components/shared/Select.tsx +60 -0
  457. package/src/components/shared/Textarea.tsx +34 -0
  458. package/src/components/shared/Toggle.tsx +35 -0
  459. package/src/components/shared/Tooltip.tsx +28 -0
  460. package/src/components/shared/icons.tsx +28 -0
  461. package/src/components/shell/AudienceAddForm.tsx +94 -0
  462. package/src/components/shell/AudienceRow.tsx +171 -0
  463. package/src/components/shell/EditorContext.tsx +44 -0
  464. package/src/components/shell/EditorLoginForm.tsx +130 -0
  465. package/src/components/shell/EditorModal.tsx +93 -0
  466. package/src/components/shell/EditorModalContext.tsx +40 -0
  467. package/src/components/shell/EditorShell.tsx +910 -0
  468. package/src/components/shell/MediaLibraryContext.tsx +19 -0
  469. package/src/components/shell/MediaLibraryModal.tsx +371 -0
  470. package/src/components/shell/ProcessingIndicator.tsx +84 -0
  471. package/src/components/shell/SectionSkeleton.tsx +54 -0
  472. package/src/components/shell/SectionTypePicker.tsx +47 -0
  473. package/src/components/shell/SiteSettingsDisplay.tsx +78 -0
  474. package/src/components/shell/SiteSettingsModal.tsx +129 -0
  475. package/src/components/shell/SiteSettingsUsers.tsx +190 -0
  476. package/src/components/shell/SiteSettingsViewerAccess.tsx +171 -0
  477. package/src/components/shell/ViewerLoginForm.tsx +95 -0
  478. package/src/data/google-fonts.json +7718 -0
  479. package/src/env.d.ts +3 -0
  480. package/src/hooks/index.ts +6 -0
  481. package/src/hooks/useActiveHeadings.ts +120 -0
  482. package/src/hooks/useEditorPersistence.ts +103 -0
  483. package/src/hooks/useEditorPublish.ts +187 -0
  484. package/src/hooks/useFocusTrap.ts +57 -0
  485. package/src/hooks/useMediaPipeline.ts +309 -0
  486. package/src/hooks/useResolvedMedia.ts +54 -0
  487. package/src/index.ts +4 -0
  488. package/src/lib/cn.ts +6 -0
  489. package/src/lib/contrast.ts +11 -0
  490. package/src/lib/dexie.ts +347 -0
  491. package/src/lib/events.ts +23 -0
  492. package/src/lib/google-fonts.ts +10 -0
  493. package/src/lib/grid.ts +7 -0
  494. package/src/lib/icons.ts +58 -0
  495. package/src/lib/index.ts +35 -0
  496. package/src/lib/loader.ts +81 -0
  497. package/src/lib/nav.ts +64 -0
  498. package/src/lib/registry.ts +202 -0
  499. package/src/lib/safeRedirect.ts +11 -0
  500. package/src/lib/sanitize.ts +6 -0
  501. package/src/lib/timestamp.ts +31 -0
  502. package/src/media/github.ts +72 -0
  503. package/src/media/index.ts +12 -0
  504. package/src/media/queue.ts +166 -0
  505. package/src/media/resolve.ts +63 -0
  506. package/src/media/types.ts +58 -0
  507. package/src/media/utils.ts +48 -0
  508. package/src/media/videoPoster.ts +53 -0
  509. package/src/media/worker.ts +122 -0
  510. package/src/schemas/audience.ts +28 -0
  511. package/src/schemas/auth.ts +31 -0
  512. package/src/schemas/index.ts +7 -0
  513. package/src/schemas/media-grid-options.ts +8 -0
  514. package/src/schemas/media.ts +40 -0
  515. package/src/schemas/sections.ts +24 -0
  516. package/src/schemas/shared.ts +96 -0
  517. package/src/schemas/site-config.ts +38 -0
@@ -0,0 +1,145 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useRef, useCallback } from "react";
3
+ import { Search, Upload, Trash2 } from "lucide-react";
4
+ import { cn } from "../../lib/cn";
5
+ import { Button } from "../shared/Button";
6
+ import { Select } from "../shared/Select";
7
+ import { displayFilenameExt, mimeToExt } from "../../media/utils";
8
+ function formatFileSize(bytes) {
9
+ if (bytes >= 1048576)
10
+ return `${Math.round(bytes / 1048576)}MB`;
11
+ if (bytes >= 1024)
12
+ return `${Math.round(bytes / 1024)}KB`;
13
+ return `${bytes}B`;
14
+ }
15
+ function thumbnailSrc(item, localUrls) {
16
+ const localUrl = localUrls[item.id];
17
+ if (localUrl)
18
+ return localUrl;
19
+ if (item.kind === "video") {
20
+ return `/api/media/${item.id}/original.${mimeToExt(item.mimeType)}`;
21
+ }
22
+ if (item.kind === "image" && item.variants.length > 0) {
23
+ const smallest = item.variants.reduce((a, b) => (a.width < b.width ? a : b));
24
+ return `/api/media/${item.id}/${smallest.width}.webp`;
25
+ }
26
+ return `/api/media/${item.id}/poster.webp`;
27
+ }
28
+ function displayFilename(item) {
29
+ return `${item.originalName}${displayFilenameExt(item.mimeType)}`;
30
+ }
31
+ function UploadZone({ onUpload }) {
32
+ const [dragging, setDragging] = useState(false);
33
+ const inputRef = useRef(null);
34
+ const handleFiles = useCallback((files) => {
35
+ if (!files || files.length === 0)
36
+ return;
37
+ onUpload(Array.from(files));
38
+ }, [onUpload]);
39
+ return (_jsxs("button", { type: "button", onClick: () => inputRef.current?.click(), onDragOver: (e) => {
40
+ e.preventDefault();
41
+ setDragging(true);
42
+ }, onDragLeave: () => setDragging(false), onDrop: (e) => {
43
+ e.preventDefault();
44
+ setDragging(false);
45
+ handleFiles(e.dataTransfer.files);
46
+ }, className: cn("flex w-full cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed px-6 py-8 text-center transition-colors", dragging
47
+ ? "border-primary bg-primary/5"
48
+ : "border-base-200 hover:border-base-300"), children: [_jsx(Upload, { size: 24, className: "text-base-contrast-light" }), _jsx("span", { className: "text-sm text-base-contrast-light", children: "Drag & drop files or click to browse" }), _jsx("input", { ref: inputRef, type: "file", multiple: true, accept: "image/*,video/*", className: "hidden", onChange: (e) => {
49
+ handleFiles(e.target.files);
50
+ e.target.value = "";
51
+ } })] }));
52
+ }
53
+ export function MediaLibraryModal({ mode, items, onSelect, onUpload, onDelete, onAltChange, referenceCountMap, localUrlMap = {}, maxFileSize, }) {
54
+ const [search, setSearch] = useState("");
55
+ const [kindFilter, setKindFilter] = useState("all");
56
+ const [selected, setSelected] = useState(new Set());
57
+ const [rejectedFiles, setRejectedFiles] = useState([]);
58
+ const handleUpload = useCallback((files) => {
59
+ if (!maxFileSize) {
60
+ onUpload(files);
61
+ return;
62
+ }
63
+ const valid = [];
64
+ const rejected = [];
65
+ for (const file of files) {
66
+ if (file.size > maxFileSize) {
67
+ rejected.push(file.name);
68
+ }
69
+ else {
70
+ valid.push(file);
71
+ }
72
+ }
73
+ if (rejected.length > 0)
74
+ setRejectedFiles(rejected);
75
+ if (valid.length > 0)
76
+ onUpload(valid);
77
+ }, [maxFileSize, onUpload]);
78
+ const filtered = items.filter((item) => {
79
+ const matchesSearch = item.originalName
80
+ .toLowerCase()
81
+ .includes(search.toLowerCase());
82
+ const matchesKind = kindFilter === "all" || item.kind === kindFilter;
83
+ return matchesSearch && matchesKind;
84
+ });
85
+ function toggleSelect(id) {
86
+ setSelected((prev) => {
87
+ const next = new Set(prev);
88
+ if (next.has(id)) {
89
+ next.delete(id);
90
+ }
91
+ else {
92
+ next.add(id);
93
+ }
94
+ return next;
95
+ });
96
+ }
97
+ const [confirmDelete, setConfirmDelete] = useState(false);
98
+ const selectedIds = Array.from(selected);
99
+ const totalUsage = selectedIds.reduce((sum, id) => sum + (referenceCountMap[id] ?? 0), 0);
100
+ function handleBatchDelete() {
101
+ if (totalUsage > 0) {
102
+ setConfirmDelete(true);
103
+ return;
104
+ }
105
+ onDelete(selectedIds);
106
+ setSelected(new Set());
107
+ }
108
+ function handleConfirmDelete() {
109
+ onDelete(selectedIds);
110
+ setSelected(new Set());
111
+ setConfirmDelete(false);
112
+ }
113
+ return (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(UploadZone, { onUpload: handleUpload }), _jsxs("div", { className: "sticky top-[-16px] z-10 -mx-6 space-y-3 bg-base px-6 pb-3 pt-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { size: 14, className: "pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-base-contrast-light" }), _jsx("input", { type: "text", placeholder: "Search media...", value: search, onChange: (e) => setSearch(e.target.value), className: "w-full rounded border border-base-200 bg-base py-1.5 pl-8 pr-3 text-sm text-base-contrast placeholder:text-base-contrast-light focus:outline-none focus:ring-1 focus:ring-primary" })] }), _jsx(Select, { value: kindFilter, onChange: (v) => setKindFilter(v), options: [
114
+ { value: "all", label: "All types" },
115
+ { value: "image", label: "Images" },
116
+ { value: "animated", label: "Animated" },
117
+ { value: "video", label: "Video" },
118
+ ], selectClassName: "py-1.5 pr-7 pl-2.5" }), mode === "manage" && selected.size > 0 && (_jsxs(Button, { variant: "destructive", size: "sm", onClick: handleBatchDelete, className: "flex items-center gap-1.5", children: [_jsx(Trash2, { size: 13 }), "Delete ", selected.size] }))] }), confirmDelete && (_jsxs("div", { className: "flex flex-col items-center rounded-lg border border-red-200 bg-red-50 px-4 py-3 lg:flex-row lg:justify-between dark:border-red-900/50 dark:bg-red-950/30", children: [_jsx("p", { className: "mb-2 text-center text-sm text-red-800 lg:mb-0 lg:text-left dark:text-red-200", children: "Some of these images are being used. Deleting these will remove them from these references." }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(Button, { variant: "secondary", size: "sm", onClick: () => setConfirmDelete(false), children: "Cancel" }), _jsx(Button, { variant: "destructive", size: "sm", onClick: handleConfirmDelete, children: "Confirm Delete" })] })] })), rejectedFiles.length > 0 && maxFileSize && (_jsxs("div", { className: "flex flex-col items-center rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 lg:flex-row lg:justify-between dark:border-amber-900/50 dark:bg-amber-950/30", children: [_jsxs("p", { className: "mb-2 text-center text-sm text-amber-800 lg:mb-0 lg:text-left dark:text-amber-200", children: [rejectedFiles.length === 1
119
+ ? `"${rejectedFiles[0]}" exceeds`
120
+ : `${rejectedFiles.length} files exceed`, " the ", formatFileSize(maxFileSize), " file size limit."] }), _jsx("div", { className: "flex shrink-0 items-center", children: _jsx(Button, { variant: "secondary", size: "sm", onClick: () => setRejectedFiles([]), children: "Dismiss" }) })] }))] }), filtered.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-12 text-center", children: [_jsx("p", { className: "text-sm font-medium text-base-contrast", children: items.length === 0 ? "No media uploaded yet" : "No results found" }), _jsx("p", { className: "text-xs text-base-contrast-light", children: items.length === 0
121
+ ? "Upload files using the drop zone above."
122
+ : "Try a different search or filter." })] })) : (_jsx("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5", children: filtered.map((item) => {
123
+ const isSelected = selected.has(item.id);
124
+ const refCount = referenceCountMap[item.id] ?? 0;
125
+ const usageLabel = refCount === 0 ? "Not used" : `Used ${refCount}x`;
126
+ return (_jsxs("div", { className: "group flex flex-col gap-1.5", onClick: () => {
127
+ if (mode === "select") {
128
+ onSelect(item.id);
129
+ }
130
+ else {
131
+ toggleSelect(item.id);
132
+ }
133
+ }, children: [_jsxs("div", { className: cn("relative aspect-square cursor-pointer overflow-hidden rounded-lg border-2 transition-colors", mode === "select"
134
+ ? "border-transparent hover:border-primary"
135
+ : isSelected
136
+ ? "border-primary"
137
+ : "border-transparent hover:border-base-300"), children: [_jsx("div", { className: "h-full w-full bg-base-accent", children: item.kind === "video" ? (_jsx("video", { src: thumbnailSrc(item, localUrlMap), muted: true, playsInline: true, className: "h-full w-full object-cover", onMouseEnter: (e) => e.currentTarget.play().catch(() => { }), onMouseLeave: (e) => { e.currentTarget.pause(); e.currentTarget.currentTime = 0; } })) : (_jsx("img", { src: thumbnailSrc(item, localUrlMap), alt: item.originalName, className: "h-full w-full object-cover" })) }), mode === "manage" && (_jsx("div", { className: cn("absolute top-1.5 left-1.5 flex h-5 w-5 items-center justify-center rounded-full border-2 transition-colors", isSelected
138
+ ? "border-primary bg-primary"
139
+ : "border-white/80 bg-white/40 opacity-0 group-hover:opacity-100"), children: isSelected && (_jsx("div", { className: "h-2 w-2 rounded-full bg-white" })) })), mode === "manage" && (_jsx("div", { className: cn("absolute top-1.5 right-1.5 rounded-full px-2 py-0.5 text-[11px] font-medium transition-opacity", isSelected
140
+ ? "opacity-100"
141
+ : "opacity-0 group-hover:opacity-100", refCount > 0
142
+ ? "bg-black/50 text-white"
143
+ : "bg-black/50 text-white/70"), children: usageLabel })), _jsx("div", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/60 to-transparent px-2 pb-1.5 pt-4 opacity-0 transition-opacity group-hover:opacity-100", children: _jsx("p", { className: "truncate text-[11px] text-white", children: displayFilename(item) }) })] }), _jsxs("div", { className: "px-0.5", children: [_jsx("label", { className: "text-[10px] font-medium uppercase leading-none tracking-wide text-base-contrast-light/50", children: "Alt text" }), _jsx("textarea", { value: item.alt, placeholder: "Describe this image for accessibility", rows: 2, onClick: (e) => e.stopPropagation(), onChange: (e) => onAltChange?.(item.id, e.target.value), className: "w-full resize-none border-0 bg-transparent p-0 text-xs leading-snug text-base-contrast placeholder:text-base-contrast-light/40 focus:outline-none focus:ring-0" })] })] }, item.id));
144
+ }) }))] }));
145
+ }
@@ -0,0 +1,7 @@
1
+ import type { QueueItem } from "../../media/queue";
2
+ interface ProcessingIndicatorProps {
3
+ items: QueueItem[];
4
+ }
5
+ export declare function ProcessingIndicator({ items }: ProcessingIndicatorProps): import("react/jsx-runtime").JSX.Element | null;
6
+ export {};
7
+ //# sourceMappingURL=ProcessingIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessingIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/shell/ProcessingIndicator.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,UAAU,wBAAwB;IAChC,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,wBAAwB,kDA0EtE"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState } from "react";
3
+ import { Loader2 } from "lucide-react";
4
+ import { cn } from "../../lib/cn";
5
+ export function ProcessingIndicator({ items }) {
6
+ const [open, setOpen] = useState(false);
7
+ const buttonRef = useRef(null);
8
+ const activeItems = items.filter((i) => i.state === "active");
9
+ const queuedItems = items.filter((i) => i.state === "queued");
10
+ const errorItems = items.filter((i) => i.state === "error");
11
+ const visibleCount = activeItems.length + queuedItems.length + errorItems.length;
12
+ if (visibleCount === 0)
13
+ return null;
14
+ return (_jsxs("div", { className: "relative inline-flex", children: [_jsxs("button", { ref: buttonRef, type: "button", onClick: () => setOpen((o) => !o), className: cn("relative inline-flex items-center gap-1.5 rounded-md border border-base-200 bg-base px-3 py-1.5 text-sm font-medium text-base-contrast transition-colors hover:bg-base-accent"), "aria-label": "Processing status", children: [_jsx(Loader2, { size: 14, className: "animate-spin text-primary" }), _jsx("span", { className: "text-xs font-semibold tabular-nums", children: visibleCount })] }), open && (_jsx("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-64 rounded-lg border border-base-200 bg-base shadow-lg", children: _jsxs("div", { className: "flex flex-col divide-y divide-base-200", children: [activeItems.map((item) => (_jsxs("div", { className: "flex flex-col gap-1.5 px-3 py-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "truncate text-xs font-medium text-base-contrast", children: item.originalName }), _jsxs("span", { className: "ml-2 shrink-0 text-xs text-base-contrast-light", children: [item.percent, "%"] })] }), _jsx("div", { className: "h-1 overflow-hidden rounded-full bg-base-accent", children: _jsx("div", { className: "h-full rounded-full bg-primary transition-all", style: { width: `${item.percent}%` } }) })] }, item.id))), errorItems.map((item) => (_jsxs("div", { className: "flex flex-col gap-0.5 px-3 py-2", children: [_jsx("span", { className: "truncate text-xs font-medium text-red-600", children: item.originalName }), item.error && (_jsx("span", { className: "text-xs text-red-500", children: item.error }))] }, item.id))), queuedItems.length > 0 && (_jsx("div", { className: "px-3 py-2", children: _jsxs("span", { className: "text-xs text-base-contrast-light", children: ["+", queuedItems.length, " queued"] }) }))] }) }))] }));
15
+ }
@@ -0,0 +1,9 @@
1
+ import { type TypeOption } from "./SectionTypePicker";
2
+ interface SectionSkeletonProps {
3
+ types: TypeOption[];
4
+ onSelect: (type: string) => void;
5
+ onDismiss: () => void;
6
+ }
7
+ export declare function SectionSkeleton({ types, onSelect, onDismiss }: SectionSkeletonProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=SectionSkeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionSkeleton.d.ts","sourceRoot":"","sources":["../../../src/components/shell/SectionSkeleton.tsx"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIzE,UAAU,oBAAoB;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,oBAAoB,2CA0CnF"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import { SectionTypePicker } from "./SectionTypePicker";
4
+ import { SectionLayout } from "../sections/SectionLayout";
5
+ import { cn } from "../../lib/cn";
6
+ export function SectionSkeleton({ types, onSelect, onDismiss }) {
7
+ const [isVisible, setIsVisible] = useState(false);
8
+ useEffect(() => {
9
+ // Trigger animation on next frame
10
+ requestAnimationFrame(() => setIsVisible(true));
11
+ }, []);
12
+ useEffect(() => {
13
+ function handleKeyDown(e) {
14
+ if (e.key === "Escape") {
15
+ onDismiss();
16
+ }
17
+ }
18
+ document.addEventListener("keydown", handleKeyDown);
19
+ return () => document.removeEventListener("keydown", handleKeyDown);
20
+ }, [onDismiss]);
21
+ return (_jsx(SectionLayout, { type: "skeleton", status: "draft", children: _jsxs("div", { className: cn("relative transition-all duration-200", isVisible ? "opacity-100" : "opacity-0 -translate-y-2"), children: [_jsx("div", { className: "flex h-20 items-center justify-center rounded-lg bg-base-accent", children: _jsx("span", { className: "text-sm text-base-contrast-light/50", children: "New section" }) }), _jsx("div", { className: "relative flex justify-center", children: _jsx(SectionTypePicker, { types: types, onSelect: onSelect, onClose: onDismiss }) })] }) }));
22
+ }
@@ -0,0 +1,14 @@
1
+ import { type ComponentType } from "react";
2
+ export interface TypeOption {
3
+ type: string;
4
+ label: string;
5
+ icon: ComponentType;
6
+ }
7
+ interface SectionTypePickerProps {
8
+ types: TypeOption[];
9
+ onSelect: (type: string) => void;
10
+ onClose: () => void;
11
+ }
12
+ export declare function SectionTypePicker({ types, onSelect, onClose }: SectionTypePickerProps): import("react/jsx-runtime").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=SectionTypePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionTypePicker.d.ts","sourceRoot":"","sources":["../../../src/components/shell/SectionTypePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAE9D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,sBAAsB,2CAgCrF"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
3
+ export function SectionTypePicker({ types, onSelect, onClose }) {
4
+ const panelRef = useRef(null);
5
+ useEffect(() => {
6
+ function handleMouseDown(e) {
7
+ if (panelRef.current && !panelRef.current.contains(e.target)) {
8
+ onClose();
9
+ }
10
+ }
11
+ document.addEventListener("mousedown", handleMouseDown);
12
+ return () => document.removeEventListener("mousedown", handleMouseDown);
13
+ }, [onClose]);
14
+ return (_jsx("div", { ref: panelRef, className: "absolute z-50 mt-1 w-64 rounded-lg border border-base-200 bg-base p-2 shadow-lg", children: types.map(({ type, label, icon: Icon }) => (_jsxs("button", { className: "cursor-pointer flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-sm text-base-contrast-light hover:bg-base-accent hover:text-base-contrast", onClick: () => onSelect(type), children: [_jsx("span", { className: "flex h-6 w-6 items-center justify-center text-base", children: _jsx(Icon, {}) }), _jsx("span", { children: label })] }, type))) }));
15
+ }
@@ -0,0 +1,8 @@
1
+ import type { SiteConfig } from "../../schemas/site-config";
2
+ interface Props {
3
+ siteConfig: SiteConfig;
4
+ onChange: (config: SiteConfig) => void;
5
+ }
6
+ export declare function SiteSettingsDisplay({ siteConfig, onChange }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=SiteSettingsDisplay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteSettingsDisplay.d.ts","sourceRoot":"","sources":["../../../src/components/shell/SiteSettingsDisplay.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,UAAU,KAAK;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAQD,wBAAgB,mBAAmB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,KAAK,2CAyDlE"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ColorPicker } from "../shared/ColorPicker";
3
+ import { FontPicker } from "../shared/FontPicker";
4
+ import { Input } from "../shared/Input";
5
+ import { Select } from "../shared/Select";
6
+ import { FormLabel } from "../shared/FormLabel";
7
+ import { deriveContrast } from "../../lib/contrast";
8
+ import { buildGoogleFontsUrl } from "../../lib/google-fonts";
9
+ const darkModeOptions = [
10
+ { label: "Light", value: "light" },
11
+ { label: "Dark", value: "dark" },
12
+ { label: "Optional (viewer toggle)", value: "optional" },
13
+ ];
14
+ export function SiteSettingsDisplay({ siteConfig, onChange }) {
15
+ function update(patch) {
16
+ onChange({ ...siteConfig, ...patch });
17
+ }
18
+ function handleColorChange(color) {
19
+ const contrast = deriveContrast(color);
20
+ onChange({ ...siteConfig, primaryColor: color, primaryContrast: contrast });
21
+ }
22
+ function handleFontChange(field, family) {
23
+ const next = { ...siteConfig, [field]: family };
24
+ next.googleFontsUrl = buildGoogleFontsUrl(next.headingFont, next.bodyFont);
25
+ onChange(next);
26
+ }
27
+ return (_jsxs("div", { className: "space-y-5", children: [_jsx(Input, { label: "Site name", value: siteConfig.siteName, onChange: (value) => update({ siteName: value }), placeholder: "Brand Portal" }), _jsxs("div", { children: [_jsx(FormLabel, { children: "Primary color" }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(ColorPicker, { value: siteConfig.primaryColor, onChange: handleColorChange, label: "Primary color" }), _jsx("span", { className: "text-sm text-base-contrast-light", children: siteConfig.primaryColor })] })] }), _jsx(Select, { label: "Dark mode", value: siteConfig.darkMode, onChange: (value) => update({ darkMode: value }), options: darkModeOptions }), _jsx(FontPicker, { label: "Heading font", value: siteConfig.headingFont, onChange: (family) => handleFontChange("headingFont", family) }), _jsx(FontPicker, { label: "Body font", value: siteConfig.bodyFont, onChange: (family) => handleFontChange("bodyFont", family) })] }));
28
+ }
@@ -0,0 +1,24 @@
1
+ import type { SiteConfig } from "../../schemas/site-config";
2
+ import type { Audience } from "../../auth/types";
3
+ interface Props {
4
+ isOpen: boolean;
5
+ onClose: () => void;
6
+ siteConfig: SiteConfig;
7
+ onSiteConfigChange: (config: SiteConfig) => void;
8
+ onAudiencesChange: (audiences: Audience[]) => void;
9
+ capabilities: {
10
+ oauth: boolean;
11
+ emailPassword: boolean;
12
+ passwordOnly: boolean;
13
+ userManagement: boolean;
14
+ audienceManagement: boolean;
15
+ passwordToggle: boolean;
16
+ };
17
+ currentUser: {
18
+ email: string;
19
+ role: "owner" | "editor";
20
+ } | null;
21
+ }
22
+ export declare function SiteSettingsModal({ isOpen, onClose, siteConfig, onSiteConfigChange, onAudiencesChange, capabilities, currentUser }: Props): import("react/jsx-runtime").JSX.Element;
23
+ export {};
24
+ //# sourceMappingURL=SiteSettingsModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteSettingsModal.d.ts","sourceRoot":"","sources":["../../../src/components/shell/SiteSettingsModal.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,UAAU,KAAK;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACjD,iBAAiB,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAID,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,2CAmGzI"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { EditorModal } from "./EditorModal";
4
+ import { Button } from "../shared/Button";
5
+ import { SiteSettingsViewerAccess } from "./SiteSettingsViewerAccess";
6
+ import { SiteSettingsDisplay } from "./SiteSettingsDisplay";
7
+ import { SiteSettingsUsers } from "./SiteSettingsUsers";
8
+ import { cn } from "../../lib/cn";
9
+ export function SiteSettingsModal({ isOpen, onClose, siteConfig, onSiteConfigChange, onAudiencesChange, capabilities, currentUser }) {
10
+ const tabs = [
11
+ { id: "users", label: "Users", show: capabilities.userManagement },
12
+ { id: "viewer-access", label: "Viewer Access", show: true },
13
+ { id: "display", label: "Display", show: true },
14
+ ];
15
+ const visibleTabs = tabs.filter((t) => t.show);
16
+ const [activeTab, setActiveTab] = useState(visibleTabs[0]?.id ?? "display");
17
+ const [signOutError, setSignOutError] = useState(null);
18
+ async function handleSignOut() {
19
+ setSignOutError(null);
20
+ try {
21
+ const res = await fetch("/api/auth/sign-out", { method: "POST" });
22
+ if (!res.ok) {
23
+ setSignOutError("Sign out failed");
24
+ return;
25
+ }
26
+ window.location.assign("/edit/login");
27
+ }
28
+ catch {
29
+ setSignOutError("Network error during sign out");
30
+ }
31
+ }
32
+ const identityLabel = currentUser?.email
33
+ ? currentUser.email
34
+ : currentUser
35
+ ? (currentUser.role === "owner" ? "Owner" : "Editor")
36
+ : null;
37
+ return (_jsx(EditorModal, { isOpen: isOpen, onClose: onClose, title: "Site Settings", size: "settings", noPadding: true, children: _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [_jsx("div", { className: "border-b border-base-200", children: _jsx("div", { className: "flex px-6", role: "tablist", children: visibleTabs.map((tab) => (_jsx("button", { role: "tab", "aria-selected": activeTab === tab.id, onClick: () => setActiveTab(tab.id), className: cn("cursor-pointer px-4 py-2 text-sm font-medium border-b-2 -mb-px", activeTab === tab.id
38
+ ? "border-brand text-brand"
39
+ : "border-transparent text-base-contrast-light hover:text-base-contrast"), children: tab.label }, tab.id))) }) }), _jsxs("div", { "data-testid": "site-settings-tab-panel", className: "flex flex-1 flex-col overflow-y-auto px-6 py-4", children: [activeTab === "users" && _jsx(SiteSettingsUsers, { currentUser: currentUser }), activeTab === "viewer-access" && (_jsx(SiteSettingsViewerAccess, { audienceManagement: capabilities.audienceManagement, passwordToggle: capabilities.passwordToggle, onAudiencesChange: onAudiencesChange })), activeTab === "display" && (_jsx(SiteSettingsDisplay, { siteConfig: siteConfig, onChange: onSiteConfigChange }))] }), currentUser && (_jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-base-200 px-6 py-3", children: [_jsxs("div", { className: "text-xs text-base-contrast-light", children: ["Signed in as", " ", _jsx("span", { className: "font-medium text-base-contrast", children: identityLabel }), currentUser.email && (_jsxs("span", { className: "ml-1 capitalize", children: ["(", currentUser.role, ")"] })), signOutError && (_jsxs("span", { className: "ml-2 text-red-600", children: ["\u2014 ", signOutError] }))] }), _jsx(Button, { type: "button", variant: "destructive", onClick: handleSignOut, children: "Sign out" })] }))] }) }));
40
+ }
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ currentUser: {
3
+ email: string;
4
+ role: "owner" | "editor";
5
+ } | null;
6
+ }
7
+ export declare function SiteSettingsUsers({ currentUser }: Props): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=SiteSettingsUsers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteSettingsUsers.d.ts","sourceRoot":"","sources":["../../../src/components/shell/SiteSettingsUsers.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,WAAW,EAAE,EAAE,KAAK,2CA6KvD"}
@@ -0,0 +1,87 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment, useState, useEffect } from "react";
3
+ import { ChevronDown } from "lucide-react";
4
+ import { Button } from "../shared/Button";
5
+ export function SiteSettingsUsers({ currentUser }) {
6
+ const [users, setUsers] = useState([]);
7
+ const [loading, setLoading] = useState(true);
8
+ const [inviteEmail, setInviteEmail] = useState("");
9
+ const [inviteRole, setInviteRole] = useState("editor");
10
+ const [error, setError] = useState(null);
11
+ const [confirmingRevoke, setConfirmingRevoke] = useState(null);
12
+ async function loadUsers() {
13
+ try {
14
+ const res = await fetch("/api/auth/users");
15
+ if (!res.ok) {
16
+ setError("Failed to load users");
17
+ setUsers([]);
18
+ return;
19
+ }
20
+ const data = await res.json();
21
+ setUsers(data.users);
22
+ }
23
+ catch {
24
+ setError("Network error while loading users");
25
+ setUsers([]);
26
+ }
27
+ finally {
28
+ setLoading(false);
29
+ }
30
+ }
31
+ useEffect(() => {
32
+ loadUsers();
33
+ }, []);
34
+ async function handleInvite(e) {
35
+ e.preventDefault();
36
+ setError(null);
37
+ try {
38
+ const res = await fetch("/api/auth/users", {
39
+ method: "POST",
40
+ headers: { "Content-Type": "application/json" },
41
+ body: JSON.stringify({ email: inviteEmail, role: inviteRole }),
42
+ });
43
+ if (!res.ok) {
44
+ const data = await res.json().catch(() => ({}));
45
+ setError(data.error || "Invite failed");
46
+ return;
47
+ }
48
+ setInviteEmail("");
49
+ await loadUsers();
50
+ }
51
+ catch {
52
+ setError("Network error while inviting");
53
+ }
54
+ }
55
+ function handleRevoke(userId) {
56
+ setError(null);
57
+ const ownerCount = users.filter((u) => u.role === "owner").length;
58
+ const user = users.find((u) => u.id === userId);
59
+ if (user?.role === "owner" && ownerCount <= 1) {
60
+ setError("Cannot remove the last owner");
61
+ return;
62
+ }
63
+ setConfirmingRevoke(userId);
64
+ }
65
+ async function confirmRevoke(userId) {
66
+ setConfirmingRevoke(null);
67
+ try {
68
+ const res = await fetch("/api/auth/users", {
69
+ method: "DELETE",
70
+ headers: { "Content-Type": "application/json" },
71
+ body: JSON.stringify({ userId }),
72
+ });
73
+ if (!res.ok) {
74
+ const data = await res.json().catch(() => ({}));
75
+ setError(data.error || "Revoke failed");
76
+ return;
77
+ }
78
+ await loadUsers();
79
+ }
80
+ catch {
81
+ setError("Network error while removing user");
82
+ }
83
+ }
84
+ if (loading)
85
+ return _jsx("p", { className: "text-sm text-base-contrast-light", children: "Loading users..." });
86
+ return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "grid grid-cols-[1fr_7rem_5rem] text-sm", children: [_jsx("div", { className: "flex items-center border-b border-base-200 pr-2 pb-2 text-base-contrast-light", children: "Email" }), _jsx("div", { className: "flex items-center border-b border-base-200 pr-2 pb-2 text-base-contrast-light", children: "Role" }), _jsx("div", { className: "border-b border-base-200 pb-2" }), users.map((user) => (_jsxs(Fragment, { children: [_jsx("div", { className: "flex items-center border-b border-base-200 py-2 pr-2 text-base-contrast", children: user.email }), _jsx("div", { className: "flex items-center border-b border-base-200 py-2 pr-2 capitalize text-base-contrast-light", children: user.role }), _jsx("div", { className: "flex items-center justify-end border-b border-base-200 py-2", children: currentUser?.email === user.email ? (_jsx("span", { className: "text-xs text-base-contrast-light", children: "\u2014" })) : confirmingRevoke === user.id ? (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(Button, { type: "button", variant: "ghost", tone: "destructive", onClick: () => confirmRevoke(user.id), children: "Confirm" }), _jsx(Button, { type: "button", variant: "ghost", onClick: () => setConfirmingRevoke(null), children: "Cancel" })] })) : (_jsx(Button, { type: "button", variant: "ghost", tone: "destructive", onClick: () => handleRevoke(user.id), children: "Remove" })) })] }, user.id)))] }), _jsxs("form", { onSubmit: handleInvite, className: "grid grid-cols-[1fr_7rem_5rem] text-sm", children: [_jsx("div", { className: "pr-2", children: _jsx("input", { type: "email", placeholder: "Email address", value: inviteEmail, onChange: (e) => setInviteEmail(e.target.value), required: true, "aria-label": "Email address", className: "w-full rounded border border-base-200 bg-base px-3 py-2 text-sm text-base-contrast focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast" }) }), _jsx("div", { className: "pr-2", children: _jsxs("div", { className: "relative", children: [_jsxs("select", { value: inviteRole, onChange: (e) => setInviteRole(e.target.value), "aria-label": "Role", className: "w-full appearance-none rounded border border-base-200 bg-base py-2 pr-8 pl-3 text-sm text-base-contrast focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast", children: [_jsx("option", { value: "editor", children: "Editor" }), _jsx("option", { value: "owner", children: "Owner" })] }), _jsx(ChevronDown, { size: 14, className: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-base-contrast-light" })] }) }), _jsx(Button, { type: "submit", variant: "primary", size: "md", className: "w-full", children: "Invite" })] }), error && _jsx("p", { className: "text-sm text-red-600", children: error })] }));
87
+ }
@@ -0,0 +1,9 @@
1
+ import type { Audience } from "../../auth/types";
2
+ interface Props {
3
+ audienceManagement: boolean;
4
+ passwordToggle: boolean;
5
+ onAudiencesChange: (audiences: Audience[]) => void;
6
+ }
7
+ export declare function SiteSettingsViewerAccess({ audienceManagement, passwordToggle, onAudiencesChange }: Props): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=SiteSettingsViewerAccess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteSettingsViewerAccess.d.ts","sourceRoot":"","sources":["../../../src/components/shell/SiteSettingsViewerAccess.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAOjD,UAAU,KAAK;IACb,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;CACpD;AAED,wBAAgB,wBAAwB,CAAC,EAAE,kBAAkB,EAAE,cAAc,EAAE,iBAAiB,EAAE,EAAE,KAAK,2CA4JxG"}
@@ -0,0 +1,94 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback } from "react";
3
+ import { Button } from "../shared/Button";
4
+ import { Toggle } from "../shared/Toggle";
5
+ import { AudienceRow } from "./AudienceRow";
6
+ import { AudienceAddForm } from "./AudienceAddForm";
7
+ import { cn } from "../../lib/cn";
8
+ export function SiteSettingsViewerAccess({ audienceManagement, passwordToggle, onAudiencesChange }) {
9
+ const [audiences, setAudiences] = useState([]);
10
+ const [passwordEnabled, setPasswordEnabled] = useState(true);
11
+ const [loading, setLoading] = useState(true);
12
+ const [showAddForm, setShowAddForm] = useState(false);
13
+ const [toggleError, setToggleError] = useState(null);
14
+ const loadAudiences = useCallback(async () => {
15
+ try {
16
+ const res = await fetch("/api/auth/audiences");
17
+ const data = await res.json();
18
+ const list = data.audiences ?? [];
19
+ setAudiences(list);
20
+ onAudiencesChange(list);
21
+ setPasswordEnabled(data.passwordEnabled ?? true);
22
+ }
23
+ finally {
24
+ setLoading(false);
25
+ }
26
+ }, [onAudiencesChange]);
27
+ useEffect(() => {
28
+ loadAudiences();
29
+ }, [loadAudiences]);
30
+ async function handlePasswordToggle(enabled) {
31
+ setToggleError(null);
32
+ const previous = passwordEnabled;
33
+ setPasswordEnabled(enabled);
34
+ try {
35
+ const res = await fetch("/api/auth/password-enabled", {
36
+ method: "POST",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: JSON.stringify({ enabled }),
39
+ });
40
+ if (!res.ok) {
41
+ const body = await res.json().catch(() => ({}));
42
+ setToggleError(body.error ?? "Update failed");
43
+ setPasswordEnabled(previous);
44
+ }
45
+ }
46
+ catch {
47
+ setToggleError("Network error");
48
+ setPasswordEnabled(previous);
49
+ }
50
+ }
51
+ async function handleAdd(data) {
52
+ const res = await fetch("/api/auth/audiences", {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/json" },
55
+ body: JSON.stringify(data),
56
+ });
57
+ if (!res.ok) {
58
+ const err = await res.json().catch(() => ({}));
59
+ throw new Error(err.error ?? "Add failed");
60
+ }
61
+ setShowAddForm(false);
62
+ await loadAudiences();
63
+ }
64
+ async function handleSave(name, patch) {
65
+ const res = await fetch("/api/auth/audiences", {
66
+ method: "PATCH",
67
+ headers: { "Content-Type": "application/json" },
68
+ body: JSON.stringify({ name, ...patch }),
69
+ });
70
+ if (!res.ok) {
71
+ const err = await res.json().catch(() => ({}));
72
+ throw new Error(err.error ?? "Save failed");
73
+ }
74
+ await loadAudiences();
75
+ }
76
+ async function handleDelete(name) {
77
+ const res = await fetch("/api/auth/audiences", {
78
+ method: "DELETE",
79
+ headers: { "Content-Type": "application/json" },
80
+ body: JSON.stringify({ name }),
81
+ });
82
+ if (!res.ok) {
83
+ const err = await res.json().catch(() => ({}));
84
+ throw new Error(err.error ?? "Delete failed");
85
+ }
86
+ await loadAudiences();
87
+ }
88
+ if (loading) {
89
+ return _jsx("p", { className: "text-sm text-base-contrast-light", children: "Loading audiences..." });
90
+ }
91
+ return (_jsxs("div", { className: "space-y-4", children: [!audienceManagement && (_jsx("p", { className: "text-xs text-base-contrast-light", children: "This site is running in password-only mode. A developer can configure the environment variables for Admin, Editor, and Viewer details." })), passwordToggle && (_jsxs("div", { className: "space-y-2 rounded border border-base-200 p-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Toggle, { checked: passwordEnabled, onChange: handlePasswordToggle, label: "Require password to view site" }), _jsx("span", { className: "text-sm font-medium", children: "Require password to view site" })] }), _jsx("p", { className: "text-xs text-base-contrast-light", children: passwordEnabled
92
+ ? "Viewers must select an audience and enter a password to see any content."
93
+ : "Site is fully public. All published sections are visible to anyone." }), toggleError && _jsx("p", { className: "text-xs text-red-600", children: toggleError })] })), _jsxs("div", { className: cn("space-y-2", !passwordEnabled && "opacity-60"), children: [!passwordEnabled && (_jsx("p", { className: "mb-2 text-xs text-base-contrast-light", children: "Audiences are saved but not enforced while the password is disabled." })), audiences.map((a) => (_jsx(AudienceRow, { audience: a, isDefault: a.isDefault, canMutate: audienceManagement, onSave: (patch) => handleSave(a.name, patch), onDelete: () => handleDelete(a.name) }, a.name))), audiences.length === 0 && (_jsx("p", { className: "text-sm text-base-contrast-light", children: "No audiences configured." }))] }), audienceManagement && (showAddForm ? (_jsx(AudienceAddForm, { onSubmit: handleAdd, onCancel: () => setShowAddForm(false) })) : (_jsx(Button, { variant: "secondary", onClick: () => setShowAddForm(true), children: "Add audience" })))] }));
94
+ }
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ audiences: Array<{
3
+ name: string;
4
+ displayName: string;
5
+ }>;
6
+ next?: string | null;
7
+ }
8
+ export declare function ViewerLoginForm({ audiences, next }: Props): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=ViewerLoginForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ViewerLoginForm.d.ts","sourceRoot":"","sources":["../../../src/components/shell/ViewerLoginForm.tsx"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,KAAK,2CAoFzD"}