@actuate-media/cms-admin 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +8 -5
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/__tests__/layout/primitives.test.d.ts +2 -0
  5. package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
  6. package/dist/__tests__/layout/primitives.test.js +34 -0
  7. package/dist/__tests__/layout/primitives.test.js.map +1 -0
  8. package/dist/__tests__/lib/cv.test.d.ts +2 -0
  9. package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
  10. package/dist/__tests__/lib/cv.test.js +66 -0
  11. package/dist/__tests__/lib/cv.test.js.map +1 -0
  12. package/dist/actuate-admin.css +1 -1
  13. package/dist/assets/actuate-logo.d.ts +36 -0
  14. package/dist/assets/actuate-logo.d.ts.map +1 -0
  15. package/dist/assets/actuate-logo.js +15 -0
  16. package/dist/assets/actuate-logo.js.map +1 -0
  17. package/dist/components/Breadcrumbs.js +2 -2
  18. package/dist/components/CommandPalette.js +10 -10
  19. package/dist/components/ContentOverviewChart.js +3 -3
  20. package/dist/components/ErrorBoundary.js +1 -1
  21. package/dist/components/FocalPointPicker.js +2 -2
  22. package/dist/components/FolderTree.js +20 -20
  23. package/dist/components/LivePreview.js +3 -3
  24. package/dist/components/LocaleSwitcher.js +1 -1
  25. package/dist/components/MediaPickerModal.js +4 -4
  26. package/dist/components/PresenceIndicator.js +1 -1
  27. package/dist/components/SEOConfigPanel.d.ts +2 -0
  28. package/dist/components/SEOConfigPanel.d.ts.map +1 -0
  29. package/dist/components/SEOConfigPanel.js +174 -0
  30. package/dist/components/SEOConfigPanel.js.map +1 -0
  31. package/dist/components/SEOPanel.js +9 -9
  32. package/dist/components/SEOPerformance.js +2 -2
  33. package/dist/components/SchedulePublishDialog.d.ts +18 -0
  34. package/dist/components/SchedulePublishDialog.d.ts.map +1 -0
  35. package/dist/components/SchedulePublishDialog.js +106 -0
  36. package/dist/components/SchedulePublishDialog.js.map +1 -0
  37. package/dist/components/SharePreviewLinkDialog.d.ts +17 -0
  38. package/dist/components/SharePreviewLinkDialog.d.ts.map +1 -0
  39. package/dist/components/SharePreviewLinkDialog.js +83 -0
  40. package/dist/components/SharePreviewLinkDialog.js.map +1 -0
  41. package/dist/components/TipTapEditor.js +5 -5
  42. package/dist/components/VersionHistory.js +2 -2
  43. package/dist/components/ui/Badge.d.ts +33 -3
  44. package/dist/components/ui/Badge.d.ts.map +1 -1
  45. package/dist/components/ui/Badge.js +42 -8
  46. package/dist/components/ui/Badge.js.map +1 -1
  47. package/dist/components/ui/Button.d.ts +19 -8
  48. package/dist/components/ui/Button.d.ts.map +1 -1
  49. package/dist/components/ui/Button.js +35 -14
  50. package/dist/components/ui/Button.js.map +1 -1
  51. package/dist/components/ui/Card.d.ts +26 -0
  52. package/dist/components/ui/Card.d.ts.map +1 -0
  53. package/dist/components/ui/Card.js +45 -0
  54. package/dist/components/ui/Card.js.map +1 -0
  55. package/dist/components/ui/DataTable.js +1 -1
  56. package/dist/components/ui/Input.d.ts +15 -0
  57. package/dist/components/ui/Input.d.ts.map +1 -0
  58. package/dist/components/ui/Input.js +23 -0
  59. package/dist/components/ui/Input.js.map +1 -0
  60. package/dist/components/ui/SearchInput.js +1 -1
  61. package/dist/components/ui/Select.d.ts +16 -0
  62. package/dist/components/ui/Select.d.ts.map +1 -0
  63. package/dist/components/ui/Select.js +25 -0
  64. package/dist/components/ui/Select.js.map +1 -0
  65. package/dist/components/ui/Toast.js +1 -1
  66. package/dist/components/ui/index.d.ts +10 -4
  67. package/dist/components/ui/index.d.ts.map +1 -1
  68. package/dist/components/ui/index.js +5 -2
  69. package/dist/components/ui/index.js.map +1 -1
  70. package/dist/fields/BlockBuilderField.js +3 -3
  71. package/dist/fields/DateField.js +1 -1
  72. package/dist/fields/RelationshipField.js +3 -3
  73. package/dist/fields/TextField.js +1 -1
  74. package/dist/index.d.ts +6 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +5 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/layout/Header.js +1 -1
  79. package/dist/layout/Layout.d.ts +14 -0
  80. package/dist/layout/Layout.d.ts.map +1 -1
  81. package/dist/layout/Layout.js +17 -11
  82. package/dist/layout/Layout.js.map +1 -1
  83. package/dist/layout/Sidebar.d.ts.map +1 -1
  84. package/dist/layout/Sidebar.js +21 -11
  85. package/dist/layout/Sidebar.js.map +1 -1
  86. package/dist/layout/primitives/AdminShell.d.ts +43 -0
  87. package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
  88. package/dist/layout/primitives/AdminShell.js +51 -0
  89. package/dist/layout/primitives/AdminShell.js.map +1 -0
  90. package/dist/layout/primitives/Box.d.ts +19 -0
  91. package/dist/layout/primitives/Box.d.ts.map +1 -0
  92. package/dist/layout/primitives/Box.js +12 -0
  93. package/dist/layout/primitives/Box.js.map +1 -0
  94. package/dist/layout/primitives/Cluster.d.ts +27 -0
  95. package/dist/layout/primitives/Cluster.d.ts.map +1 -0
  96. package/dist/layout/primitives/Cluster.js +37 -0
  97. package/dist/layout/primitives/Cluster.js.map +1 -0
  98. package/dist/layout/primitives/Grid.d.ts +45 -0
  99. package/dist/layout/primitives/Grid.d.ts.map +1 -0
  100. package/dist/layout/primitives/Grid.js +59 -0
  101. package/dist/layout/primitives/Grid.js.map +1 -0
  102. package/dist/layout/primitives/PageContainer.d.ts +36 -0
  103. package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
  104. package/dist/layout/primitives/PageContainer.js +41 -0
  105. package/dist/layout/primitives/PageContainer.js.map +1 -0
  106. package/dist/layout/primitives/Split.d.ts +34 -0
  107. package/dist/layout/primitives/Split.d.ts.map +1 -0
  108. package/dist/layout/primitives/Split.js +27 -0
  109. package/dist/layout/primitives/Split.js.map +1 -0
  110. package/dist/layout/primitives/Stack.d.ts +23 -0
  111. package/dist/layout/primitives/Stack.d.ts.map +1 -0
  112. package/dist/layout/primitives/Stack.js +34 -0
  113. package/dist/layout/primitives/Stack.js.map +1 -0
  114. package/dist/layout/primitives/index.d.ts +30 -0
  115. package/dist/layout/primitives/index.d.ts.map +1 -0
  116. package/dist/layout/primitives/index.js +22 -0
  117. package/dist/layout/primitives/index.js.map +1 -0
  118. package/dist/layout/primitives/tokens.d.ts +48 -0
  119. package/dist/layout/primitives/tokens.d.ts.map +1 -0
  120. package/dist/layout/primitives/tokens.js +54 -0
  121. package/dist/layout/primitives/tokens.js.map +1 -0
  122. package/dist/lib/cv.d.ts +53 -0
  123. package/dist/lib/cv.d.ts.map +1 -0
  124. package/dist/lib/cv.js +39 -0
  125. package/dist/lib/cv.js.map +1 -0
  126. package/dist/views/ApiKeys.d.ts.map +1 -1
  127. package/dist/views/ApiKeys.js +13 -11
  128. package/dist/views/ApiKeys.js.map +1 -1
  129. package/dist/views/CollectionList.js +8 -8
  130. package/dist/views/Dashboard.d.ts.map +1 -1
  131. package/dist/views/Dashboard.js +333 -78
  132. package/dist/views/Dashboard.js.map +1 -1
  133. package/dist/views/DocumentEdit.d.ts.map +1 -1
  134. package/dist/views/DocumentEdit.js +17 -5
  135. package/dist/views/DocumentEdit.js.map +1 -1
  136. package/dist/views/ForgotPassword.js +2 -2
  137. package/dist/views/FormEditor.js +5 -5
  138. package/dist/views/FormSubmissions.js +6 -6
  139. package/dist/views/Forms.js +2 -2
  140. package/dist/views/Login.d.ts +16 -1
  141. package/dist/views/Login.d.ts.map +1 -1
  142. package/dist/views/Login.js +17 -7
  143. package/dist/views/Login.js.map +1 -1
  144. package/dist/views/MediaBrowser.js +16 -16
  145. package/dist/views/PageEditor.js +2 -2
  146. package/dist/views/Pages.js +10 -10
  147. package/dist/views/PostEditor.js +2 -2
  148. package/dist/views/Posts.js +4 -4
  149. package/dist/views/Redirects.js +4 -4
  150. package/dist/views/ResetPassword.js +2 -2
  151. package/dist/views/SEO.js +6 -6
  152. package/dist/views/ScriptTagEditor.js +4 -4
  153. package/dist/views/ScriptTags.js +2 -2
  154. package/dist/views/Settings.d.ts.map +1 -1
  155. package/dist/views/Settings.js +9 -8
  156. package/dist/views/Settings.js.map +1 -1
  157. package/dist/views/SetupWizard.js +2 -2
  158. package/dist/views/Users.js +4 -4
  159. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  160. package/dist/views/page-builder/AIGenerateDialog.js +10 -10
  161. package/dist/views/page-builder/BlockEditor.js +10 -10
  162. package/dist/views/page-builder/BlockPicker.js +4 -4
  163. package/dist/views/page-builder/BottomBar.js +1 -1
  164. package/dist/views/page-builder/BuilderToolbar.js +2 -2
  165. package/dist/views/page-builder/ContextPanel.js +2 -2
  166. package/dist/views/page-builder/DesignScore.js +9 -9
  167. package/dist/views/page-builder/NodeSettings.js +8 -8
  168. package/dist/views/page-builder/PageBuilder.js +3 -3
  169. package/dist/views/page-builder/PageSettings.js +1 -1
  170. package/dist/views/page-builder/PageTemplates.js +2 -2
  171. package/dist/views/page-builder/SEOPanel.js +13 -13
  172. package/dist/views/page-builder/SavedSections.js +5 -5
  173. package/dist/views/page-builder/TemplatePicker.js +2 -2
  174. package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
  175. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  176. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
  177. package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
  178. package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
  179. package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
  180. package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
  181. package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
  182. package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
  183. package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
  184. package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
  185. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
  186. package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
  187. package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
  188. package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
  189. package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
  190. package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
  191. package/package.json +6 -2
  192. package/src/AdminRoot.tsx +21 -11
  193. package/src/__tests__/layout/primitives.test.ts +37 -0
  194. package/src/__tests__/lib/cv.test.ts +74 -0
  195. package/src/assets/actuate-logo.tsx +72 -0
  196. package/src/components/Breadcrumbs.tsx +6 -6
  197. package/src/components/CommandPalette.tsx +34 -34
  198. package/src/components/ContentOverviewChart.tsx +3 -3
  199. package/src/components/ErrorBoundary.tsx +3 -3
  200. package/src/components/FocalPointPicker.tsx +4 -4
  201. package/src/components/FolderTree.tsx +38 -38
  202. package/src/components/LivePreview.tsx +16 -16
  203. package/src/components/LocaleSwitcher.tsx +7 -7
  204. package/src/components/MediaPickerModal.tsx +21 -21
  205. package/src/components/PresenceIndicator.tsx +2 -2
  206. package/src/components/SEOConfigPanel.tsx +582 -0
  207. package/src/components/SEOPanel.tsx +46 -46
  208. package/src/components/SEOPerformance.tsx +21 -21
  209. package/src/components/SchedulePublishDialog.tsx +241 -0
  210. package/src/components/SharePreviewLinkDialog.tsx +227 -0
  211. package/src/components/TipTapEditor.tsx +33 -33
  212. package/src/components/VersionHistory.tsx +16 -16
  213. package/src/components/ui/Badge.tsx +66 -14
  214. package/src/components/ui/Button.tsx +70 -33
  215. package/src/components/ui/Card.tsx +101 -0
  216. package/src/components/ui/DataTable.tsx +1 -1
  217. package/src/components/ui/Input.tsx +35 -0
  218. package/src/components/ui/SearchInput.tsx +4 -4
  219. package/src/components/ui/Select.tsx +56 -0
  220. package/src/components/ui/Toast.tsx +1 -1
  221. package/src/components/ui/index.ts +18 -4
  222. package/src/fields/BlockBuilderField.tsx +3 -3
  223. package/src/fields/DateField.tsx +1 -1
  224. package/src/fields/RelationshipField.tsx +10 -10
  225. package/src/fields/TextField.tsx +1 -1
  226. package/src/index.ts +32 -0
  227. package/src/layout/Header.tsx +28 -28
  228. package/src/layout/Layout.tsx +39 -46
  229. package/src/layout/Sidebar.tsx +37 -64
  230. package/src/layout/primitives/AdminShell.tsx +118 -0
  231. package/src/layout/primitives/Box.tsx +30 -0
  232. package/src/layout/primitives/Cluster.tsx +74 -0
  233. package/src/layout/primitives/Grid.tsx +120 -0
  234. package/src/layout/primitives/PageContainer.tsx +96 -0
  235. package/src/layout/primitives/Split.tsx +73 -0
  236. package/src/layout/primitives/Stack.tsx +67 -0
  237. package/src/layout/primitives/index.ts +36 -0
  238. package/src/layout/primitives/tokens.ts +76 -0
  239. package/src/lib/cv.ts +96 -0
  240. package/src/styles/build-input.css +1 -1
  241. package/src/views/ApiKeys.tsx +57 -57
  242. package/src/views/CollectionList.tsx +30 -30
  243. package/src/views/Dashboard.tsx +737 -186
  244. package/src/views/DocumentEdit.tsx +90 -10
  245. package/src/views/ForgotPassword.tsx +18 -18
  246. package/src/views/FormEditor.tsx +75 -75
  247. package/src/views/FormSubmissions.tsx +76 -76
  248. package/src/views/Forms.tsx +27 -27
  249. package/src/views/Login.tsx +65 -25
  250. package/src/views/MediaBrowser.tsx +127 -127
  251. package/src/views/PageEditor.tsx +25 -25
  252. package/src/views/Pages.tsx +59 -59
  253. package/src/views/PostEditor.tsx +37 -37
  254. package/src/views/Posts.tsx +48 -48
  255. package/src/views/Redirects.tsx +21 -21
  256. package/src/views/ResetPassword.tsx +28 -28
  257. package/src/views/SEO.tsx +144 -144
  258. package/src/views/ScriptTagEditor.tsx +24 -24
  259. package/src/views/ScriptTags.tsx +10 -10
  260. package/src/views/Settings.tsx +88 -80
  261. package/src/views/SetupWizard.tsx +28 -28
  262. package/src/views/Users.tsx +20 -20
  263. package/src/views/page-builder/AIBlockAssist.tsx +1 -1
  264. package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
  265. package/src/views/page-builder/BlockEditor.tsx +26 -26
  266. package/src/views/page-builder/BlockPicker.tsx +22 -22
  267. package/src/views/page-builder/BottomBar.tsx +8 -8
  268. package/src/views/page-builder/BuilderToolbar.tsx +17 -17
  269. package/src/views/page-builder/ContextPanel.tsx +3 -3
  270. package/src/views/page-builder/DesignScore.tsx +21 -21
  271. package/src/views/page-builder/NodeSettings.tsx +27 -27
  272. package/src/views/page-builder/PageBuilder.tsx +11 -11
  273. package/src/views/page-builder/PageSettings.tsx +4 -4
  274. package/src/views/page-builder/PageTemplates.tsx +18 -18
  275. package/src/views/page-builder/SEOPanel.tsx +53 -53
  276. package/src/views/page-builder/SavedSections.tsx +37 -37
  277. package/src/views/page-builder/TemplatePicker.tsx +17 -17
  278. package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
  279. package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
  280. package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
  281. package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
  282. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
  283. package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
  284. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
  285. package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
  286. package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
  287. package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
  288. package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
  289. package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
  290. package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
  291. package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
  292. package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
  293. package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
  294. package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
