@actuate-media/cms-admin 0.8.0 → 0.8.1

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 (432) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +44 -42
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/__tests__/lib/search.test.js +10 -10
  5. package/dist/__tests__/lib/search.test.js.map +1 -1
  6. package/dist/__tests__/lib/utils.test.js.map +1 -1
  7. package/dist/__tests__/router/match-route.test.js.map +1 -1
  8. package/dist/__tests__/router/strip-base.test.js.map +1 -1
  9. package/dist/components/Breadcrumbs.d.ts.map +1 -1
  10. package/dist/components/Breadcrumbs.js +2 -4
  11. package/dist/components/Breadcrumbs.js.map +1 -1
  12. package/dist/components/CommandPalette.d.ts.map +1 -1
  13. package/dist/components/CommandPalette.js +7 -3
  14. package/dist/components/CommandPalette.js.map +1 -1
  15. package/dist/components/ContentOverviewChart.d.ts.map +1 -1
  16. package/dist/components/ContentOverviewChart.js.map +1 -1
  17. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  18. package/dist/components/ErrorBoundary.js.map +1 -1
  19. package/dist/components/FocalPointPicker.d.ts.map +1 -1
  20. package/dist/components/FocalPointPicker.js +4 -2
  21. package/dist/components/FocalPointPicker.js.map +1 -1
  22. package/dist/components/FolderTree.d.ts.map +1 -1
  23. package/dist/components/FolderTree.js +18 -10
  24. package/dist/components/FolderTree.js.map +1 -1
  25. package/dist/components/LivePreview.d.ts +1 -1
  26. package/dist/components/LivePreview.d.ts.map +1 -1
  27. package/dist/components/LivePreview.js +6 -2
  28. package/dist/components/LivePreview.js.map +1 -1
  29. package/dist/components/LocaleProvider.d.ts.map +1 -1
  30. package/dist/components/LocaleProvider.js.map +1 -1
  31. package/dist/components/LocaleSwitcher.d.ts.map +1 -1
  32. package/dist/components/LocaleSwitcher.js +1 -1
  33. package/dist/components/LocaleSwitcher.js.map +1 -1
  34. package/dist/components/MediaPickerModal.d.ts.map +1 -1
  35. package/dist/components/MediaPickerModal.js.map +1 -1
  36. package/dist/components/PresenceIndicator.d.ts.map +1 -1
  37. package/dist/components/PresenceIndicator.js +5 -2
  38. package/dist/components/PresenceIndicator.js.map +1 -1
  39. package/dist/components/SEOPanel.d.ts +1 -1
  40. package/dist/components/SEOPanel.d.ts.map +1 -1
  41. package/dist/components/SEOPanel.js +110 -24
  42. package/dist/components/SEOPanel.js.map +1 -1
  43. package/dist/components/SEOPerformance.d.ts.map +1 -1
  44. package/dist/components/SEOPerformance.js +2 -2
  45. package/dist/components/SEOPerformance.js.map +1 -1
  46. package/dist/components/ThemeProvider.d.ts.map +1 -1
  47. package/dist/components/ThemeProvider.js.map +1 -1
  48. package/dist/components/TipTapEditor.d.ts.map +1 -1
  49. package/dist/components/TipTapEditor.js +5 -1
  50. package/dist/components/TipTapEditor.js.map +1 -1
  51. package/dist/components/VersionHistory.d.ts +1 -1
  52. package/dist/components/VersionHistory.d.ts.map +1 -1
  53. package/dist/components/VersionHistory.js +1 -1
  54. package/dist/components/VersionHistory.js.map +1 -1
  55. package/dist/components/ui/Avatar.d.ts.map +1 -1
  56. package/dist/components/ui/Avatar.js.map +1 -1
  57. package/dist/components/ui/Badge.d.ts.map +1 -1
  58. package/dist/components/ui/Badge.js.map +1 -1
  59. package/dist/components/ui/Button.d.ts.map +1 -1
  60. package/dist/components/ui/Button.js.map +1 -1
  61. package/dist/components/ui/CommandPalette.d.ts.map +1 -1
  62. package/dist/components/ui/CommandPalette.js +8 -2
  63. package/dist/components/ui/CommandPalette.js.map +1 -1
  64. package/dist/components/ui/ConfirmDialog.d.ts.map +1 -1
  65. package/dist/components/ui/ConfirmDialog.js.map +1 -1
  66. package/dist/components/ui/DataTable.d.ts.map +1 -1
  67. package/dist/components/ui/DataTable.js +1 -3
  68. package/dist/components/ui/DataTable.js.map +1 -1
  69. package/dist/components/ui/EmptyState.d.ts.map +1 -1
  70. package/dist/components/ui/EmptyState.js +1 -1
  71. package/dist/components/ui/EmptyState.js.map +1 -1
  72. package/dist/components/ui/Modal.d.ts.map +1 -1
  73. package/dist/components/ui/Modal.js.map +1 -1
  74. package/dist/components/ui/Pagination.d.ts +1 -1
  75. package/dist/components/ui/Pagination.d.ts.map +1 -1
  76. package/dist/components/ui/Pagination.js +7 -2
  77. package/dist/components/ui/Pagination.js.map +1 -1
  78. package/dist/components/ui/SearchInput.d.ts.map +1 -1
  79. package/dist/components/ui/SearchInput.js.map +1 -1
  80. package/dist/components/ui/Skeleton.d.ts.map +1 -1
  81. package/dist/components/ui/Skeleton.js.map +1 -1
  82. package/dist/components/ui/Toast.d.ts.map +1 -1
  83. package/dist/components/ui/Toast.js.map +1 -1
  84. package/dist/components/ui/index.d.ts.map +1 -1
  85. package/dist/components/ui/index.js.map +1 -1
  86. package/dist/fields/ArrayField.d.ts.map +1 -1
  87. package/dist/fields/ArrayField.js +1 -1
  88. package/dist/fields/ArrayField.js.map +1 -1
  89. package/dist/fields/BlockBuilderField.d.ts.map +1 -1
  90. package/dist/fields/BlockBuilderField.js +7 -7
  91. package/dist/fields/BlockBuilderField.js.map +1 -1
  92. package/dist/fields/DateField.d.ts.map +1 -1
  93. package/dist/fields/DateField.js +1 -1
  94. package/dist/fields/DateField.js.map +1 -1
  95. package/dist/fields/FieldRenderer.d.ts.map +1 -1
  96. package/dist/fields/FieldRenderer.js.map +1 -1
  97. package/dist/fields/GroupField.d.ts.map +1 -1
  98. package/dist/fields/GroupField.js +1 -1
  99. package/dist/fields/GroupField.js.map +1 -1
  100. package/dist/fields/MediaField.d.ts.map +1 -1
  101. package/dist/fields/MediaField.js +1 -1
  102. package/dist/fields/MediaField.js.map +1 -1
  103. package/dist/fields/NavBuilderField.d.ts.map +1 -1
  104. package/dist/fields/NavBuilderField.js +2 -5
  105. package/dist/fields/NavBuilderField.js.map +1 -1
  106. package/dist/fields/NumberField.d.ts +1 -1
  107. package/dist/fields/NumberField.d.ts.map +1 -1
  108. package/dist/fields/NumberField.js +2 -2
  109. package/dist/fields/NumberField.js.map +1 -1
  110. package/dist/fields/RelationshipField.d.ts.map +1 -1
  111. package/dist/fields/RelationshipField.js +7 -3
  112. package/dist/fields/RelationshipField.js.map +1 -1
  113. package/dist/fields/RichTextField.d.ts +1 -1
  114. package/dist/fields/RichTextField.d.ts.map +1 -1
  115. package/dist/fields/RichTextField.js +2 -2
  116. package/dist/fields/RichTextField.js.map +1 -1
  117. package/dist/fields/SelectField.d.ts.map +1 -1
  118. package/dist/fields/SelectField.js +9 -7
  119. package/dist/fields/SelectField.js.map +1 -1
  120. package/dist/fields/SlugField.d.ts.map +1 -1
  121. package/dist/fields/SlugField.js +1 -1
  122. package/dist/fields/SlugField.js.map +1 -1
  123. package/dist/fields/TextField.d.ts +1 -1
  124. package/dist/fields/TextField.d.ts.map +1 -1
  125. package/dist/fields/TextField.js +2 -2
  126. package/dist/fields/TextField.js.map +1 -1
  127. package/dist/fields/ToggleField.d.ts.map +1 -1
  128. package/dist/fields/ToggleField.js +1 -1
  129. package/dist/fields/ToggleField.js.map +1 -1
  130. package/dist/fields/block-types.d.ts.map +1 -1
  131. package/dist/fields/block-types.js +28 -8
  132. package/dist/fields/block-types.js.map +1 -1
  133. package/dist/fields/index.d.ts.map +1 -1
  134. package/dist/fields/index.js.map +1 -1
  135. package/dist/hooks/useBuilderState.d.ts.map +1 -1
  136. package/dist/hooks/useBuilderState.js.map +1 -1
  137. package/dist/hooks/useContentLock.d.ts.map +1 -1
  138. package/dist/hooks/useContentLock.js.map +1 -1
  139. package/dist/hooks/useDebounce.js.map +1 -1
  140. package/dist/hooks/useKeyboardShortcuts.d.ts.map +1 -1
  141. package/dist/hooks/useKeyboardShortcuts.js.map +1 -1
  142. package/dist/index.d.ts +2 -2
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js.map +1 -1
  145. package/dist/layout/Header.d.ts.map +1 -1
  146. package/dist/layout/Header.js.map +1 -1
  147. package/dist/layout/Layout.d.ts.map +1 -1
  148. package/dist/layout/Layout.js.map +1 -1
  149. package/dist/layout/Sidebar.d.ts +1 -1
  150. package/dist/layout/Sidebar.d.ts.map +1 -1
  151. package/dist/layout/Sidebar.js +5 -8
  152. package/dist/layout/Sidebar.js.map +1 -1
  153. package/dist/lib/api.js.map +1 -1
  154. package/dist/lib/search.d.ts.map +1 -1
  155. package/dist/lib/search.js +3 -5
  156. package/dist/lib/search.js.map +1 -1
  157. package/dist/lib/useApiData.d.ts.map +1 -1
  158. package/dist/lib/useApiData.js.map +1 -1
  159. package/dist/lib/utils.d.ts.map +1 -1
  160. package/dist/lib/utils.js.map +1 -1
  161. package/dist/router/index.d.ts.map +1 -1
  162. package/dist/router/index.js +1 -3
  163. package/dist/router/index.js.map +1 -1
  164. package/dist/views/CollectionList.d.ts.map +1 -1
  165. package/dist/views/CollectionList.js +56 -17
  166. package/dist/views/CollectionList.js.map +1 -1
  167. package/dist/views/Dashboard.d.ts.map +1 -1
  168. package/dist/views/Dashboard.js +26 -13
  169. package/dist/views/Dashboard.js.map +1 -1
  170. package/dist/views/DocumentEdit.d.ts +1 -1
  171. package/dist/views/DocumentEdit.d.ts.map +1 -1
  172. package/dist/views/DocumentEdit.js +33 -15
  173. package/dist/views/DocumentEdit.js.map +1 -1
  174. package/dist/views/ForgotPassword.d.ts.map +1 -1
  175. package/dist/views/ForgotPassword.js.map +1 -1
  176. package/dist/views/FormEditor.d.ts.map +1 -1
  177. package/dist/views/FormEditor.js +8 -2
  178. package/dist/views/FormEditor.js.map +1 -1
  179. package/dist/views/FormSubmissions.d.ts.map +1 -1
  180. package/dist/views/FormSubmissions.js +6 -6
  181. package/dist/views/FormSubmissions.js.map +1 -1
  182. package/dist/views/Forms.d.ts.map +1 -1
  183. package/dist/views/Forms.js.map +1 -1
  184. package/dist/views/Login.d.ts.map +1 -1
  185. package/dist/views/Login.js +5 -2
  186. package/dist/views/Login.js.map +1 -1
  187. package/dist/views/MediaBrowser.d.ts.map +1 -1
  188. package/dist/views/MediaBrowser.js +39 -19
  189. package/dist/views/MediaBrowser.js.map +1 -1
  190. package/dist/views/PageEditor.d.ts.map +1 -1
  191. package/dist/views/PageEditor.js.map +1 -1
  192. package/dist/views/Pages.d.ts.map +1 -1
  193. package/dist/views/Pages.js +20 -10
  194. package/dist/views/Pages.js.map +1 -1
  195. package/dist/views/PostEditor.d.ts.map +1 -1
  196. package/dist/views/PostEditor.js.map +1 -1
  197. package/dist/views/Posts.d.ts.map +1 -1
  198. package/dist/views/Posts.js +13 -7
  199. package/dist/views/Posts.js.map +1 -1
  200. package/dist/views/Redirects.d.ts.map +1 -1
  201. package/dist/views/Redirects.js +17 -5
  202. package/dist/views/Redirects.js.map +1 -1
  203. package/dist/views/ResetPassword.d.ts.map +1 -1
  204. package/dist/views/ResetPassword.js.map +1 -1
  205. package/dist/views/SEO.d.ts.map +1 -1
  206. package/dist/views/SEO.js +39 -16
  207. package/dist/views/SEO.js.map +1 -1
  208. package/dist/views/ScriptTagEditor.d.ts.map +1 -1
  209. package/dist/views/ScriptTagEditor.js +2 -1
  210. package/dist/views/ScriptTagEditor.js.map +1 -1
  211. package/dist/views/ScriptTags.d.ts.map +1 -1
  212. package/dist/views/ScriptTags.js.map +1 -1
  213. package/dist/views/Settings.d.ts.map +1 -1
  214. package/dist/views/Settings.js +38 -11
  215. package/dist/views/Settings.js.map +1 -1
  216. package/dist/views/SetupWizard.d.ts.map +1 -1
  217. package/dist/views/SetupWizard.js.map +1 -1
  218. package/dist/views/Users.d.ts.map +1 -1
  219. package/dist/views/Users.js +5 -3
  220. package/dist/views/Users.js.map +1 -1
  221. package/dist/views/page-builder/AIBlockAssist.d.ts.map +1 -1
  222. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  223. package/dist/views/page-builder/AIBlockAssist.js.map +1 -1
  224. package/dist/views/page-builder/AIGenerateDialog.d.ts.map +1 -1
  225. package/dist/views/page-builder/AIGenerateDialog.js +4 -1
  226. package/dist/views/page-builder/AIGenerateDialog.js.map +1 -1
  227. package/dist/views/page-builder/BlockEditor.d.ts.map +1 -1
  228. package/dist/views/page-builder/BlockEditor.js +1 -1
  229. package/dist/views/page-builder/BlockEditor.js.map +1 -1
  230. package/dist/views/page-builder/BlockPicker.d.ts.map +1 -1
  231. package/dist/views/page-builder/BlockPicker.js.map +1 -1
  232. package/dist/views/page-builder/BottomBar.d.ts.map +1 -1
  233. package/dist/views/page-builder/BottomBar.js.map +1 -1
  234. package/dist/views/page-builder/BuilderToolbar.d.ts.map +1 -1
  235. package/dist/views/page-builder/BuilderToolbar.js.map +1 -1
  236. package/dist/views/page-builder/ContextPanel.d.ts.map +1 -1
  237. package/dist/views/page-builder/ContextPanel.js +4 -1
  238. package/dist/views/page-builder/ContextPanel.js.map +1 -1
  239. package/dist/views/page-builder/DesignScore.d.ts.map +1 -1
  240. package/dist/views/page-builder/DesignScore.js.map +1 -1
  241. package/dist/views/page-builder/NodeSettings.d.ts.map +1 -1
  242. package/dist/views/page-builder/NodeSettings.js +1 -1
  243. package/dist/views/page-builder/NodeSettings.js.map +1 -1
  244. package/dist/views/page-builder/PageBuilder.d.ts +1 -1
  245. package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
  246. package/dist/views/page-builder/PageBuilder.js +4 -2
  247. package/dist/views/page-builder/PageBuilder.js.map +1 -1
  248. package/dist/views/page-builder/PageSettings.d.ts.map +1 -1
  249. package/dist/views/page-builder/PageSettings.js.map +1 -1
  250. package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
  251. package/dist/views/page-builder/PageTemplates.js.map +1 -1
  252. package/dist/views/page-builder/SEOPanel.d.ts.map +1 -1
  253. package/dist/views/page-builder/SEOPanel.js +1 -3
  254. package/dist/views/page-builder/SEOPanel.js.map +1 -1
  255. package/dist/views/page-builder/SavedSections.d.ts.map +1 -1
  256. package/dist/views/page-builder/SavedSections.js +3 -7
  257. package/dist/views/page-builder/SavedSections.js.map +1 -1
  258. package/dist/views/page-builder/TemplatePicker.d.ts.map +1 -1
  259. package/dist/views/page-builder/TemplatePicker.js.map +1 -1
  260. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +1 -1
  261. package/dist/views/page-builder/block-renderers/CTAPreview.js +1 -1
  262. package/dist/views/page-builder/block-renderers/CTAPreview.js.map +1 -1
  263. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +1 -1
  264. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  265. package/dist/views/page-builder/block-renderers/CardsPreview.js.map +1 -1
  266. package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +1 -1
  267. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -5
  268. package/dist/views/page-builder/block-renderers/CodePreview.js.map +1 -1
  269. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +1 -1
  270. package/dist/views/page-builder/block-renderers/FAQPreview.js +4 -1
  271. package/dist/views/page-builder/block-renderers/FAQPreview.js.map +1 -1
  272. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +1 -1
  273. package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +1 -1
  274. package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +1 -1
  275. package/dist/views/page-builder/block-renderers/FormPreview.js +2 -2
  276. package/dist/views/page-builder/block-renderers/FormPreview.js.map +1 -1
  277. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +1 -1
  278. package/dist/views/page-builder/block-renderers/GalleryPreview.js +1 -3
  279. package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +1 -1
  280. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +1 -1
  281. package/dist/views/page-builder/block-renderers/HeroPreview.js.map +1 -1
  282. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +1 -1
  283. package/dist/views/page-builder/block-renderers/ImagePreview.js.map +1 -1
  284. package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +1 -1
  285. package/dist/views/page-builder/block-renderers/TextPreview.js +2 -6
  286. package/dist/views/page-builder/block-renderers/TextPreview.js.map +1 -1
  287. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +1 -1
  288. package/dist/views/page-builder/block-renderers/VideoPreview.js +2 -5
  289. package/dist/views/page-builder/block-renderers/VideoPreview.js.map +1 -1
  290. package/dist/views/page-builder/block-renderers/index.d.ts.map +1 -1
  291. package/dist/views/page-builder/block-renderers/index.js.map +1 -1
  292. package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +1 -1
  293. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -5
  294. package/dist/views/page-builder/canvas/BlockRenderer.js.map +1 -1
  295. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +1 -1
  296. package/dist/views/page-builder/canvas/BuilderCanvas.js.map +1 -1
  297. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +1 -1
  298. package/dist/views/page-builder/canvas/ColumnRenderer.js +1 -5
  299. package/dist/views/page-builder/canvas/ColumnRenderer.js.map +1 -1
  300. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +1 -1
  301. package/dist/views/page-builder/canvas/ContainerRenderer.js +1 -5
  302. package/dist/views/page-builder/canvas/ContainerRenderer.js.map +1 -1
  303. package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +1 -1
  304. package/dist/views/page-builder/canvas/RowRenderer.js +1 -5
  305. package/dist/views/page-builder/canvas/RowRenderer.js.map +1 -1
  306. package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +1 -1
  307. package/dist/views/page-builder/canvas/SectionRenderer.js +1 -5
  308. package/dist/views/page-builder/canvas/SectionRenderer.js.map +1 -1
  309. package/dist/views/page-builder/canvas/index.d.ts.map +1 -1
  310. package/dist/views/page-builder/canvas/index.js.map +1 -1
  311. package/package.json +2 -2
  312. package/src/AdminRoot.tsx +263 -191
  313. package/src/__tests__/lib/search.test.ts +60 -69
  314. package/src/__tests__/lib/utils.test.ts +12 -12
  315. package/src/__tests__/router/match-route.test.ts +24 -26
  316. package/src/__tests__/router/strip-base.test.ts +15 -15
  317. package/src/components/Breadcrumbs.tsx +27 -24
  318. package/src/components/CommandPalette.tsx +115 -99
  319. package/src/components/ContentOverviewChart.tsx +19 -14
  320. package/src/components/ErrorBoundary.tsx +13 -13
  321. package/src/components/FocalPointPicker.tsx +31 -20
  322. package/src/components/FolderTree.tsx +172 -139
  323. package/src/components/LivePreview.tsx +68 -41
  324. package/src/components/LocaleProvider.tsx +26 -20
  325. package/src/components/LocaleSwitcher.tsx +9 -11
  326. package/src/components/MediaPickerModal.tsx +46 -45
  327. package/src/components/PresenceIndicator.tsx +30 -27
  328. package/src/components/SEOPanel.tsx +378 -228
  329. package/src/components/SEOPerformance.tsx +52 -30
  330. package/src/components/ThemeProvider.tsx +46 -46
  331. package/src/components/TipTapEditor.tsx +60 -64
  332. package/src/components/VersionHistory.tsx +63 -52
  333. package/src/components/ui/Avatar.tsx +8 -8
  334. package/src/components/ui/Badge.tsx +7 -5
  335. package/src/components/ui/Button.tsx +24 -13
  336. package/src/components/ui/CommandPalette.tsx +56 -42
  337. package/src/components/ui/ConfirmDialog.tsx +14 -14
  338. package/src/components/ui/DataTable.tsx +37 -39
  339. package/src/components/ui/EmptyState.tsx +9 -11
  340. package/src/components/ui/Modal.tsx +21 -15
  341. package/src/components/ui/Pagination.tsx +34 -19
  342. package/src/components/ui/SearchInput.tsx +17 -7
  343. package/src/components/ui/Skeleton.tsx +7 -7
  344. package/src/components/ui/Toast.tsx +29 -22
  345. package/src/components/ui/index.ts +24 -24
  346. package/src/fields/ArrayField.tsx +43 -25
  347. package/src/fields/BlockBuilderField.tsx +80 -99
  348. package/src/fields/DateField.tsx +20 -12
  349. package/src/fields/FieldRenderer.tsx +34 -34
  350. package/src/fields/GroupField.tsx +8 -10
  351. package/src/fields/MediaField.tsx +8 -10
  352. package/src/fields/NavBuilderField.tsx +24 -25
  353. package/src/fields/NumberField.tsx +21 -14
  354. package/src/fields/RelationshipField.tsx +105 -91
  355. package/src/fields/RichTextField.tsx +16 -12
  356. package/src/fields/SelectField.tsx +42 -34
  357. package/src/fields/SlugField.tsx +29 -17
  358. package/src/fields/TextField.tsx +24 -16
  359. package/src/fields/ToggleField.tsx +7 -9
  360. package/src/fields/block-types.ts +50 -24
  361. package/src/fields/index.ts +17 -17
  362. package/src/hooks/useBuilderState.ts +260 -221
  363. package/src/hooks/useContentLock.ts +23 -20
  364. package/src/hooks/useDebounce.ts +7 -7
  365. package/src/hooks/useKeyboardShortcuts.ts +16 -16
  366. package/src/index.ts +69 -58
  367. package/src/layout/Header.tsx +21 -20
  368. package/src/layout/Layout.tsx +22 -24
  369. package/src/layout/Sidebar.tsx +107 -72
  370. package/src/lib/api.ts +34 -34
  371. package/src/lib/search.ts +30 -34
  372. package/src/lib/useApiData.ts +65 -62
  373. package/src/lib/utils.ts +3 -3
  374. package/src/router/index.ts +33 -35
  375. package/src/styles/build-input.css +2 -2
  376. package/src/styles/tailwind.css +1 -1
  377. package/src/styles/theme.css +7 -1
  378. package/src/views/CollectionList.tsx +275 -121
  379. package/src/views/Dashboard.tsx +164 -117
  380. package/src/views/DocumentEdit.tsx +298 -253
  381. package/src/views/ForgotPassword.tsx +27 -23
  382. package/src/views/FormEditor.tsx +165 -99
  383. package/src/views/FormSubmissions.tsx +261 -117
  384. package/src/views/Forms.tsx +56 -26
  385. package/src/views/Login.tsx +107 -84
  386. package/src/views/MediaBrowser.tsx +717 -523
  387. package/src/views/PageEditor.tsx +44 -46
  388. package/src/views/Pages.tsx +312 -149
  389. package/src/views/PostEditor.tsx +57 -51
  390. package/src/views/Posts.tsx +206 -74
  391. package/src/views/Redirects.tsx +173 -117
  392. package/src/views/ResetPassword.tsx +43 -32
  393. package/src/views/SEO.tsx +589 -160
  394. package/src/views/ScriptTagEditor.tsx +69 -69
  395. package/src/views/ScriptTags.tsx +54 -42
  396. package/src/views/Settings.tsx +430 -220
  397. package/src/views/SetupWizard.tsx +69 -46
  398. package/src/views/Users.tsx +154 -120
  399. package/src/views/page-builder/AIBlockAssist.tsx +21 -25
  400. package/src/views/page-builder/AIGenerateDialog.tsx +134 -127
  401. package/src/views/page-builder/BlockEditor.tsx +94 -96
  402. package/src/views/page-builder/BlockPicker.tsx +73 -88
  403. package/src/views/page-builder/BottomBar.tsx +15 -11
  404. package/src/views/page-builder/BuilderToolbar.tsx +32 -29
  405. package/src/views/page-builder/ContextPanel.tsx +57 -57
  406. package/src/views/page-builder/DesignScore.tsx +52 -59
  407. package/src/views/page-builder/NodeSettings.tsx +59 -59
  408. package/src/views/page-builder/PageBuilder.tsx +156 -155
  409. package/src/views/page-builder/PageSettings.tsx +16 -15
  410. package/src/views/page-builder/PageTemplates.tsx +23 -17
  411. package/src/views/page-builder/SEOPanel.tsx +90 -111
  412. package/src/views/page-builder/SavedSections.tsx +99 -105
  413. package/src/views/page-builder/TemplatePicker.tsx +44 -48
  414. package/src/views/page-builder/block-renderers/CTAPreview.tsx +11 -13
  415. package/src/views/page-builder/block-renderers/CardsPreview.tsx +13 -15
  416. package/src/views/page-builder/block-renderers/CodePreview.tsx +16 -16
  417. package/src/views/page-builder/block-renderers/FAQPreview.tsx +20 -23
  418. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +5 -5
  419. package/src/views/page-builder/block-renderers/FormPreview.tsx +9 -13
  420. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +22 -28
  421. package/src/views/page-builder/block-renderers/HeroPreview.tsx +17 -30
  422. package/src/views/page-builder/block-renderers/ImagePreview.tsx +12 -12
  423. package/src/views/page-builder/block-renderers/TextPreview.tsx +22 -22
  424. package/src/views/page-builder/block-renderers/VideoPreview.tsx +13 -18
  425. package/src/views/page-builder/block-renderers/index.ts +17 -17
  426. package/src/views/page-builder/canvas/BlockRenderer.tsx +19 -23
  427. package/src/views/page-builder/canvas/BuilderCanvas.tsx +17 -20
  428. package/src/views/page-builder/canvas/ColumnRenderer.tsx +22 -26
  429. package/src/views/page-builder/canvas/ContainerRenderer.tsx +20 -24
  430. package/src/views/page-builder/canvas/RowRenderer.tsx +19 -23
  431. package/src/views/page-builder/canvas/SectionRenderer.tsx +30 -34
  432. package/src/views/page-builder/canvas/index.ts +2 -2
package/src/AdminRoot.tsx CHANGED
@@ -1,50 +1,67 @@
1
- 'use client';
2
-
3
- import { useState, useMemo, useEffect, useRef } from 'react';
4
- import { Layout } from './layout/Layout.js';
5
- import { useAdminRouter } from './router/index.js';
6
- import { ensureCsrfToken } from './lib/api.js';
7
- import { Dashboard } from './views/Dashboard.js';
8
- import { CollectionList } from './views/CollectionList.js';
9
- import { DocumentEdit } from './views/DocumentEdit.js';
10
- import { MediaBrowser } from './views/MediaBrowser.js';
11
- import { Settings } from './views/Settings.js';
12
- import { Forms } from './views/Forms.js';
13
- import { FormEditor } from './views/FormEditor.js';
14
- import { FormSubmissions } from './views/FormSubmissions.js';
15
- import { Users } from './views/Users.js';
16
- import { SEO } from './views/SEO.js';
17
- import { ScriptTags } from './views/ScriptTags.js';
18
- import { ScriptTagEditor } from './views/ScriptTagEditor.js';
19
- import { SetupWizard } from './views/SetupWizard.js';
20
- import { Login } from './views/Login.js';
21
- import { ForgotPassword } from './views/ForgotPassword.js';
22
- import { ResetPassword } from './views/ResetPassword.js';
23
- import { ErrorBoundary } from './components/ErrorBoundary.js';
24
- import { ThemeProvider } from './components/ThemeProvider.js';
25
- import { LocaleProvider } from './components/LocaleProvider.js';
26
- import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts.js';
27
- import { PageBuilder } from './views/page-builder/PageBuilder.js';
28
- import { SavedSections } from './views/page-builder/SavedSections.js';
29
- import { PageTemplates } from './views/page-builder/PageTemplates.js';
1
+ 'use client'
2
+
3
+ import { useState, useMemo, useEffect, useRef } from 'react'
4
+ import { Layout } from './layout/Layout.js'
5
+ import { useAdminRouter } from './router/index.js'
6
+ import { ensureCsrfToken } from './lib/api.js'
7
+ import { Dashboard } from './views/Dashboard.js'
8
+ import { CollectionList } from './views/CollectionList.js'
9
+ import { DocumentEdit } from './views/DocumentEdit.js'
10
+ import { MediaBrowser } from './views/MediaBrowser.js'
11
+ import { Settings } from './views/Settings.js'
12
+ import { Forms } from './views/Forms.js'
13
+ import { FormEditor } from './views/FormEditor.js'
14
+ import { FormSubmissions } from './views/FormSubmissions.js'
15
+ import { Users } from './views/Users.js'
16
+ import { SEO } from './views/SEO.js'
17
+ import { ScriptTags } from './views/ScriptTags.js'
18
+ import { ScriptTagEditor } from './views/ScriptTagEditor.js'
19
+ import { SetupWizard } from './views/SetupWizard.js'
20
+ import { Login } from './views/Login.js'
21
+ import { ForgotPassword } from './views/ForgotPassword.js'
22
+ import { ResetPassword } from './views/ResetPassword.js'
23
+ import { ErrorBoundary } from './components/ErrorBoundary.js'
24
+ import { ThemeProvider } from './components/ThemeProvider.js'
25
+ import { LocaleProvider } from './components/LocaleProvider.js'
26
+ import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts.js'
27
+ import { PageBuilder } from './views/page-builder/PageBuilder.js'
28
+ import { SavedSections } from './views/page-builder/SavedSections.js'
29
+ import { PageTemplates } from './views/page-builder/PageTemplates.js'
30
30
 