@@ -29,13 +29,13 @@ export function BlockEditor({ node, onUpdateBlock, onUpdateSettings, onRemoveNod
29
29
  }
30
30
  }, [confirmDelete, node.id, onRemoveNode]);
31
31
  if (!blockDef) {
32
- return (_jsx("div", { className: "p-4", children: _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Unknown block type: ", _jsx("code", { className: "text-xs", children: node.settings.blockType })] }) }));
32
+ return (_jsx("div", { className: "p-4", children: _jsxs("p", { className: "text-muted-foreground text-sm", children: ["Unknown block type: ", _jsx("code", { className: "text-xs", children: node.settings.blockType })] }) }));
33
33
  }
34
- return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "p-4 border-b border-border", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Star, { size: 16, className: "text-muted-foreground" }), _jsx("span", { className: "text-sm font-medium text-foreground flex-1", children: blockDef.label }), _jsx(AIBlockAssist, { block: node, onUpdateData: (data) => onUpdateBlock(node.id, data) })] }), blockDef.description && (_jsx("p", { className: "text-xs text-muted-foreground mt-1", children: blockDef.description }))] }), blockDef.variants.length > 1 && (_jsxs("div", { className: "p-4 border-b border-border", children: [_jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground mb-2", children: "Variant" }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: blockDef.variants.map((variant) => (_jsx("button", { type: "button", onClick: () => handleVariantChange(variant.name), className: `px-2 py-1.5 text-xs rounded-md border transition-colors ${node.settings.variant === variant.name
34
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "border-border border-b p-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Star, { size: 16, className: "text-muted-foreground" }), _jsx("span", { className: "text-foreground flex-1 text-sm font-medium", children: blockDef.label }), _jsx(AIBlockAssist, { block: node, onUpdateData: (data) => onUpdateBlock(node.id, data) })] }), blockDef.description && (_jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: blockDef.description }))] }), blockDef.variants.length > 1 && (_jsxs("div", { className: "border-border border-b p-4", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase", children: "Variant" }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: blockDef.variants.map((variant) => (_jsx("button", { type: "button", onClick: () => handleVariantChange(variant.name), className: `rounded-md border px-2 py-1.5 text-xs transition-colors ${node.settings.variant === variant.name
35
35
  ? 'bg-primary text-primary-foreground border-primary'
36
- : 'bg-background border-input text-foreground hover:bg-accent'}`, children: variant.label }, variant.name))) })] })), _jsxs("div", { className: "space-y-4 p-4 flex-1", children: [_jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground mb-2", children: "Fields" }), Object.entries(blockDef.fields).map(([fieldName, fieldDef]) => (_jsx(FieldRenderer, { name: fieldName, definition: fieldDef, value: node.data[fieldName], onChange: (value) => handleFieldChange(fieldName, value) }, fieldName)))] }), _jsxs("div", { className: "p-4 border-t border-border space-y-2", children: [_jsxs("button", { type: "button", onClick: () => onDuplicateNode(node.id), className: "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium bg-background border border-input rounded-md hover:bg-accent transition-colors", children: [_jsx(Copy, { size: 14 }), "Duplicate"] }), _jsxs("button", { type: "button", onClick: handleDelete, onBlur: () => setConfirmDelete(false), className: `w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-md transition-colors ${confirmDelete
36
+ : 'bg-background border-input text-foreground hover:bg-accent'}`, children: variant.label }, variant.name))) })] })), _jsxs("div", { className: "flex-1 space-y-4 p-4", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase", children: "Fields" }), Object.entries(blockDef.fields).map(([fieldName, fieldDef]) => (_jsx(FieldRenderer, { name: fieldName, definition: fieldDef, value: node.data[fieldName], onChange: (value) => handleFieldChange(fieldName, value) }, fieldName)))] }), _jsxs("div", { className: "border-border space-y-2 border-t p-4", children: [_jsxs("button", { type: "button", onClick: () => onDuplicateNode(node.id), className: "bg-background border-input hover:bg-accent flex w-full items-center justify-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors", children: [_jsx(Copy, { size: 14 }), "Duplicate"] }), _jsxs("button", { type: "button", onClick: handleDelete, onBlur: () => setConfirmDelete(false), className: `flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${confirmDelete
37
37
  ? 'bg-destructive text-destructive-foreground'
38
- : 'bg-background border border-destructive text-destructive hover:bg-destructive/10'}`, children: [_jsx(Trash2, { size: 14 }), confirmDelete ? 'Click again to confirm' : 'Delete'] })] })] }));
38
+ : 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'}`, children: [_jsx(Trash2, { size: 14 }), confirmDelete ? 'Click again to confirm' : 'Delete'] })] })] }));
39
39
  }
40
40
  function FieldRenderer({ name, definition, value, onChange }) {
41
41
  const label = definition.label || name;
@@ -43,13 +43,13 @@ function FieldRenderer({ name, definition, value, onChange }) {
43
43
  case 'text':
44
44
  return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "text", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: definition.admin?.placeholder, className: INPUT_CLASS })] }));
45
45
  case 'richText':
46
- return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("div", { className: "rounded-md border border-input overflow-hidden bg-background", children: _jsx(TipTapEditor, { content: value ?? '', onChange: (html) => onChange(html), placeholder: definition.admin?.placeholder }) })] }));
46
+ return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("div", { className: "border-input bg-background overflow-hidden rounded-md border", children: _jsx(TipTapEditor, { content: value ?? '', onChange: (html) => onChange(html), placeholder: definition.admin?.placeholder }) })] }));
47
47
  case 'url':
48
48
  return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "url", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: definition.admin?.placeholder ?? 'https://', className: INPUT_CLASS })] }));
49
49
  case 'number':
50
50
  return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "number", value: value ?? '', onChange: (e) => onChange(e.target.value ? Number(e.target.value) : undefined), min: definition.min, max: definition.max, step: definition.step, className: INPUT_CLASS })] }));
51
51
  case 'boolean':