31
31
  export interface AdminRootProps {
32
- config: any;
33
- session: any;
34
- basePath?: string;
35
- initialPath?: string;
36
- setupRequired?: boolean;
37
- onSetupComplete?: (data: { name: string; email: string; password: string }) => Promise<{ success: boolean; error?: string }>;
38
- onLogin?: (email: string, password: string, captchaToken?: string) => Promise<{ success: boolean; error?: string }>;
39
- captchaConfig?: { provider: 'recaptcha' | 'turnstile' | 'none'; siteKey: string | null };
32
+ config: any
33
+ session: any
34
+ basePath?: string
35
+ initialPath?: string
36
+ setupRequired?: boolean
37
+ onSetupComplete?: (data: {
38
+ name: string
39
+ email: string
40
+ password: string
41
+ }) => Promise<{ success: boolean; error?: string }>
42
+ onLogin?: (
43
+ email: string,
44
+ password: string,
45
+ captchaToken?: string,
46
+ ) => Promise<{ success: boolean; error?: string }>
47
+ captchaConfig?: { provider: 'recaptcha' | 'turnstile' | 'none'; siteKey: string | null }
40
48
  }
41
49
 
42
- function AdminShell({ config, session, basePath = '/admin', initialPath = '/', setupRequired, onSetupComplete, onLogin, captchaConfig }: AdminRootProps) {
43
- const { currentPath, navigate, matchRoute } = useAdminRouter(basePath, initialPath);
44
- const [shortcutHelpOpen, setShortcutHelpOpen] = useState(false);
45
-
46
- useBranding(config);
47
- useAdminPageTitle(config, currentPath);
50
+ function AdminShell({
51
+ config,
52
+ session,
53
+ basePath = '/admin',
54
+ initialPath = '/',
55
+ setupRequired,
56
+ onSetupComplete,
57
+ onLogin,
58
+ captchaConfig,
59
+ }: AdminRootProps) {
60
+ const { currentPath, navigate, matchRoute } = useAdminRouter(basePath, initialPath)
61
+ const [shortcutHelpOpen, setShortcutHelpOpen] = useState(false)
62
+
63
+ useBranding(config)
64
+ useAdminPageTitle(config, currentPath)
48
65
 
49
66
  // When the session was minted via a custom Server Action (the Next.js App
50
67
  // Router pattern) the admin won't have hit /auth/login directly and thus
@@ -53,47 +70,79 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
53
70
  // also bootstraps lazily inside non-GET requests as a belt-and-braces.
54
71
  useEffect(() => {
55
72
  if (session) {
56
- void ensureCsrfToken();
57
- }
58
- }, [session]);
59
-
60
- const shortcuts = useMemo(() => ({
61
- 'mod+k': () => {
62
- const searchInput = document.querySelector<HTMLInputElement>('input[placeholder*="Search"]');
63
- searchInput?.focus();
64
- },
65
- 'mod+s': () => {
66
- const saveBtn = document.querySelector<HTMLButtonElement>('[data-shortcut="save"]');
67
- saveBtn?.click();
68
- },
69
- 'escape': () => {
70
- const closeBtn = document.querySelector<HTMLButtonElement>('[data-shortcut="close"]');
71
- closeBtn?.click();
72
- },
73
- 'mod+/': () => {
74
- setShortcutHelpOpen(prev => !prev);
75
- },
76
- }), []);
77
-
78
- useKeyboardShortcuts(shortcuts);
73
+ void ensureCsrfToken()
74
+ }
75
+ }, [session])
76
+
77
+ const shortcuts = useMemo(
78
+ () => ({
79
+ 'mod+k': () => {
80
+ const searchInput = document.querySelector<HTMLInputElement>('input[placeholder*="Search"]')
81
+ searchInput?.focus()
82
+ },
83
+ 'mod+s': () => {
84
+ const saveBtn = document.querySelector<HTMLButtonElement>('[data-shortcut="save"]')
85
+ saveBtn?.click()
86
+ },
87
+ escape: () => {
88
+ const closeBtn = document.querySelector<HTMLButtonElement>('[data-shortcut="close"]')
89
+ closeBtn?.click()
90
+ },
91
+ 'mod+/': () => {
92
+ setShortcutHelpOpen((prev) => !prev)
93
+ },
94
+ }),
95
+ [],
96
+ )
97
+
98
+ useKeyboardShortcuts(shortcuts)
99
+
100
+ // IMPORTANT: this useMemo MUST stay above the `setupRequired` / `!session`
101
+ // early returns. React's Rules of Hooks require the same number of hooks
102
+ // on every render — putting it below the early returns means we call N
103
+ // hooks pre-login and N+1 post-login, which crashes AdminShell with
104
+ // "Rendered more hooks than during the previous render." (caught by the
105
+ // e2e auth.spec.ts → login redirects to dashboard test).
106
+ const collectionMap = useMemo(() => {
107
+ const map = new Map<string, { slug: string; type?: string }>()
108
+ if (config?.collections) {
109
+ for (const c of Object.values(
110
+ config.collections as Record<string, { slug: string; type?: string }>,
111
+ )) {
112
+ if (c?.slug) map.set(c.slug, c)
113
+ }
114
+ }
115
+ if (map.size === 0) {
116
+ map.set('pages', { slug: 'pages', type: 'page' })
117
+ map.set('posts', { slug: 'posts' })
118
+ }
119
+ return map
120
+ }, [config])
79
121
 
80
122
  if (setupRequired && onSetupComplete) {
81
- return <SetupWizard onComplete={onSetupComplete} siteName={config?.admin?.branding?.name ?? 'Actuate CMS'} />;
123
+ return (
124
+ <SetupWizard
125
+ onComplete={onSetupComplete}
126
+ siteName={config?.admin?.branding?.name ?? 'Actuate CMS'}
127
+ />
128
+ )
82
129
  }
83
130
 
84
131
  if (!session && !setupRequired) {
85
132
  if (matchRoute('/forgot-password')) {
86
- return <ForgotPassword onNavigate={navigate} />;
133
+ return <ForgotPassword onNavigate={navigate} />
87
134
  }
88
135
 
89
- const resetMatch = matchRoute('/reset-password');
136
+ const resetMatch = matchRoute('/reset-password')
90
137
  if (resetMatch) {
91
- const params = new URLSearchParams(typeof window !== 'undefined' ? window.location.search : '');
92
- return <ResetPassword onNavigate={navigate} token={params.get('token')} />;
138
+ const params = new URLSearchParams(
139
+ typeof window !== 'undefined' ? window.location.search : '',
140
+ )
141
+ return <ResetPassword onNavigate={navigate} token={params.get('token')} />
93
142
  }
94
143
 
95
144
  if (onLogin) {
96
- return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig} />;
145
+ return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig} />
97
146
  }