52
- return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium text-foreground", children: label }), _jsx(SwitchPrimitive.Root, { checked: !!value, onCheckedChange: (checked) => onChange(checked), className: "w-9 h-5 bg-input rounded-full relative data-[state=checked]:bg-primary transition-colors", "aria-label": label, children: _jsx(SwitchPrimitive.Thumb, { className: "block h-3.5 w-3.5 rounded-full bg-background shadow-sm transition-transform translate-x-0.5 data-[state=checked]:translate-x-[18px]" }) })] }));
52
+ return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: label }), _jsx(SwitchPrimitive.Root, { checked: !!value, onCheckedChange: (checked) => onChange(checked), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": label, children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }));
53
53
  case 'media':
54
54
  return _jsx(MediaFieldRenderer, { label: label, value: value, onChange: onChange });
55
55
  case 'select':
@@ -73,7 +73,7 @@ function FieldRenderer({ name, definition, value, onChange }) {
73
73
  case 'email':
74
74
  return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "email", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: definition.admin?.placeholder ?? 'email@example.com', className: INPUT_CLASS })] }));
75
75
  case 'color':
76
- return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: value ?? '#000000', onChange: (e) => onChange(e.target.value), className: "h-9 w-9 rounded-md border border-input cursor-pointer" }), _jsx("input", { type: "text", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: "#000000", className: `${INPUT_CLASS} flex-1` })] })] }));
76
+ return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: value ?? '#000000', onChange: (e) => onChange(e.target.value), className: "border-input h-9 w-9 cursor-pointer rounded-md border" }), _jsx("input", { type: "text", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: "#000000", className: `${INPUT_CLASS} flex-1` })] })] }));
77
77
  default:
78
78
  return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "text", value: String(value ?? ''), onChange: (e) => onChange(e.target.value), className: INPUT_CLASS })] }));
79
79
  }
@@ -90,7 +90,7 @@ function MediaFieldRenderer({ label, value, onChange }) {
90
90
  : value && typeof value === 'object' && 'url' in value
91
91
  ? String(value.url)
92
92
  : '';
93
- return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: url, onChange: (e) => onChange(e.target.value), placeholder: "https://...", className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => setOpen(true), className: "px-3 py-2 text-xs font-medium bg-accent text-foreground border border-input rounded-md hover:bg-accent/80 transition-colors", children: "Browse" })] }), url && /\.(png|jpe?g|gif|webp|avif|svg)(\?|$)/i.test(url) && (_jsx("div", { className: "mt-2 rounded-md border border-border overflow-hidden bg-muted", children: _jsx("img", { src: url, alt: "", className: "w-full h-32 object-contain bg-checkered" }) })), _jsx(MediaPickerModal, { open: open, onClose: () => setOpen(false), onSelect: (selectedUrl) => {
93
+ return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: url, onChange: (e) => onChange(e.target.value), placeholder: "https://...", className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => setOpen(true), className: "bg-accent text-foreground border-input hover:bg-accent/80 rounded-md border px-3 py-2 text-xs font-medium transition-colors", children: "Browse" })] }), url && /\.(png|jpe?g|gif|webp|avif|svg)(\?|$)/i.test(url) && (_jsx("div", { className: "border-border bg-muted mt-2 overflow-hidden rounded-md border", children: _jsx("img", { src: url, alt: "", className: "bg-checkered h-32 w-full object-contain" }) })), _jsx(MediaPickerModal, { open: open, onClose: () => setOpen(false), onSelect: (selectedUrl) => {
94
94
  onChange(selectedUrl);
95
95
  setOpen(false);
96
96
  } })] }));
@@ -131,7 +131,7 @@ function JsonFieldRenderer({ label, value, onChange }) {
131
131
  setError(err instanceof Error ? err.message : 'Invalid JSON');
132
132
  }
133
133
  };
134
- return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("textarea", { value: draft, onChange: (e) => handleChange(e.target.value), rows: 6, spellCheck: false, className: `${INPUT_CLASS} font-mono text-xs resize-y` }), error && (_jsx("p", { className: "mt-1 text-xs text-destructive", role: "alert", children: error }))] }));
134
+ return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("textarea", { value: draft, onChange: (e) => handleChange(e.target.value), rows: 6, spellCheck: false, className: `${INPUT_CLASS} resize-y font-mono text-xs` }), error && (_jsx("p", { className: "text-destructive mt-1 text-xs", role: "alert", children: error }))] }));
135
135
  }