98
147
  return (
99
148
  <div className="min-h-screen flex items-center justify-center bg-background">
@@ -102,32 +151,12 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
102
151
  <p className="text-sm text-muted-foreground">Please log in to access the admin panel.</p>
103
152
  </div>
104
153
  </div>
105
- );
154
+ )
106
155
  }
107
156
 
108
- // Map of collection slug → definition. Used to:
109
- // 1. Decide which editor (PageBuilder vs DocumentEdit) to render based
110
- // on `collection.type === 'page'`.
111
- // 2. Skip collections that collide with reserved admin paths so a
112
- // consumer-defined collection named `users` can't hijack the Users
113
- // view (or vice versa).
114
- const collectionMap = useMemo(() => {
115
- const map = new Map<string, { slug: string; type?: string }>();
116
- if (config?.collections) {
117
- for (const c of Object.values(config.collections as Record<string, { slug: string; type?: string }>)) {
118
- if (c?.slug) map.set(c.slug, c);
119
- }
120
- }
121
- if (map.size === 0) {
122
- map.set('pages', { slug: 'pages', type: 'page' });
123
- map.set('posts', { slug: 'posts' });
124
- }
125
- return map;
126
- }, [config]);
127
-
128
157
  function renderView() {
129
158
  if (matchRoute('/')) {
130
- return <Dashboard config={config} session={session} onNavigate={navigate} />;
159
+ return <Dashboard config={config} session={session} onNavigate={navigate} />
131
160
  }
132
161
 
133
162
  // Reserved admin routes — must match BEFORE iterating collection slugs
@@ -135,122 +164,165 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
135
164
  // a collection slugged `media`, `users`, or `settings`).
136
165
 
137
166
  if (matchRoute('/media')) {
138
- return <MediaBrowser onNavigate={navigate} />;
167
+ return <MediaBrowser onNavigate={navigate} />
139
168
  }
140
169
 
141
170
  if (matchRoute('/forms/new')) {
142
- return <FormEditor onNavigate={navigate} />;
171
+ return <FormEditor onNavigate={navigate} />
143
172
  }
144
- const formEdit = matchRoute('/forms/:id/edit');
173
+ const formEdit = matchRoute('/forms/:id/edit')
145
174
  if (formEdit?.id) {
146
- return <FormEditor formId={formEdit.id} onNavigate={navigate} />;
175
+ return <FormEditor formId={formEdit.id} onNavigate={navigate} />
147
176
  }
148
- const formSubmissions = matchRoute('/forms/:id/submissions');
177
+ const formSubmissions = matchRoute('/forms/:id/submissions')
149
178
  if (formSubmissions?.id) {
150
- return <FormSubmissions formId={formSubmissions.id} onNavigate={navigate} />;
179
+ return <FormSubmissions formId={formSubmissions.id} onNavigate={navigate} />
151
180
  }
152
181
  if (matchRoute('/forms')) {
153
- return <Forms onNavigate={navigate} />;
182
+ return <Forms onNavigate={navigate} />
154
183
  }
155
184
 
156
185
  if (matchRoute('/seo/redirects')) {
157
- return <SEO onNavigate={navigate} initialTab="redirects" />;
186
+ return <SEO onNavigate={navigate} initialTab="redirects" />
158
187
  }
159
188
  if (matchRoute('/seo/canonicals')) {
160
- return <SEO onNavigate={navigate} initialTab="canonicals" />;
189
+ return <SEO onNavigate={navigate} initialTab="canonicals" />
161
190
  }
162
191
  if (matchRoute('/seo/links')) {
163
- return <SEO onNavigate={navigate} initialTab="links" />;
192
+ return <SEO onNavigate={navigate} initialTab="links" />
164
193
  }
165
194
  if (matchRoute('/seo')) {
166
- return <SEO onNavigate={navigate} initialTab="pages" />;
195
+ return <SEO onNavigate={navigate} initialTab="pages" />
167
196
  }
168
197
 
169
198
  if (matchRoute('/script-tags/new')) {
170
- return <ScriptTagEditor onNavigate={navigate} />;
199
+ return <ScriptTagEditor onNavigate={navigate} />
171
200
  }
172
- const scriptTagEdit = matchRoute('/script-tags/:id');
201
+ const scriptTagEdit = matchRoute('/script-tags/:id')
173
202
  if (scriptTagEdit?.id) {
174
- return <ScriptTagEditor tagId={scriptTagEdit.id} onNavigate={navigate} />;
203
+ return <ScriptTagEditor tagId={scriptTagEdit.id} onNavigate={navigate} />
175
204
  }
176
205
  if (matchRoute('/script-tags')) {
177
- return <ScriptTags onNavigate={navigate} />;
206
+ return <ScriptTags onNavigate={navigate} />
178
207
  }
179
208
 
180
209
  if (matchRoute('/saved-sections')) {
181
- return <SavedSections onNavigate={navigate} config={config} />;
210
+ return <SavedSections onNavigate={navigate} config={config} />
182
211
  }
183
212
 
184
213
  if (matchRoute('/page-templates')) {
185
- return <PageTemplates onNavigate={navigate} />;
214
+ return <PageTemplates onNavigate={navigate} />
186
215
  }
187
216
 
188
217
  if (matchRoute('/users')) {
189
- return <Users onNavigate={navigate} />;
218
+ return <Users onNavigate={navigate} />
190
219
  }
191
220
 
192
221
  if (matchRoute('/settings')) {
193
- return <Settings onNavigate={navigate} config={config} />;
222
+ return <Settings onNavigate={navigate} config={config} />
194
223
  }
195
224
 
196
225
  // Page Builder routes — explicit /page-builder/* takes precedence over
197
226
  // the collection-derived routing below, but we ALSO route a collection
198
227
  // declared as `type: 'page'` through the Page Builder by default.
199
- const pageBuilderNew = matchRoute('/page-builder/new');
228
+ const pageBuilderNew = matchRoute('/page-builder/new')
200
229
  if (pageBuilderNew) {
201
- return <PageBuilder collectionSlug="pages" config={config} onNavigate={navigate} />;
230
+ return <PageBuilder collectionSlug="pages" config={config} onNavigate={navigate} />
202
231
  }
203
232
 
204
- const pageBuilderEdit = matchRoute('/page-builder/:id');
233
+ const pageBuilderEdit = matchRoute('/page-builder/:id')
205
234
  if (pageBuilderEdit?.id) {
206
- return <PageBuilder documentId={pageBuilderEdit.id} collectionSlug="pages" config={config} onNavigate={navigate} />;
235
+ return (
236
+ <PageBuilder
237
+ documentId={pageBuilderEdit.id}
238
+ collectionSlug="pages"
239
+ config={config}
240
+ onNavigate={navigate}
241
+ />
242
+ )
207
243
  }
208
244
 
209
245
  const RESERVED_SLUGS = new Set([
210
- 'media', 'forms', 'seo', 'script-tags', 'saved-sections',
211
- 'page-templates', 'users', 'settings', 'page-builder', 'collections',
212
- ]);
246
+ 'media',
247
+ 'forms',
248
+ 'seo',
249
+ 'script-tags',
250
+ 'saved-sections',
251
+ 'page-templates',
252
+ 'users',
253
+ 'settings',
254
+ 'page-builder',
255
+ 'collections',
256
+ ])
213
257
 
214
258
  for (const [slug, def] of collectionMap) {
215
- if (RESERVED_SLUGS.has(slug)) continue;
259
+ if (RESERVED_SLUGS.has(slug)) continue
216
260
 
217
- const isPageType = def.type === 'page';
218
- const newMatch = matchRoute(`/${slug}/new`);
261
+ const isPageType = def.type === 'page'
262
+ const newMatch = matchRoute(`/${slug}/new`)
219
263
  if (newMatch) {
220
- return isPageType
221
- ? <PageBuilder collectionSlug={slug} config={config} onNavigate={navigate} />
222
- : <DocumentEdit collectionSlug={slug} config={config} />;
264
+ return isPageType ? (
265
+ <PageBuilder collectionSlug={slug} config={config} onNavigate={navigate} />
266
+ ) : (
267
+ <DocumentEdit collectionSlug={slug} config={config} />
268
+ )
223
269
  }
224
- const editMatch = matchRoute(`/${slug}/:id`);
270
+ const editMatch = matchRoute(`/${slug}/:id`)
225
271
  if (editMatch?.id) {
226
- return isPageType
227
- ? <PageBuilder documentId={editMatch.id} collectionSlug={slug} config={config} onNavigate={navigate} />
228
- : <DocumentEdit collectionSlug={slug} documentId={editMatch.id} config={config} />;
272
+ return isPageType ? (
273
+ <PageBuilder
274
+ documentId={editMatch.id}
275
+ collectionSlug={slug}
276
+ config={config}
277
+ onNavigate={navigate}
278
+ />
279
+ ) : (
280
+ <DocumentEdit collectionSlug={slug} documentId={editMatch.id} config={config} />
281
+ )
229
282
  }
230
283
  if (matchRoute(`/${slug}`)) {
231
- return <CollectionList collectionSlug={slug} config={config} onNavigate={navigate} />;
284
+ return <CollectionList collectionSlug={slug} config={config} onNavigate={navigate} />
232
285
  }
233
286
  }