136
136
  /**
137
137
  * Lightweight array editor — supports homogenous arrays of strings or
@@ -153,6 +153,6 @@ function ArrayFieldRenderer({ label, value, onChange }) {
153
153
  };
154
154
  const addItem = () => onChange([...items, '']);
155
155
  const removeItem = (idx) => onChange(items.filter((_, i) => i !== idx));
156
- return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "space-y-2", children: [items.map((item, idx) => (_jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: typeof item === 'string' ? item : '', onChange: (e) => updateItem(idx, e.target.value), className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => removeItem(idx), "aria-label": `Remove item ${idx + 1}`, className: "px-2 py-2 text-xs text-destructive border border-input rounded-md hover:bg-destructive/10 transition-colors", children: _jsx(Trash2, { size: 14 }) })] }, idx))), _jsx("button", { type: "button", onClick: addItem, className: "w-full px-3 py-2 text-xs font-medium bg-accent text-foreground border border-input rounded-md hover:bg-accent/80 transition-colors", children: "+ Add item" })] })] }));
156
+ return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "space-y-2", children: [items.map((item, idx) => (_jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: typeof item === 'string' ? item : '', onChange: (e) => updateItem(idx, e.target.value), className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => removeItem(idx), "aria-label": `Remove item ${idx + 1}`, className: "text-destructive border-input hover:bg-destructive/10 rounded-md border px-2 py-2 text-xs transition-colors", children: _jsx(Trash2, { size: 14 }) })] }, idx))), _jsx("button", { type: "button", onClick: addItem, className: "bg-accent text-foreground border-input hover:bg-accent/80 w-full rounded-md border px-3 py-2 text-xs font-medium transition-colors", children: "+ Add item" })] })] }));
157
157
  }
158
158
  //# sourceMappingURL=BlockEditor.js.map
@@ -83,20 +83,20 @@ export function BlockPicker({ open, onClose, onSelect }) {
83
83
  handleBack();
84
84
  }
85
85
  }
86
- return (_jsx(Dialog.Root, { open: open, onOpenChange: (isOpen) => !isOpen && onClose(), children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 bg-black/50 z-50 motion-safe:animate-in motion-safe:fade-in-0" }), _jsx(Dialog.Content, { className: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-card rounded-xl shadow-2xl border border-border z-50 w-full max-w-2xl max-h-[80vh] overflow-hidden flex flex-col", "aria-describedby": undefined, onEscapeKeyDown: () => {
86
+ return (_jsx(Dialog.Root, { open: open, onOpenChange: (isOpen) => !isOpen && onClose(), children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "motion-safe:animate-in motion-safe:fade-in-0 fixed inset-0 z-50 bg-black/50" }), _jsx(Dialog.Content, { className: "bg-card border-border fixed top-1/2 left-1/2 z-50 flex max-h-[80vh] w-full max-w-2xl -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border shadow-2xl", "aria-describedby": undefined, onEscapeKeyDown: () => {
87
87
  if (selectedBlock) {
88
88
  handleBack();
89
89
  }
90
90
  }, children: selectedBlock ? (_jsx(VariantView, { block: selectedBlock, variantListRef: variantListRef, onBack: handleBack, onVariantClick: handleVariantClick, onKeyDown: handleKeyDownOnVariants })) : (_jsx(BlockTypeGrid, { search: search, filteredBlocks: filteredBlocks, searchInputRef: searchInputRef, onSearchChange: setSearch, onBlockClick: handleBlockClick, onClose: onClose, onKeyDown: handleKeyDownOnGrid })) })] }) }));
91
91
  }
92
92
  function BlockTypeGrid({ search, filteredBlocks, searchInputRef, onSearchChange, onBlockClick, onClose, onKeyDown, }) {
93
- return (_jsxs("div", { className: "flex flex-col h-full", onKeyDown: onKeyDown, children: [_jsxs("div", { className: "flex items-center justify-between gap-3 px-5 pt-5 pb-3", children: [_jsx(Dialog.Title, { className: "text-lg font-medium text-foreground", children: "Add Block" }), _jsx(Dialog.Close, { asChild: true, children: _jsx("button", { type: "button", className: "p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent transition-colors", "aria-label": "Close", children: _jsx(X, { size: 18 }) }) })] }), _jsx("div", { className: "px-5 pb-3", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none", size: 16 }), _jsx("input", { ref: searchInputRef, type: "text", placeholder: "Search blocks...", value: search, onChange: (e) => onSearchChange(e.target.value), className: "w-full pl-9 pr-3 py-2 text-sm bg-background border border-input rounded-md focus:outline-none focus:ring-2 focus:ring-ring", "aria-label": "Search block types" })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-5", children: filteredBlocks.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx(Search, { size: 24, className: "text-muted-foreground mb-2" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["No blocks match \u201C", search, "\u201D"] })] })) : (_jsx("div", { className: "grid grid-cols-2 gap-3", role: "list", "aria-label": "Available block types", children: filteredBlocks.map((block) => {
93
+ return (_jsxs("div", { className: "flex h-full flex-col", onKeyDown: onKeyDown, children: [_jsxs("div", { className: "flex items-center justify-between gap-3 px-5 pt-5 pb-3", children: [_jsx(Dialog.Title, { className: "text-foreground text-lg font-medium", children: "Add Block" }), _jsx(Dialog.Close, { asChild: true, children: _jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground hover:bg-accent rounded-md p-1.5 transition-colors", "aria-label": "Close", children: _jsx(X, { size: 18 }) }) })] }), _jsx("div", { className: "px-5 pb-3", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground pointer-events-none absolute top-1/2 left-3 -translate-y-1/2", size: 16 }), _jsx("input", { ref: searchInputRef, type: "text", placeholder: "Search blocks...", value: search, onChange: (e) => onSearchChange(e.target.value), className: "bg-background border-input focus:ring-ring w-full rounded-md border py-2 pr-3 pl-9 text-sm focus:ring-2 focus:outline-none", "aria-label": "Search block types" })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-5", children: filteredBlocks.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx(Search, { size: 24, className: "text-muted-foreground mb-2" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: ["No blocks match \u201C", search, "\u201D"] })] })) : (_jsx("div", { className: "grid grid-cols-2 gap-3", role: "list", "aria-label": "Available block types", children: filteredBlocks.map((block) => {
94
94
  const Icon = resolveIcon(block.icon);
95
- return (_jsxs("button", { type: "button", role: "listitem", onClick: () => onBlockClick(block), className: "p-4 border border-border rounded-lg hover:border-primary cursor-pointer transition-colors bg-card text-left flex items-start gap-3 group focus:outline-none focus:ring-2 focus:ring-ring", children: [_jsx("div", { className: "shrink-0 w-9 h-9 rounded-md bg-accent flex items-center justify-center text-foreground group-hover:bg-primary/10 group-hover:text-primary transition-colors", children: _jsx(Icon, { size: 18 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground truncate", children: block.label }), block.description && (_jsx("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-2", children: block.description }))] })] }, block.type));
95
+ return (_jsxs("button", { type: "button", role: "listitem", onClick: () => onBlockClick(block), className: "border-border hover:border-primary bg-card group focus:ring-ring flex cursor-pointer items-start gap-3 rounded-lg border p-4 text-left transition-colors focus:ring-2 focus:outline-none", children: [_jsx("div", { className: "bg-accent text-foreground group-hover:bg-primary/10 group-hover:text-primary flex h-9 w-9 shrink-0 items-center justify-center rounded-md transition-colors", children: _jsx(Icon, { size: 18 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: block.label }), block.description && (_jsx("p", { className: "text-muted-foreground mt-0.5 line-clamp-2 text-xs", children: block.description }))] })] }, block.type));
96
96
  }) })) })] }));
97
97
  }
98
98
  function VariantView({ block, variantListRef, onBack, onVariantClick, onKeyDown, }) {
99
99
  const Icon = resolveIcon(block.icon);
100
- return (_jsxs("div", { className: "flex flex-col h-full", onKeyDown: onKeyDown, children: [_jsxs("div", { className: "flex items-center gap-3 px-5 pt-5 pb-3", children: [_jsx("button", { type: "button", onClick: onBack, className: "p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent transition-colors", "aria-label": "Back to block types", children: _jsx(ArrowLeft, { size: 18 }) }), _jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx(Icon, { size: 18, className: "text-foreground shrink-0" }), _jsx("h2", { className: "text-lg font-medium text-foreground truncate", children: block.label })] })] }), block.description && (_jsx("p", { className: "text-sm text-muted-foreground px-5 pb-3", children: block.description })), _jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-5", ref: variantListRef, children: _jsx("div", { className: "space-y-2", role: "list", "aria-label": `${block.label} variants`, children: block.variants.map((variant, index) => (_jsx("button", { type: "button", role: "listitem", "data-variant": variant.name, onClick: () => onVariantClick(variant), className: "w-full p-4 border border-border rounded-lg hover:border-primary cursor-pointer transition-colors bg-card text-left flex items-center gap-3 group focus:outline-none focus:ring-2 focus:ring-ring", children: _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: variant.label }), index === 0 && (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-primary bg-primary/10 px-1.5 py-0.5 rounded", children: [_jsx(Check, { size: 10 }), "Default"] }))] }), _jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: variant.description })] }) }, variant.name))) }) })] }));
100
+ return (_jsxs("div", { className: "flex h-full flex-col", onKeyDown: onKeyDown, children: [_jsxs("div", { className: "flex items-center gap-3 px-5 pt-5 pb-3", children: [_jsx("button", { type: "button", onClick: onBack, className: "text-muted-foreground hover:text-foreground hover:bg-accent rounded-md p-1.5 transition-colors", "aria-label": "Back to block types", children: _jsx(ArrowLeft, { size: 18 }) }), _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Icon, { size: 18, className: "text-foreground shrink-0" }), _jsx("h2", { className: "text-foreground truncate text-lg font-medium", children: block.label })] })] }), block.description && (_jsx("p", { className: "text-muted-foreground px-5 pb-3 text-sm", children: block.description })), _jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-5", ref: variantListRef, children: _jsx("div", { className: "space-y-2", role: "list", "aria-label": `${block.label} variants`, children: block.variants.map((variant, index) => (_jsx("button", { type: "button", role: "listitem", "data-variant": variant.name, onClick: () => onVariantClick(variant), className: "border-border hover:border-primary bg-card group focus:ring-ring flex w-full cursor-pointer items-center gap-3 rounded-lg border p-4 text-left transition-colors focus:ring-2 focus:outline-none", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: variant.label }), index === 0 && (_jsxs("span", { className: "text-primary bg-primary/10 inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs", children: [_jsx(Check, { size: 10 }), "Default"] }))] }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: variant.description })] }) }, variant.name))) }) })] }));
101
101
  }
102
102
  //# sourceMappingURL=BlockPicker.js.map
@@ -8,6 +8,6 @@ const DEVICE_LABELS = {
8
8
  mobile: '375px',
9
9
  };
10
10
  export function BottomBar({ deviceMode, showGridOverlay, onAddSection, onToggleGrid, }) {
11
- return (_jsxs("div", { className: "h-10 bg-card border-t border-border flex items-center px-4 gap-4 shrink-0", role: "toolbar", "aria-label": "Builder actions", children: [_jsxs("button", { onClick: onAddSection, className: "flex items-center gap-1.5 px-3 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors", "aria-label": "Add a new section", children: [_jsx(Plus, { size: 14 }), _jsx("span", { children: "Add Section" })] }), _jsx("div", { className: "w-px h-5 bg-border" }), _jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [_jsx(Grid3X3, { size: 14, className: "text-muted-foreground" }), _jsx(Switch.Root, { checked: showGridOverlay, onCheckedChange: onToggleGrid, className: "w-8 h-[18px] bg-input-background rounded-full relative data-[state=checked]:bg-primary transition-colors", "aria-label": "Toggle grid overlay", children: _jsx(Switch.Thumb, { className: "block w-3.5 h-3.5 bg-background rounded-full shadow-sm transition-transform translate-x-0.5 data-[state=checked]:translate-x-[14px]" }) }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Grid" })] }), _jsx("div", { className: "flex-1" }), _jsx("span", { className: "text-xs text-muted-foreground tabular-nums", children: DEVICE_LABELS[deviceMode] })] }));
11
+ return (_jsxs("div", { className: "bg-card border-border flex h-10 shrink-0 items-center gap-4 border-t px-4", role: "toolbar", "aria-label": "Builder actions", children: [_jsxs("button", { onClick: onAddSection, className: "text-muted-foreground hover:text-foreground flex items-center gap-1.5 px-3 py-2 text-sm transition-colors", "aria-label": "Add a new section", children: [_jsx(Plus, { size: 14 }), _jsx("span", { children: "Add Section" })] }), _jsx("div", { className: "bg-border h-5 w-px" }), _jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx(Grid3X3, { size: 14, className: "text-muted-foreground" }), _jsx(Switch.Root, { checked: showGridOverlay, onCheckedChange: onToggleGrid, className: "bg-input-background data-[state=checked]:bg-primary relative h-[18px] w-8 rounded-full transition-colors", "aria-label": "Toggle grid overlay", children: _jsx(Switch.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" }) }), _jsx("span", { className: "text-muted-foreground text-xs", children: "Grid" })] }), _jsx("div", { className: "flex-1" }), _jsx("span", { className: "text-muted-foreground text-xs tabular-nums", children: DEVICE_LABELS[deviceMode] })] }));
12
12
  }
13
13
  //# sourceMappingURL=BottomBar.js.map
@@ -8,10 +8,10 @@ const STATUS_STYLES = {
8
8
  };
9
9
  export function BuilderToolbar({ collectionSlug, pageSettings, status, dirty, saving, canUndo, canRedo, deviceMode, onNavigate, onTitleChange, onUndo, onRedo, onDeviceMode, onSave, onPublish, onOpenAI, }) {
10
10
  const collectionLabel = collectionSlug.charAt(0).toUpperCase() + collectionSlug.slice(1);
11
- return (_jsxs("div", { className: "h-14 bg-card border-b border-border flex items-center px-4 gap-3 shrink-0", role: "toolbar", "aria-label": "Page builder toolbar", children: [_jsxs("button", { onClick: () => onNavigate(`/collections/${collectionSlug}`), className: "flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors", "aria-label": `Back to ${collectionLabel}`, children: [_jsx(ChevronLeft, { size: 16 }), _jsx("span", { className: "hidden sm:inline", children: collectionLabel })] }), _jsx("div", { className: "w-px h-6 bg-border" }), _jsx("input", { type: "text", value: pageSettings.title, onChange: (e) => onTitleChange(e.target.value), placeholder: "Untitled Page", className: "flex-1 min-w-0 text-sm font-medium text-foreground bg-transparent border-none outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm placeholder:text-muted-foreground", "aria-label": "Page title" }), _jsx("span", { className: `text-xs font-medium px-2 py-0.5 rounded-md whitespace-nowrap ${STATUS_STYLES[status] ?? STATUS_STYLES.DRAFT}`, children: status }), dirty && !saving && (_jsx("span", { className: "w-2 h-2 rounded-full bg-destructive shrink-0", title: "Unsaved changes", "aria-label": "Unsaved changes" })), _jsx("div", { className: "w-px h-6 bg-border" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: onUndo, disabled: !canUndo, className: "p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-30 disabled:pointer-events-none transition-colors", "aria-label": "Undo", children: _jsx(Undo2, { size: 16 }) }), _jsx("button", { onClick: onRedo, disabled: !canRedo, className: "p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-30 disabled:pointer-events-none transition-colors", "aria-label": "Redo", children: _jsx(Redo2, { size: 16 }) })] }), _jsx("div", { className: "w-px h-6 bg-border" }), _jsxs("div", { className: "flex items-center gap-0.5 bg-muted rounded-md p-0.5", children: [_jsx(DeviceButton, { active: deviceMode === 'desktop', onClick: () => onDeviceMode('desktop'), label: "Desktop view", children: _jsx(Monitor, { size: 16 }) }), _jsx(DeviceButton, { active: deviceMode === 'tablet', onClick: () => onDeviceMode('tablet'), label: "Tablet view", children: _jsx(Tablet, { size: 16 }) }), _jsx(DeviceButton, { active: deviceMode === 'mobile', onClick: () => onDeviceMode('mobile'), label: "Mobile view", children: _jsx(Smartphone, { size: 16 }) })] }), _jsx("div", { className: "w-px h-6 bg-border" }), onOpenAI && (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: onOpenAI, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-medium text-primary bg-primary/10 rounded-md hover:bg-primary/20 transition-colors", "aria-label": "Generate page with AI", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: "hidden sm:inline", children: "AI" })] }), _jsx("div", { className: "w-px h-6 bg-border" })] })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { onClick: onSave, disabled: saving || !dirty, className: "bg-muted text-muted-foreground rounded-md px-3 py-1.5 text-sm font-medium hover:bg-muted/80 disabled:opacity-50 disabled:pointer-events-none transition-colors flex items-center gap-1.5", children: [saving && _jsx(Loader2, { size: 14, className: "animate-spin" }), saving ? 'Saving...' : 'Save'] }), _jsx("button", { onClick: onPublish, disabled: saving, className: "bg-primary text-primary-foreground rounded-md px-3 py-1.5 text-sm font-medium hover:bg-primary/90 disabled:opacity-50 disabled:pointer-events-none transition-colors", children: "Publish" })] })] }));
11
+ return (_jsxs("div", { className: "bg-card border-border flex h-14 shrink-0 items-center gap-3 border-b px-4", role: "toolbar", "aria-label": "Page builder toolbar", children: [_jsxs("button", { onClick: () => onNavigate(`/collections/${collectionSlug}`), className: "text-muted-foreground hover:text-foreground flex items-center gap-1 text-sm transition-colors", "aria-label": `Back to ${collectionLabel}`, children: [_jsx(ChevronLeft, { size: 16 }), _jsx("span", { className: "hidden sm:inline", children: collectionLabel })] }), _jsx("div", { className: "bg-border h-6 w-px" }), _jsx("input", { type: "text", value: pageSettings.title, onChange: (e) => onTitleChange(e.target.value), placeholder: "Untitled Page", className: "text-foreground focus-visible:ring-ring placeholder:text-muted-foreground min-w-0 flex-1 rounded-sm border-none bg-transparent text-sm font-medium outline-none focus-visible:ring-2 focus-visible:ring-offset-2", "aria-label": "Page title" }), _jsx("span", { className: `rounded-md px-2 py-0.5 text-xs font-medium whitespace-nowrap ${STATUS_STYLES[status] ?? STATUS_STYLES.DRAFT}`, children: status }), dirty && !saving && (_jsx("span", { className: "bg-destructive h-2 w-2 shrink-0 rounded-full", title: "Unsaved changes", "aria-label": "Unsaved changes" })), _jsx("div", { className: "bg-border h-6 w-px" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: onUndo, disabled: !canUndo, className: "text-muted-foreground hover:text-foreground hover:bg-muted rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-30", "aria-label": "Undo", children: _jsx(Undo2, { size: 16 }) }), _jsx("button", { onClick: onRedo, disabled: !canRedo, className: "text-muted-foreground hover:text-foreground hover:bg-muted rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-30", "aria-label": "Redo", children: _jsx(Redo2, { size: 16 }) })] }), _jsx("div", { className: "bg-border h-6 w-px" }), _jsxs("div", { className: "bg-muted flex items-center gap-0.5 rounded-md p-0.5", children: [_jsx(DeviceButton, { active: deviceMode === 'desktop', onClick: () => onDeviceMode('desktop'), label: "Desktop view", children: _jsx(Monitor, { size: 16 }) }), _jsx(DeviceButton, { active: deviceMode === 'tablet', onClick: () => onDeviceMode('tablet'), label: "Tablet view", children: _jsx(Tablet, { size: 16 }) }), _jsx(DeviceButton, { active: deviceMode === 'mobile', onClick: () => onDeviceMode('mobile'), label: "Mobile view", children: _jsx(Smartphone, { size: 16 }) })] }), _jsx("div", { className: "bg-border h-6 w-px" }), onOpenAI && (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: onOpenAI, className: "text-primary bg-primary/10 hover:bg-primary/20 flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-sm font-medium transition-colors", "aria-label": "Generate page with AI", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: "hidden sm:inline", children: "AI" })] }), _jsx("div", { className: "bg-border h-6 w-px" })] })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { onClick: onSave, disabled: saving || !dirty, className: "bg-muted text-muted-foreground hover:bg-muted/80 flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50", children: [saving && _jsx(Loader2, { size: 14, className: "animate-spin" }), saving ? 'Saving...' : 'Save'] }), _jsx("button", { onClick: onPublish, disabled: saving, className: "bg-primary text-primary-foreground hover:bg-primary/90 rounded-md px-3 py-1.5 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50", children: "Publish" })] })] }));
12
12
  }
13
13
  function DeviceButton({ active, onClick, label, children, }) {
14
- return (_jsx("button", { onClick: onClick, className: `p-1.5 rounded-md transition-colors ${active
14
+ return (_jsx("button", { onClick: onClick, className: `rounded-md p-1.5 transition-colors ${active
15
15
  ? 'bg-background text-foreground shadow-sm'
16
16
  : 'text-muted-foreground hover:text-foreground'}`, "aria-label": label, "aria-pressed": active, children: children }));
17
17
  }
@@ -32,9 +32,9 @@ export function ContextPanel({ activeTab, onTabChange, selectedNode, tree, pageS
32
32
  return 'node';
33
33
  return 'page';
34
34
  }, [activeTab, availableTabs, selectedNode]);
35
- return (_jsx("div", { className: "w-full h-full bg-card overflow-y-auto", children: _jsxs(Tabs.Root, { value: effectiveTab, onValueChange: (value) => onTabChange(value), children: [_jsx(Tabs.List, { className: "flex border-b border-border bg-muted/30", children: availableTabs.map((tab) => {
35
+ return (_jsx("div", { className: "bg-card h-full w-full overflow-y-auto", children: _jsxs(Tabs.Root, { value: effectiveTab, onValueChange: (value) => onTabChange(value), children: [_jsx(Tabs.List, { className: "border-border bg-muted/30 flex border-b", children: availableTabs.map((tab) => {
36
36
  const Icon = tab.icon;
37
- return (_jsxs(Tabs.Trigger, { value: tab.value, className: "flex-1 flex items-center justify-center gap-1.5 px-2 py-2.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground data-[state=active]:text-foreground data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:bg-background", children: [_jsx(Icon, { size: 14 }), _jsx("span", { children: tab.label })] }, tab.value));
37
+ return (_jsxs(Tabs.Trigger, { value: tab.value, className: "text-muted-foreground hover:text-foreground data-[state=active]:text-foreground data-[state=active]:border-primary data-[state=active]:bg-background flex flex-1 items-center justify-center gap-1.5 px-2 py-2.5 text-xs font-medium transition-colors data-[state=active]:border-b-2", children: [_jsx(Icon, { size: 14 }), _jsx("span", { children: tab.label })] }, tab.value));
38
38
  }) }), _jsx(Tabs.Content, { value: "block", children: selectedNode?.type === 'block' && (_jsx(BlockEditor, { node: selectedNode, onUpdateBlock: onUpdateBlock, onUpdateSettings: onUpdateSettings, onRemoveNode: onRemoveNode, onDuplicateNode: onDuplicateNode, config: config })) }), _jsx(Tabs.Content, { value: "node", children: selectedNode &&
39
39
  selectedNode.type !== 'block' &&
40
40
  selectedNode.type !== 'page' &&
@@ -38,11 +38,11 @@ function getRingStrokeColor(score) {
38
38
  function StatusIcon({ status }) {
39
39
  switch (status) {
40
40
  case 'good':
41
- return _jsx(CheckCircle2, { size: 14, className: "text-green-500 shrink-0" });
41
+ return _jsx(CheckCircle2, { size: 14, className: "shrink-0 text-green-500" });
42
42
  case 'warning':
43
- return _jsx(AlertCircle, { size: 14, className: "text-amber-500 shrink-0" });
43
+ return _jsx(AlertCircle, { size: 14, className: "shrink-0 text-amber-500" });
44
44
  case 'error':
45
- return _jsx(XCircle, { size: 14, className: "text-red-500 shrink-0" });
45
+ return _jsx(XCircle, { size: 14, className: "shrink-0 text-red-500" });
46
46
  }
47
47
  }
48
48
  function SeverityBadge({ severity }) {
@@ -51,7 +51,7 @@ function SeverityBadge({ severity }) {
51
51
  suggestion: 'bg-amber-100 text-amber-700',
52
52
  info: 'bg-blue-100 text-blue-700',
53
53
  };
54
- return (_jsx("span", { className: `inline-block px-1.5 py-0.5 rounded text-xs font-medium ${classes[severity]}`, children: severity }));
54
+ return (_jsx("span", { className: `inline-block rounded px-1.5 py-0.5 text-xs font-medium ${classes[severity]}`, children: severity }));
55
55
  }
56
56
  function ScoreRing({ score }) {
57
57
  const radius = 32;
@@ -60,11 +60,11 @@ function ScoreRing({ score }) {
60
60
  const progress = Math.min(score, 100) / 100;
61
61
  const dashOffset = circumference * (1 - progress);
62
62
  const size = (radius + strokeWidth) * 2;
63
- return (_jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsxs("div", { className: "relative", children: [_jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: "var(--border)", strokeWidth: strokeWidth }), _jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: getRingStrokeColor(score), strokeWidth: strokeWidth, strokeDasharray: circumference, strokeDashoffset: dashOffset, strokeLinecap: "round", className: "transition-all duration-700 ease-out" })] }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: `text-lg font-medium ${getScoreColor(score, 100)}`, children: score }) })] }), _jsx("span", { className: "text-xs text-muted-foreground", children: getScoreLabel(score) })] }));
63
+ return (_jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsxs("div", { className: "relative", children: [_jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: "var(--border)", strokeWidth: strokeWidth }), _jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: getRingStrokeColor(score), strokeWidth: strokeWidth, strokeDasharray: circumference, strokeDashoffset: dashOffset, strokeLinecap: "round", className: "transition-all duration-700 ease-out" })] }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: `text-lg font-medium ${getScoreColor(score, 100)}`, children: score }) })] }), _jsx("span", { className: "text-muted-foreground text-xs", children: getScoreLabel(score) })] }));
64
64
  }
65
65
  function CategoryRow({ category, expanded, onToggle, }) {
66
66
  const percentage = category.maxScore > 0 ? (category.score / category.maxScore) * 100 : 0;
67
- return (_jsxs("div", { className: "border-b border-border last:border-b-0", children: [_jsxs("button", { type: "button", className: "w-full text-left px-4 py-3 flex flex-col gap-2 hover:bg-muted/50 transition-colors", onClick: onToggle, "aria-expanded": expanded, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: category.label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { className: "text-xs text-muted-foreground", children: [category.score, "/", category.maxScore] }), expanded ? (_jsx(ChevronUp, { size: 14, className: "text-muted-foreground" })) : (_jsx(ChevronDown, { size: 14, className: "text-muted-foreground" }))] })] }), _jsx("div", { className: "w-full h-1.5 rounded-full bg-muted overflow-hidden", children: _jsx("div", { className: `h-full rounded-full transition-all duration-500 ease-out ${getBarColor(category.score, category.maxScore)}`, style: { width: `${percentage}%` } }) })] }), expanded && category.checks.length > 0 && (_jsx("div", { className: "px-4 pb-3 flex flex-col gap-2", children: category.checks.map((check) => (_jsxs("div", { className: "flex items-start gap-2 pl-1", children: [_jsx(StatusIcon, { status: check.status }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: check.label }), _jsx("span", { className: "text-xs text-muted-foreground", children: check.detail })] })] }, check.id))) }))] }));
67
+ return (_jsxs("div", { className: "border-border border-b last:border-b-0", children: [_jsxs("button", { type: "button", className: "hover:bg-muted/50 flex w-full flex-col gap-2 px-4 py-3 text-left transition-colors", onClick: onToggle, "aria-expanded": expanded, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-foreground text-xs font-medium", children: category.label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { className: "text-muted-foreground text-xs", children: [category.score, "/", category.maxScore] }), expanded ? (_jsx(ChevronUp, { size: 14, className: "text-muted-foreground" })) : (_jsx(ChevronDown, { size: 14, className: "text-muted-foreground" }))] })] }), _jsx("div", { className: "bg-muted h-1.5 w-full overflow-hidden rounded-full", children: _jsx("div", { className: `h-full rounded-full transition-all duration-500 ease-out ${getBarColor(category.score, category.maxScore)}`, style: { width: `${percentage}%` } }) })] }), expanded && category.checks.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 px-4 pb-3", children: category.checks.map((check) => (_jsxs("div", { className: "flex items-start gap-2 pl-1", children: [_jsx(StatusIcon, { status: check.status }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-foreground text-xs font-medium", children: check.label }), _jsx("span", { className: "text-muted-foreground text-xs", children: check.detail })] })] }, check.id))) }))] }));
68
68
  }
69
69
  function SuggestionsList({ suggestions }) {
70
70
  const sorted = useMemo(() => {
@@ -77,7 +77,7 @@ function SuggestionsList({ suggestions }) {
77
77
  }, [suggestions]);
78
78
  if (sorted.length === 0)
79
79
  return null;
80
- return (_jsxs("div", { className: "px-4 py-3 border-t border-border", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(Lightbulb, { size: 14, className: "text-muted-foreground" }), _jsx("span", { className: "text-xs font-medium text-foreground", children: "Suggestions" })] }), _jsx("div", { className: "flex flex-col gap-2.5", children: sorted.map((suggestion) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(SeverityBadge, { severity: suggestion.severity }), _jsx("span", { className: "text-xs text-muted-foreground leading-relaxed", children: suggestion.message })] }, suggestion.id))) })] }));
80
+ return (_jsxs("div", { className: "border-border border-t px-4 py-3", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(Lightbulb, { size: 14, className: "text-muted-foreground" }), _jsx("span", { className: "text-foreground text-xs font-medium", children: "Suggestions" })] }), _jsx("div", { className: "flex flex-col gap-2.5", children: sorted.map((suggestion) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(SeverityBadge, { severity: suggestion.severity }), _jsx("span", { className: "text-muted-foreground text-xs leading-relaxed", children: suggestion.message })] }, suggestion.id))) })] }));
81
81
  }
82
82
  export function DesignScorePanel({ tree }) {
83
83
  const analysis = useMemo(() => analyzeDesign(tree), [tree]);
@@ -86,8 +86,8 @@ export function DesignScorePanel({ tree }) {
86
86
  setExpandedCategories((prev) => prev.includes(name) ? prev.filter((n) => n !== name) : [...prev, name]);
87
87
  };
88
88
  if (!tree.children || tree.children.length === 0) {
89
- return (_jsxs("div", { className: "p-6 flex flex-col items-center justify-center text-center min-h-[200px]", children: [_jsx(Palette, { size: 32, className: "text-muted-foreground mb-3" }), _jsx("p", { className: "text-sm font-medium text-foreground mb-1", children: "Design Score" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Add sections to your page to see the design analysis" })] }));
89
+ return (_jsxs("div", { className: "flex min-h-[200px] flex-col items-center justify-center p-6 text-center", children: [_jsx(Palette, { size: 32, className: "text-muted-foreground mb-3" }), _jsx("p", { className: "text-foreground mb-1 text-sm font-medium", children: "Design Score" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Add sections to your page to see the design analysis" })] }));
90
90
  }
91
- return (_jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "flex flex-col items-center py-5 border-b border-border", children: _jsx(ScoreRing, { score: analysis.score }) }), _jsx("div", { className: "flex flex-col", children: analysis.categories.map((category) => (_jsx(CategoryRow, { category: category, expanded: expandedCategories.includes(category.name), onToggle: () => toggleCategory(category.name) }, category.name))) }), _jsx(SuggestionsList, { suggestions: analysis.suggestions })] }));
91
+ return (_jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "border-border flex flex-col items-center border-b py-5", children: _jsx(ScoreRing, { score: analysis.score }) }), _jsx("div", { className: "flex flex-col", children: analysis.categories.map((category) => (_jsx(CategoryRow, { category: category, expanded: expandedCategories.includes(category.name), onToggle: () => toggleCategory(category.name) }, category.name))) }), _jsx(SuggestionsList, { suggestions: analysis.suggestions })] }));
92
92
  }
93
93
  //# sourceMappingURL=DesignScore.js.map
@@ -36,19 +36,19 @@ export function NodeSettings({ node, onUpdateSettings, onRemoveNode, onDuplicate
36
36
  : node.type === 'row'
37
37
  ? 'Row'
38
38
  : 'Column';
39
- return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsx("div", { className: "p-4 border-b border-border", children: _jsxs("p", { className: "text-sm font-medium text-foreground", children: [nodeLabel, " Settings"] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsxs("div", { className: "space-y-4 p-4", children: [node.type === 'section' && (_jsx(SectionFields, { node: node, updateSetting: updateSetting, onAddRow: onAddRow })), node.type === 'container' && (_jsx(ContainerFields, { node: node, updateSetting: updateSetting })), node.type === 'row' && _jsx(RowFields, { node: node, updateSetting: updateSetting }), node.type === 'column' && _jsx(ColumnFields, { node: node, updateSetting: updateSetting })] }) }), _jsxs("div", { className: "p-4 border-t border-border space-y-2", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Actions" }), _jsxs("div", { className: "flex gap-2", children: [_jsxs("button", { type: "button", onClick: () => onMoveNodeUp(node.id), "aria-label": "Move up", className: "flex-1 flex items-center justify-center gap-1.5 px-3 py-2 text-sm bg-background border border-input rounded-md hover:bg-accent transition-colors", children: [_jsx(ArrowUp, { size: 14 }), "Up"] }), _jsxs("button", { type: "button", onClick: () => onMoveNodeDown(node.id), "aria-label": "Move down", className: "flex-1 flex items-center justify-center gap-1.5 px-3 py-2 text-sm bg-background border border-input rounded-md hover:bg-accent transition-colors", children: [_jsx(ArrowDown, { size: 14 }), "Down"] })] }), _jsxs("button", { type: "button", onClick: () => onDuplicateNode(node.id), className: "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium bg-background border border-input rounded-md hover:bg-accent transition-colors", children: [_jsx(Copy, { size: 14 }), "Duplicate"] }), _jsxs("button", { type: "button", onClick: handleDelete, onBlur: () => setConfirmDelete(false), className: `w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-md transition-colors ${confirmDelete
39
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx("div", { className: "border-border border-b p-4", children: _jsxs("p", { className: "text-foreground text-sm font-medium", children: [nodeLabel, " Settings"] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsxs("div", { className: "space-y-4 p-4", children: [node.type === 'section' && (_jsx(SectionFields, { node: node, updateSetting: updateSetting, onAddRow: onAddRow })), node.type === 'container' && (_jsx(ContainerFields, { node: node, updateSetting: updateSetting })), node.type === 'row' && _jsx(RowFields, { node: node, updateSetting: updateSetting }), node.type === 'column' && _jsx(ColumnFields, { node: node, updateSetting: updateSetting })] }) }), _jsxs("div", { className: "border-border space-y-2 border-t p-4", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Actions" }), _jsxs("div", { className: "flex gap-2", children: [_jsxs("button", { type: "button", onClick: () => onMoveNodeUp(node.id), "aria-label": "Move up", className: "bg-background border-input hover:bg-accent flex flex-1 items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-sm transition-colors", children: [_jsx(ArrowUp, { size: 14 }), "Up"] }), _jsxs("button", { type: "button", onClick: () => onMoveNodeDown(node.id), "aria-label": "Move down", className: "bg-background border-input hover:bg-accent flex flex-1 items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-sm transition-colors", children: [_jsx(ArrowDown, { size: 14 }), "Down"] })] }), _jsxs("button", { type: "button", onClick: () => onDuplicateNode(node.id), className: "bg-background border-input hover:bg-accent flex w-full items-center justify-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors", children: [_jsx(Copy, { size: 14 }), "Duplicate"] }), _jsxs("button", { type: "button", onClick: handleDelete, onBlur: () => setConfirmDelete(false), className: `flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${confirmDelete
40
40
  ? 'bg-destructive text-destructive-foreground'
41
- : 'bg-background border border-destructive text-destructive hover:bg-destructive/10'}`, children: [_jsx(Trash2, { size: 14 }), confirmDelete ? 'Click again to confirm' : 'Delete'] })] })] }));
41
+ : 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'}`, children: [_jsx(Trash2, { size: 14 }), confirmDelete ? 'Click again to confirm' : 'Delete'] })] })] }));
42
42
  }
43
43
  function SectionFields({ node, updateSetting, onAddRow, }) {
44
44
  const s = node.settings;
45
- return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Background" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "h-9 w-9 rounded-md border border-input cursor-pointer" }), _jsx("input", { type: "text", value: s.background ?? '', onChange: (e) => updateSetting('background', e.target.value), placeholder: "transparent", className: `${INPUT_CLASS} flex-1` })] })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Spacing" }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding Top" }), _jsx("input", { type: "text", value: s.paddingTop ?? '', onChange: (e) => updateSetting('paddingTop', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding Bottom" }), _jsx("input", { type: "text", value: s.paddingBottom ?? '', onChange: (e) => updateSetting('paddingBottom', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Margin Top" }), _jsx("input", { type: "text", value: s.marginTop ?? '', onChange: (e) => updateSetting('marginTop', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Margin Bottom" }), _jsx("input", { type: "text", value: s.marginBottom ?? '', onChange: (e) => updateSetting('marginBottom', e.target.value), placeholder: "0px", className: INPUT_CLASS })] })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Attributes" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium text-foreground", children: "Visibility" }), _jsx(SwitchPrimitive.Root, { checked: s.visibility !== 'hidden', onCheckedChange: (checked) => updateSetting('visibility', checked ? 'visible' : 'hidden'), className: "w-9 h-5 bg-input rounded-full relative data-[state=checked]:bg-primary transition-colors", "aria-label": "Section visibility", children: _jsx(SwitchPrimitive.Thumb, { className: "block h-3.5 w-3.5 rounded-full bg-background shadow-sm transition-transform translate-x-0.5 data-[state=checked]:translate-x-[18px]" }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "HTML ID" }), _jsx("input", { type: "text", value: s.htmlId ?? '', onChange: (e) => updateSetting('htmlId', e.target.value), placeholder: "section-id", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "HTML Class" }), _jsx("input", { type: "text", value: s.htmlClass ?? '', onChange: (e) => updateSetting('htmlClass', e.target.value), placeholder: "my-class", className: INPUT_CLASS })] }), onAddRow && (_jsxs("button", { type: "button", onClick: () => onAddRow(node.id), className: "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors", children: [_jsx(Plus, { size: 14 }), "Add Row"] }))] }));
45
+ return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Background" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "border-input h-9 w-9 cursor-pointer rounded-md border" }), _jsx("input", { type: "text", value: s.background ?? '', onChange: (e) => updateSetting('background', e.target.value), placeholder: "transparent", className: `${INPUT_CLASS} flex-1` })] })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Spacing" }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding Top" }), _jsx("input", { type: "text", value: s.paddingTop ?? '', onChange: (e) => updateSetting('paddingTop', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding Bottom" }), _jsx("input", { type: "text", value: s.paddingBottom ?? '', onChange: (e) => updateSetting('paddingBottom', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Margin Top" }), _jsx("input", { type: "text", value: s.marginTop ?? '', onChange: (e) => updateSetting('marginTop', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Margin Bottom" }), _jsx("input", { type: "text", value: s.marginBottom ?? '', onChange: (e) => updateSetting('marginBottom', e.target.value), placeholder: "0px", className: INPUT_CLASS })] })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Attributes" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Visibility" }), _jsx(SwitchPrimitive.Root, { checked: s.visibility !== 'hidden', onCheckedChange: (checked) => updateSetting('visibility', checked ? 'visible' : 'hidden'), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": "Section visibility", children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "HTML ID" }), _jsx("input", { type: "text", value: s.htmlId ?? '', onChange: (e) => updateSetting('htmlId', e.target.value), placeholder: "section-id", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "HTML Class" }), _jsx("input", { type: "text", value: s.htmlClass ?? '', onChange: (e) => updateSetting('htmlClass', e.target.value), placeholder: "my-class", className: INPUT_CLASS })] }), onAddRow && (_jsxs("button", { type: "button", onClick: () => onAddRow(node.id), className: "bg-primary text-primary-foreground hover:bg-primary/90 flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors", children: [_jsx(Plus, { size: 14 }), "Add Row"] }))] }));
46
46
  }
47
47
  function ContainerFields({ node, updateSetting, }) {
48
48
  const s = node.settings;
49
49
  return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Layout" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Max Width" }), _jsx("input", { type: "text", value: s.maxWidth ?? '', onChange: (e) => updateSetting('maxWidth', e.target.value), placeholder: "1200px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Alignment" }), _jsx("div", { className: "flex gap-1", children: ['left', 'center', 'right'].map((align) => {
50
50
  const Icon = align === 'left' ? AlignLeft : align === 'center' ? AlignCenter : AlignRight;
51
- return (_jsx("button", { type: "button", onClick: () => updateSetting('alignment', align), "aria-label": `Align ${align}`, className: `flex-1 flex items-center justify-center py-2 rounded-md border transition-colors ${s.alignment === align
51
+ return (_jsx("button", { type: "button", onClick: () => updateSetting('alignment', align), "aria-label": `Align ${align}`, className: `flex flex-1 items-center justify-center rounded-md border py-2 transition-colors ${s.alignment === align
52
52
  ? 'bg-primary text-primary-foreground border-primary'
53
53
  : 'bg-background border-input hover:bg-accent'}`, children: _jsx(Icon, { size: 14 }) }, align));
54
54
  }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding" }), _jsx("input", { type: "text", value: s.padding ?? '', onChange: (e) => updateSetting('padding', e.target.value), placeholder: "0px", className: INPUT_CLASS })] })] }));
@@ -63,18 +63,18 @@ function RowFields({ node, updateSetting, }) {
63
63
  : align === 'center'
64
64
  ? Minus
65
65
  : AlignCenter;
66
- return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex-1 flex items-center justify-center py-2 rounded-md border text-xs transition-colors ${s.verticalAlign === align
66
+ return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex flex-1 items-center justify-center rounded-md border py-2 text-xs transition-colors ${s.verticalAlign === align
67
67
  ? 'bg-primary text-primary-foreground border-primary'
68
68
  : 'bg-background border-input hover:bg-accent'}`, children: _jsx(Icon, { size: 14 }) }, align));
69
- }) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Mobile" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium text-foreground", children: "Reverse on Mobile" }), _jsx(SwitchPrimitive.Root, { checked: !!s.reverseOnMobile, onCheckedChange: (checked) => updateSetting('reverseOnMobile', checked), className: "w-9 h-5 bg-input rounded-full relative data-[state=checked]:bg-primary transition-colors", "aria-label": "Reverse column order on mobile", children: _jsx(SwitchPrimitive.Thumb, { className: "block h-3.5 w-3.5 rounded-full bg-background shadow-sm transition-transform translate-x-0.5 data-[state=checked]:translate-x-[18px]" }) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium text-foreground", children: "Wrap on Mobile" }), _jsx(SwitchPrimitive.Root, { checked: !!s.wrapOnMobile, onCheckedChange: (checked) => updateSetting('wrapOnMobile', checked), className: "w-9 h-5 bg-input rounded-full relative data-[state=checked]:bg-primary transition-colors", "aria-label": "Wrap columns on mobile", children: _jsx(SwitchPrimitive.Thumb, { className: "block h-3.5 w-3.5 rounded-full bg-background shadow-sm transition-transform translate-x-0.5 data-[state=checked]:translate-x-[18px]" }) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Column Presets" }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: COLUMN_PRESETS.map((preset) => (_jsxs("button", { type: "button", onClick: () => updateSetting('__columnPreset', preset.widths), className: "px-2 py-2 rounded-md border border-input bg-background hover:bg-accent transition-colors", children: [_jsx("div", { className: "flex gap-0.5 h-4", children: preset.widths.map((w, i) => (_jsx("div", { className: "bg-muted-foreground/30 rounded-sm", style: { flex: w } }, i))) }), _jsx("p", { className: "text-xs text-muted-foreground mt-1 text-center", children: preset.widths.join(' | ') })] }, preset.label))) })] }));
69
+ }) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Mobile" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Reverse on Mobile" }), _jsx(SwitchPrimitive.Root, { checked: !!s.reverseOnMobile, onCheckedChange: (checked) => updateSetting('reverseOnMobile', checked), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": "Reverse column order on mobile", children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Wrap on Mobile" }), _jsx(SwitchPrimitive.Root, { checked: !!s.wrapOnMobile, onCheckedChange: (checked) => updateSetting('wrapOnMobile', checked), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": "Wrap columns on mobile", children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Column Presets" }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: COLUMN_PRESETS.map((preset) => (_jsxs("button", { type: "button", onClick: () => updateSetting('__columnPreset', preset.widths), className: "border-input bg-background hover:bg-accent rounded-md border px-2 py-2 transition-colors", children: [_jsx("div", { className: "flex h-4 gap-0.5", children: preset.widths.map((w, i) => (_jsx("div", { className: "bg-muted-foreground/30 rounded-sm", style: { flex: w } }, i))) }), _jsx("p", { className: "text-muted-foreground mt-1 text-center text-xs", children: preset.widths.join(' | ') })] }, preset.label))) })] }));
70
70
  }
71
71
  function ColumnFields({ node, updateSetting, }) {
72
72
  const s = node.settings;
73
73
  return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Size" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Width (1-12)" }), _jsx("input", { type: "number", min: 1, max: 12, value: s.width, onChange: (e) => updateSetting('width', Number(e.target.value)), className: INPUT_CLASS })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Layout" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Vertical Align" }), _jsx("div", { className: "flex gap-1", children: ['top', 'center', 'bottom'].map((align) => {
74
74
  const Icon = align === 'top' ? ArrowUpFromLine : align === 'bottom' ? ArrowDownToLine : Minus;
75
- return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex-1 flex items-center justify-center py-2 rounded-md border transition-colors ${s.verticalAlign === align
75
+ return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex flex-1 items-center justify-center rounded-md border py-2 transition-colors ${s.verticalAlign === align
76
76
  ? 'bg-primary text-primary-foreground border-primary'
77
77
  : 'bg-background border-input hover:bg-accent'}`, children: _jsx(Icon, { size: 14 }) }, align));
78
- }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding" }), _jsx("input", { type: "text", value: s.padding ?? '', onChange: (e) => updateSetting('padding', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "h-9 w-9 rounded-md border border-input cursor-pointer" }), _jsx("input", { type: "text", value: s.background ?? '', onChange: (e) => updateSetting('background', e.target.value), placeholder: "transparent", className: `${INPUT_CLASS} flex-1` })] })] })] }));
78
+ }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding" }), _jsx("input", { type: "text", value: s.padding ?? '', onChange: (e) => updateSetting('padding', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "border-input h-9 w-9 cursor-pointer rounded-md border" }), _jsx("input", { type: "text", value: s.background ?? '', onChange: (e) => updateSetting('background', e.target.value), placeholder: "transparent", className: `${INPUT_CLASS} flex-1` })] })] })] }));
79
79
  }
80
80
  //# sourceMappingURL=NodeSettings.js.map
@@ -116,10 +116,10 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate })
116
116
  replaceTree(generatedTree);
117
117
  }, [replaceTree]);
118
118
  if (loading) {
119
- return (_jsx("div", { className: "h-full flex items-center justify-center bg-background", children: _jsx(Loader2, { className: "animate-spin text-muted-foreground", size: 24 }) }));
119
+ return (_jsx("div", { className: "bg-background flex h-full items-center justify-center", children: _jsx(Loader2, { className: "text-muted-foreground animate-spin", size: 24 }) }));
120
120
  }
121
121
  if (loadError) {
122
- return (_jsx("div", { className: "h-full flex items-center justify-center bg-background", children: _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4 max-w-md", children: [_jsx(AlertTriangle, { className: "text-destructive shrink-0", size: 20 }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Failed to load page" }), _jsx("p", { className: "text-sm text-muted-foreground mt-1", children: loadError })] })] }) }));
122
+ return (_jsx("div", { className: "bg-background flex h-full items-center justify-center", children: _jsxs("div", { className: "border-destructive/30 bg-destructive/5 flex max-w-md items-center gap-3 rounded-lg border p-4", children: [_jsx(AlertTriangle, { className: "text-destructive shrink-0", size: 20 }), _jsxs("div", { children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: "Failed to load page" }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: loadError })] })] }) }));
123
123
  }
124
124
  const canvasWidth = DEVICE_WIDTHS[deviceMode];
125
125
  const isConstrained = deviceMode !== 'desktop';
@@ -143,6 +143,6 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate })
143
143
  ...previewStyle,
144
144
  fontFamily: previewTheme.fontFamily ?? undefined,
145
145
  };
146
- return (_jsxs(ErrorBoundary, { children: [_jsxs("div", { className: "h-full flex flex-col bg-background overflow-hidden", children: [_jsx(BuilderToolbar, { collectionSlug: collectionSlug, pageSettings: pageSettings, status: status, dirty: dirty, saving: saving, canUndo: canUndo, canRedo: canRedo, deviceMode: deviceMode, onNavigate: onNavigate, onTitleChange: (title) => setPageSettings({ title }), onUndo: undo, onRedo: redo, onDeviceMode: setDeviceMode, onSave: handleSave, onPublish: handlePublish, onOpenAI: () => setAiDialogOpen(true) }), _jsxs("div", { className: "flex-1 flex overflow-hidden", children: [_jsx("div", { className: "flex-1 overflow-auto bg-muted", children: _jsx("div", { className: "mx-auto h-full max-w-full transition-all duration-200", style: { width: canvasWidth }, children: _jsx("div", { className: `h-full bg-background page-builder-canvas-shell ${isConstrained ? 'shadow-lg border-x border-border' : ''}`, style: canvasShellStyle, children: _jsx(BuilderCanvas, { tree: tree, selectedNodeId: selectedNodeId, showGridOverlay: showGridOverlay, deviceMode: deviceMode, onSelectNode: selectNode }) }) }) }), _jsx("div", { className: "w-[35%] min-w-[280px] max-w-[420px] border-l border-border bg-card overflow-y-auto", children: _jsx(ContextPanel, { activeTab: activeTab, onTabChange: setActiveTab, selectedNode: selectedNode, tree: tree, pageSettings: pageSettings, onUpdateSettings: updateSettings, onUpdateBlock: updateBlock, onRemoveNode: removeNodeById, onDuplicateNode: duplicateNode, onMoveNodeUp: moveNodeUp, onMoveNodeDown: moveNodeDown, onPageSettingsChange: setPageSettings, onAddRow: addRowToSection, config: config }) })] }), _jsx(BottomBar, { deviceMode: deviceMode, showGridOverlay: showGridOverlay, onAddSection: addSection, onToggleGrid: setShowGridOverlay })] }), _jsx(AIGenerateDialog, { open: aiDialogOpen, onClose: () => setAiDialogOpen(false), onAccept: handleAIAccept })] }));
146
+ return (_jsxs(ErrorBoundary, { children: [_jsxs("div", { className: "bg-background flex h-full flex-col overflow-hidden", children: [_jsx(BuilderToolbar, { collectionSlug: collectionSlug, pageSettings: pageSettings, status: status, dirty: dirty, saving: saving, canUndo: canUndo, canRedo: canRedo, deviceMode: deviceMode, onNavigate: onNavigate, onTitleChange: (title) => setPageSettings({ title }), onUndo: undo, onRedo: redo, onDeviceMode: setDeviceMode, onSave: handleSave, onPublish: handlePublish, onOpenAI: () => setAiDialogOpen(true) }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsx("div", { className: "bg-muted flex-1 overflow-auto", children: _jsx("div", { className: "mx-auto h-full max-w-full transition-all duration-200", style: { width: canvasWidth }, children: _jsx("div", { className: `bg-background page-builder-canvas-shell h-full ${isConstrained ? 'border-border border-x shadow-lg' : ''}`, style: canvasShellStyle, children: _jsx(BuilderCanvas, { tree: tree, selectedNodeId: selectedNodeId, showGridOverlay: showGridOverlay, deviceMode: deviceMode, onSelectNode: selectNode }) }) }) }), _jsx("div", { className: "border-border bg-card w-[35%] max-w-[420px] min-w-[280px] overflow-y-auto border-l", children: _jsx(ContextPanel, { activeTab: activeTab, onTabChange: setActiveTab, selectedNode: selectedNode, tree: tree, pageSettings: pageSettings, onUpdateSettings: updateSettings, onUpdateBlock: updateBlock, onRemoveNode: removeNodeById, onDuplicateNode: duplicateNode, onMoveNodeUp: moveNodeUp, onMoveNodeDown: moveNodeDown, onPageSettingsChange: setPageSettings, onAddRow: addRowToSection, config: config }) })] }), _jsx(BottomBar, { deviceMode: deviceMode, showGridOverlay: showGridOverlay, onAddSection: addSection, onToggleGrid: setShowGridOverlay })] }), _jsx(AIGenerateDialog, { open: aiDialogOpen, onClose: () => setAiDialogOpen(false), onAccept: handleAIAccept })] }));
147
147
  }
148
148
  //# sourceMappingURL=PageBuilder.js.map
@@ -22,6 +22,6 @@ export function PageSettingsEditor({ settings, onChange }) {
22
22
  }, [onChange]);
23
23
  const metaTitleLength = (settings.metaTitle ?? '').length;
24
24
  const metaDescLength = (settings.metaDescription ?? '').length;
25
- return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "General" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Title" }), _jsx("input", { type: "text", value: settings.title, onChange: (e) => update('title', e.target.value), placeholder: "Page title", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Slug" }), _jsx("input", { type: "text", value: settings.slug, onChange: (e) => update('slug', e.target.value), placeholder: "/page-slug", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Template" }), _jsx("input", { type: "text", value: settings.template ?? '', onChange: (e) => update('template', e.target.value), placeholder: "default", className: INPUT_CLASS, readOnly: true })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "SEO" }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between mb-1", children: [_jsx("label", { className: "text-sm font-medium text-foreground", children: "Meta Title" }), _jsxs("span", { className: `text-xs ${metaTitleLength > 60 ? 'text-destructive' : 'text-muted-foreground'}`, children: [metaTitleLength, "/60"] })] }), _jsx("input", { type: "text", value: settings.metaTitle ?? '', onChange: (e) => update('metaTitle', e.target.value), placeholder: "SEO title", maxLength: 100, className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between mb-1", children: [_jsx("label", { className: "text-sm font-medium text-foreground", children: "Meta Description" }), _jsxs("span", { className: `text-xs ${metaDescLength > 160 ? 'text-destructive' : 'text-muted-foreground'}`, children: [metaDescLength, "/160"] })] }), _jsx("textarea", { value: settings.metaDescription ?? '', onChange: (e) => update('metaDescription', e.target.value), placeholder: "Brief description for search engines", rows: 3, maxLength: 250, className: `${INPUT_CLASS} resize-y` })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "OG Image" }), _jsx("input", { type: "text", value: settings.ogImage ?? '', onChange: (e) => update('ogImage', e.target.value), placeholder: "https://example.com/image.jpg", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Focus Keyphrase" }), _jsx("input", { type: "text", value: settings.focusKeyphrase ?? '', onChange: (e) => update('focusKeyphrase', e.target.value), placeholder: "primary keyword", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Schema Type" }), _jsxs("select", { value: settings.schemaType ?? '', onChange: (e) => update('schemaType', e.target.value), className: INPUT_CLASS, children: [_jsx("option", { value: "", children: "Select schema type..." }), SCHEMA_TYPES.map((type) => (_jsx("option", { value: type, children: type }, type)))] })] })] }));
25
+ return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "General" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Title" }), _jsx("input", { type: "text", value: settings.title, onChange: (e) => update('title', e.target.value), placeholder: "Page title", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Slug" }), _jsx("input", { type: "text", value: settings.slug, onChange: (e) => update('slug', e.target.value), placeholder: "/page-slug", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Template" }), _jsx("input", { type: "text", value: settings.template ?? '', onChange: (e) => update('template', e.target.value), placeholder: "default", className: INPUT_CLASS, readOnly: true })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "SEO" }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Meta Title" }), _jsxs("span", { className: `text-xs ${metaTitleLength > 60 ? 'text-destructive' : 'text-muted-foreground'}`, children: [metaTitleLength, "/60"] })] }), _jsx("input", { type: "text", value: settings.metaTitle ?? '', onChange: (e) => update('metaTitle', e.target.value), placeholder: "SEO title", maxLength: 100, className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Meta Description" }), _jsxs("span", { className: `text-xs ${metaDescLength > 160 ? 'text-destructive' : 'text-muted-foreground'}`, children: [metaDescLength, "/160"] })] }), _jsx("textarea", { value: settings.metaDescription ?? '', onChange: (e) => update('metaDescription', e.target.value), placeholder: "Brief description for search engines", rows: 3, maxLength: 250, className: `${INPUT_CLASS} resize-y` })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "OG Image" }), _jsx("input", { type: "text", value: settings.ogImage ?? '', onChange: (e) => update('ogImage', e.target.value), placeholder: "https://example.com/image.jpg", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Focus Keyphrase" }), _jsx("input", { type: "text", value: settings.focusKeyphrase ?? '', onChange: (e) => update('focusKeyphrase', e.target.value), placeholder: "primary keyword", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Schema Type" }), _jsxs("select", { value: settings.schemaType ?? '', onChange: (e) => update('schemaType', e.target.value), className: INPUT_CLASS, children: [_jsx("option", { value: "", children: "Select schema type..." }), SCHEMA_TYPES.map((type) => (_jsx("option", { value: type, children: type }, type)))] })] })] }));
26
26
  }
27
27
  //# sourceMappingURL=PageSettings.js.map
@@ -6,8 +6,8 @@ export function PageTemplates({ onNavigate }) {
6
6
  const { data, loading, error, refetch } = useApiData('/page-templates');
7
7
  const templates = data ?? [];
8
8
  if (loading) {
9
- return (_jsxs("div", { className: "flex h-64 items-center justify-center p-4", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "h-6 w-6 animate-spin text-primary" }), _jsx("span", { className: "sr-only", children: "Loading page templates" })] }));
9
+ return (_jsxs("div", { className: "flex h-64 items-center justify-center p-4", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "text-primary h-6 w-6 animate-spin" }), _jsx("span", { className: "sr-only", children: "Loading page templates" })] }));
10
10
  }
11
- return (_jsxs("div", { className: "p-4 pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-border bg-card p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "flex-1 text-sm text-foreground", children: error }), _jsx("button", { type: "button", onClick: refetch, className: "rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-accent", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "mb-1 text-2xl font-medium text-foreground", children: "Page Templates" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [templates.length, " saved template", templates.length === 1 ? '' : 's'] })] }), _jsxs("button", { type: "button", onClick: refetch, className: "inline-flex items-center gap-2 rounded-md border border-border px-3 py-2 text-sm font-medium text-foreground hover:bg-accent", children: [_jsx(RefreshCw, { className: "h-4 w-4" }), "Refresh"] })] }), templates.length === 0 ? (_jsxs("div", { className: "rounded-lg border border-border bg-card p-8 text-center", children: [_jsx(Layers, { className: "mx-auto mb-3 h-8 w-8 text-muted-foreground" }), _jsx("h2", { className: "mb-1 text-lg font-medium text-foreground", children: "No page templates yet" }), _jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: "Built-in templates are seeded by the CMS when the templates API is available." }), _jsx("button", { type: "button", onClick: () => onNavigate?.('/saved-sections'), className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90", children: "View Saved Sections" })] })) : (_jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3", children: templates.map((template) => (_jsxs("div", { className: "rounded-lg border border-border bg-card p-4", children: [_jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-base font-medium text-foreground", children: template.name ?? 'Untitled template' }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: template.description ?? 'No description provided.' })] }), template.builtIn && (_jsx("span", { className: "rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: "Built-in" }))] }), _jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [_jsx("span", { children: template.category ?? 'content' }), _jsx("span", { children: template.updatedAt ? new Date(template.updatedAt).toLocaleDateString() : '' })] })] }, template.id))) }))] }));
11
+ return (_jsxs("div", { className: "p-4 pr-8", children: [error && (_jsxs("div", { className: "border-border bg-card mb-4 flex items-center gap-3 rounded-lg border p-3", children: [_jsx(AlertTriangle, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { className: "text-foreground flex-1 text-sm", children: error }), _jsx("button", { type: "button", onClick: refetch, className: "border-border text-foreground hover:bg-accent rounded-md border px-3 py-1 text-sm", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground mb-1 text-2xl font-medium", children: "Page Templates" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [templates.length, " saved template", templates.length === 1 ? '' : 's'] })] }), _jsxs("button", { type: "button", onClick: refetch, className: "border-border text-foreground hover:bg-accent inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium", children: [_jsx(RefreshCw, { className: "h-4 w-4" }), "Refresh"] })] }), templates.length === 0 ? (_jsxs("div", { className: "border-border bg-card rounded-lg border p-8 text-center", children: [_jsx(Layers, { className: "text-muted-foreground mx-auto mb-3 h-8 w-8" }), _jsx("h2", { className: "text-foreground mb-1 text-lg font-medium", children: "No page templates yet" }), _jsx("p", { className: "text-muted-foreground mb-4 text-sm", children: "Built-in templates are seeded by the CMS when the templates API is available." }), _jsx("button", { type: "button", onClick: () => onNavigate?.('/saved-sections'), className: "bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium hover:opacity-90", children: "View Saved Sections" })] })) : (_jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3", children: templates.map((template) => (_jsxs("div", { className: "border-border bg-card rounded-lg border p-4", children: [_jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-foreground text-base font-medium", children: template.name ?? 'Untitled template' }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: template.description ?? 'No description provided.' })] }), template.builtIn && (_jsx("span", { className: "bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs", children: "Built-in" }))] }), _jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-sm", children: [_jsx("span", { children: template.category ?? 'content' }), _jsx("span", { children: template.updatedAt ? new Date(template.updatedAt).toLocaleDateString() : '' })] })] }, template.id))) }))] }));
12
12
  }
13
13
  //# sourceMappingURL=PageTemplates.js.map