234
287
 
235
- const newCollMatch = matchRoute('/collections/:slug/new');
288
+ const newCollMatch = matchRoute('/collections/:slug/new')
236
289
  if (newCollMatch?.slug) {
237
- const def = collectionMap.get(newCollMatch.slug);
238
- return def?.type === 'page'
239
- ? <PageBuilder collectionSlug={newCollMatch.slug} config={config} onNavigate={navigate} />
240
- : <DocumentEdit collectionSlug={newCollMatch.slug} config={config} />;
290
+ const def = collectionMap.get(newCollMatch.slug)
291
+ return def?.type === 'page' ? (
292
+ <PageBuilder collectionSlug={newCollMatch.slug} config={config} onNavigate={navigate} />
293
+ ) : (
294
+ <DocumentEdit collectionSlug={newCollMatch.slug} config={config} />
295
+ )
241
296
  }
242
297
 
243
- const editCollMatch = matchRoute('/collections/:slug/:id');
298
+ const editCollMatch = matchRoute('/collections/:slug/:id')
244
299
  if (editCollMatch?.slug && editCollMatch.id) {
245
- const def = collectionMap.get(editCollMatch.slug);
246
- return def?.type === 'page'
247
- ? <PageBuilder documentId={editCollMatch.id} collectionSlug={editCollMatch.slug} config={config} onNavigate={navigate} />
248
- : <DocumentEdit collectionSlug={editCollMatch.slug} documentId={editCollMatch.id} config={config} />;
249
- }
250
-
251
- const collectionMatch = matchRoute('/collections/:slug');
300
+ const def = collectionMap.get(editCollMatch.slug)
301
+ return def?.type === 'page' ? (
302
+ <PageBuilder
303
+ documentId={editCollMatch.id}
304
+ collectionSlug={editCollMatch.slug}
305
+ config={config}
306
+ onNavigate={navigate}
307
+ />
308
+ ) : (
309
+ <DocumentEdit
310
+ collectionSlug={editCollMatch.slug}
311
+ documentId={editCollMatch.id}
312
+ config={config}
313
+ />
314
+ )
315
+ }
316
+
317
+ const collectionMatch = matchRoute('/collections/:slug')
252
318
  if (collectionMatch?.slug) {
253
- return <CollectionList collectionSlug={collectionMatch.slug} config={config} onNavigate={navigate} />;
319
+ return (
320
+ <CollectionList
321
+ collectionSlug={collectionMatch.slug}
322
+ config={config}
323
+ onNavigate={navigate}
324
+ />
325
+ )
254
326
  }
255
327
 
256
328
  return (
@@ -264,24 +336,24 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
264
336
  Back to Dashboard
265
337
  </button>
266
338
  </div>
267
- );
339
+ )
268
340
  }
269
341
 
270
342
  return (
271
343
  <Layout config={config} session={session} currentPath={currentPath} onNavigate={navigate}>
272
- <ErrorBoundary>
273
- {renderView()}
274
- </ErrorBoundary>
344
+ <ErrorBoundary>{renderView()}</ErrorBoundary>
275
345
  {shortcutHelpOpen && <ShortcutHelp onClose={() => setShortcutHelpOpen(false)} />}
276
346
  </Layout>
277
- );
347
+ )
278
348
  }
279
349
 
280
350
  function ShortcutHelp({ onClose }: { onClose: () => void }) {
281
351
  return (
282
352
  <div
283
353
  className="fixed inset-0 z-100 flex items-center justify-center bg-black/50"
284
- onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
354
+ onClick={(e) => {
355
+ if (e.target === e.currentTarget) onClose()
356
+ }}
285
357
  >
286
358
  <div className="bg-card text-card-foreground rounded-xl shadow-2xl border border-border p-6 max-w-sm w-full mx-4">
287
359
  <h3 className="text-lg font-semibold mb-4">Keyboard Shortcuts</h3>
@@ -306,86 +378,86 @@ function ShortcutHelp({ onClose }: { onClose: () => void }) {
306
378
  </button>
307
379
  </div>
308
380
  </div>
309
- );
381
+ )
310
382
  }
311
383
 
312
384
  function useBranding(config: any) {
313
- const originalFaviconRef = useRef<string | null>(null);
314
- const originalTitleRef = useRef<string | null>(null);
315
- const injectedLinkRef = useRef<HTMLLinkElement | null>(null);
385
+ const originalFaviconRef = useRef<string | null>(null)
386
+ const originalTitleRef = useRef<string | null>(null)
387
+ const injectedLinkRef = useRef<HTMLLinkElement | null>(null)
316
388
 
317
389
  useEffect(() => {
318
- const branding = config?.admin?.branding;
319
- if (!branding) return;
390
+ const branding = config?.admin?.branding
391
+ if (!branding) return
320
392
 
321
393
  // --- Favicon ---
322
394
  if (branding.favicon) {
323
- const existing = document.querySelector<HTMLLinkElement>('link[rel="icon"]');
324
- originalFaviconRef.current = existing?.href ?? null;
395
+ const existing = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
396
+ originalFaviconRef.current = existing?.href ?? null
325
397
 
326
398
  if (existing) {
327
- existing.href = branding.favicon;
399
+ existing.href = branding.favicon
328
400
  } else {
329
- const link = document.createElement('link');
330
- link.rel = 'icon';
331
- link.href = branding.favicon;
332
- document.head.appendChild(link);
333
- injectedLinkRef.current = link;
401
+ const link = document.createElement('link')
402
+ link.rel = 'icon'
403
+ link.href = branding.favicon
404
+ document.head.appendChild(link)
405
+ injectedLinkRef.current = link
334
406
  }
335
407
  }
336
408
 
337
409
  // --- Document title ---
338
- originalTitleRef.current = document.title;
410
+ originalTitleRef.current = document.title
339
411
  if (branding.title) {
340
- document.title = branding.title;
412
+ document.title = branding.title
341
413
  } else if (branding.name) {
342
- document.title = `${branding.name} Admin`;
414
+ document.title = `${branding.name} Admin`
343
415
  }
344
416
 
345
417
  // --- Primary color ---
346
- const adminEl = document.querySelector<HTMLElement>('.actuate-admin');
418
+ const adminEl = document.querySelector<HTMLElement>('.actuate-admin')
347
419
  if (branding.primaryColor && adminEl) {
348
- adminEl.style.setProperty('--primary', branding.primaryColor);
349
- adminEl.style.setProperty('--sidebar-primary', branding.primaryColor);
420
+ adminEl.style.setProperty('--primary', branding.primaryColor)
421
+ adminEl.style.setProperty('--sidebar-primary', branding.primaryColor)
350
422
  }
351
423
 
352
424
  return () => {
353
425
  // Restore favicon
354
426
  if (branding.favicon) {
355
- const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]');
427
+ const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
356
428
  if (link && originalFaviconRef.current) {
357
- link.href = originalFaviconRef.current;
429
+ link.href = originalFaviconRef.current
358
430
  }
359
431
  if (injectedLinkRef.current) {
360
- injectedLinkRef.current.remove();
361
- injectedLinkRef.current = null;
432
+ injectedLinkRef.current.remove()
433
+ injectedLinkRef.current = null
362
434
  }
363
435
  }
364
436
 
365
437
  // Restore title
366
438
  if (originalTitleRef.current !== null) {
367
- document.title = originalTitleRef.current;
439
+ document.title = originalTitleRef.current
368
440
  }
369
441
 
370
442
  // Remove primary color override
371
443
  if (branding.primaryColor && adminEl) {
372
- adminEl.style.removeProperty('--primary');
373
- adminEl.style.removeProperty('--sidebar-primary');
444
+ adminEl.style.removeProperty('--primary')
445
+ adminEl.style.removeProperty('--sidebar-primary')
374
446
  }
375
- };
376
- }, [config]);
447
+ }
448
+ }, [config])
377
449
  }
378
450
 
379
451
  function useAdminPageTitle(config: any, currentPath: string) {
380
452
  useEffect(() => {
381
- const branding = config?.admin?.branding;
382
- const baseName = branding?.title ?? (branding?.name ? `${branding.name} Admin` : null);
383
- if (!baseName) return;
384
-
385
- const segment = currentPath === '/' ? 'Dashboard' : currentPath.split('/').filter(Boolean)[0];
386
- const pageName = segment ? segment.charAt(0).toUpperCase() + segment.slice(1) : 'Dashboard';
387
- document.title = `${pageName} — ${baseName}`;
388
- }, [config, currentPath]);
453
+ const branding = config?.admin?.branding
454
+ const baseName = branding?.title ?? (branding?.name ? `${branding.name} Admin` : null)
455
+ if (!baseName) return
456
+
457
+ const segment = currentPath === '/' ? 'Dashboard' : currentPath.split('/').filter(Boolean)[0]
458
+ const pageName = segment ? segment.charAt(0).toUpperCase() + segment.slice(1) : 'Dashboard'
459
+ document.title = `${pageName} — ${baseName}`
460
+ }, [config, currentPath])
389
461
  }
390
462
 
391
463
  const ISOLATION_STYLE: React.CSSProperties = {
@@ -394,10 +466,10 @@ const ISOLATION_STYLE: React.CSSProperties = {
394
466
  zIndex: 50,
395
467
  overflow: 'auto',
396
468
  isolation: 'isolate',
397
- };
469
+ }
398
470
 
399
471
  export function AdminRoot(props: AdminRootProps) {
400
- const defaultDarkMode = props.config?.admin?.branding?.darkMode;
472
+ const defaultDarkMode = props.config?.admin?.branding?.darkMode
401
473
 
402
474
  return (
403
475
  <div style={ISOLATION_STYLE} className="actuate-admin">
@@ -407,5 +479,5 @@ export function AdminRoot(props: AdminRootProps) {
407
479
  </LocaleProvider>
408
480
  </ThemeProvider>
409
481
  </div>
410
- );
482
+ )
411
483
  }