@actuate-media/cms-admin 0.7.3 → 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 (435) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +95 -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/actuate-admin.css +1 -1
  10. package/dist/components/Breadcrumbs.d.ts.map +1 -1
  11. package/dist/components/Breadcrumbs.js +2 -4
  12. package/dist/components/Breadcrumbs.js.map +1 -1
  13. package/dist/components/CommandPalette.d.ts.map +1 -1
  14. package/dist/components/CommandPalette.js +7 -3
  15. package/dist/components/CommandPalette.js.map +1 -1
  16. package/dist/components/ContentOverviewChart.d.ts.map +1 -1
  17. package/dist/components/ContentOverviewChart.js.map +1 -1
  18. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  19. package/dist/components/ErrorBoundary.js.map +1 -1
  20. package/dist/components/FocalPointPicker.d.ts.map +1 -1
  21. package/dist/components/FocalPointPicker.js +4 -2
  22. package/dist/components/FocalPointPicker.js.map +1 -1
  23. package/dist/components/FolderTree.d.ts.map +1 -1
  24. package/dist/components/FolderTree.js +18 -10
  25. package/dist/components/FolderTree.js.map +1 -1
  26. package/dist/components/LivePreview.d.ts +1 -1
  27. package/dist/components/LivePreview.d.ts.map +1 -1
  28. package/dist/components/LivePreview.js +6 -2
  29. package/dist/components/LivePreview.js.map +1 -1
  30. package/dist/components/LocaleProvider.d.ts.map +1 -1
  31. package/dist/components/LocaleProvider.js.map +1 -1
  32. package/dist/components/LocaleSwitcher.d.ts.map +1 -1
  33. package/dist/components/LocaleSwitcher.js +1 -1
  34. package/dist/components/LocaleSwitcher.js.map +1 -1
  35. package/dist/components/MediaPickerModal.d.ts.map +1 -1
  36. package/dist/components/MediaPickerModal.js.map +1 -1
  37. package/dist/components/PresenceIndicator.d.ts.map +1 -1
  38. package/dist/components/PresenceIndicator.js +5 -2
  39. package/dist/components/PresenceIndicator.js.map +1 -1
  40. package/dist/components/SEOPanel.d.ts +1 -1
  41. package/dist/components/SEOPanel.d.ts.map +1 -1
  42. package/dist/components/SEOPanel.js +110 -24
  43. package/dist/components/SEOPanel.js.map +1 -1
  44. package/dist/components/SEOPerformance.d.ts.map +1 -1
  45. package/dist/components/SEOPerformance.js +2 -2
  46. package/dist/components/SEOPerformance.js.map +1 -1
  47. package/dist/components/ThemeProvider.d.ts.map +1 -1
  48. package/dist/components/ThemeProvider.js.map +1 -1
  49. package/dist/components/TipTapEditor.d.ts.map +1 -1
  50. package/dist/components/TipTapEditor.js +5 -1
  51. package/dist/components/TipTapEditor.js.map +1 -1
  52. package/dist/components/VersionHistory.d.ts +1 -1
  53. package/dist/components/VersionHistory.d.ts.map +1 -1
  54. package/dist/components/VersionHistory.js +1 -1
  55. package/dist/components/VersionHistory.js.map +1 -1
  56. package/dist/components/ui/Avatar.d.ts.map +1 -1
  57. package/dist/components/ui/Avatar.js.map +1 -1
  58. package/dist/components/ui/Badge.d.ts.map +1 -1
  59. package/dist/components/ui/Badge.js.map +1 -1
  60. package/dist/components/ui/Button.d.ts.map +1 -1
  61. package/dist/components/ui/Button.js.map +1 -1
  62. package/dist/components/ui/CommandPalette.d.ts.map +1 -1
  63. package/dist/components/ui/CommandPalette.js +8 -2
  64. package/dist/components/ui/CommandPalette.js.map +1 -1
  65. package/dist/components/ui/ConfirmDialog.d.ts.map +1 -1
  66. package/dist/components/ui/ConfirmDialog.js.map +1 -1
  67. package/dist/components/ui/DataTable.d.ts.map +1 -1
  68. package/dist/components/ui/DataTable.js +1 -3
  69. package/dist/components/ui/DataTable.js.map +1 -1
  70. package/dist/components/ui/EmptyState.d.ts.map +1 -1
  71. package/dist/components/ui/EmptyState.js +1 -1
  72. package/dist/components/ui/EmptyState.js.map +1 -1
  73. package/dist/components/ui/Modal.d.ts.map +1 -1
  74. package/dist/components/ui/Modal.js.map +1 -1
  75. package/dist/components/ui/Pagination.d.ts +1 -1
  76. package/dist/components/ui/Pagination.d.ts.map +1 -1
  77. package/dist/components/ui/Pagination.js +7 -2
  78. package/dist/components/ui/Pagination.js.map +1 -1
  79. package/dist/components/ui/SearchInput.d.ts.map +1 -1
  80. package/dist/components/ui/SearchInput.js.map +1 -1
  81. package/dist/components/ui/Skeleton.d.ts.map +1 -1
  82. package/dist/components/ui/Skeleton.js.map +1 -1
  83. package/dist/components/ui/Toast.d.ts.map +1 -1
  84. package/dist/components/ui/Toast.js.map +1 -1
  85. package/dist/components/ui/index.d.ts.map +1 -1
  86. package/dist/components/ui/index.js.map +1 -1
  87. package/dist/fields/ArrayField.d.ts.map +1 -1
  88. package/dist/fields/ArrayField.js +1 -1
  89. package/dist/fields/ArrayField.js.map +1 -1
  90. package/dist/fields/BlockBuilderField.d.ts.map +1 -1
  91. package/dist/fields/BlockBuilderField.js +7 -7
  92. package/dist/fields/BlockBuilderField.js.map +1 -1
  93. package/dist/fields/DateField.d.ts.map +1 -1
  94. package/dist/fields/DateField.js +1 -1
  95. package/dist/fields/DateField.js.map +1 -1
  96. package/dist/fields/FieldRenderer.d.ts.map +1 -1
  97. package/dist/fields/FieldRenderer.js.map +1 -1
  98. package/dist/fields/GroupField.d.ts.map +1 -1
  99. package/dist/fields/GroupField.js +1 -1
  100. package/dist/fields/GroupField.js.map +1 -1
  101. package/dist/fields/MediaField.d.ts.map +1 -1
  102. package/dist/fields/MediaField.js +1 -1
  103. package/dist/fields/MediaField.js.map +1 -1
  104. package/dist/fields/NavBuilderField.d.ts.map +1 -1
  105. package/dist/fields/NavBuilderField.js +2 -5
  106. package/dist/fields/NavBuilderField.js.map +1 -1
  107. package/dist/fields/NumberField.d.ts +1 -1
  108. package/dist/fields/NumberField.d.ts.map +1 -1
  109. package/dist/fields/NumberField.js +2 -2
  110. package/dist/fields/NumberField.js.map +1 -1
  111. package/dist/fields/RelationshipField.d.ts.map +1 -1
  112. package/dist/fields/RelationshipField.js +7 -3
  113. package/dist/fields/RelationshipField.js.map +1 -1
  114. package/dist/fields/RichTextField.d.ts +1 -1
  115. package/dist/fields/RichTextField.d.ts.map +1 -1
  116. package/dist/fields/RichTextField.js +2 -2
  117. package/dist/fields/RichTextField.js.map +1 -1
  118. package/dist/fields/SelectField.d.ts.map +1 -1
  119. package/dist/fields/SelectField.js +9 -7
  120. package/dist/fields/SelectField.js.map +1 -1
  121. package/dist/fields/SlugField.d.ts.map +1 -1
  122. package/dist/fields/SlugField.js +1 -1
  123. package/dist/fields/SlugField.js.map +1 -1
  124. package/dist/fields/TextField.d.ts +1 -1
  125. package/dist/fields/TextField.d.ts.map +1 -1
  126. package/dist/fields/TextField.js +2 -2
  127. package/dist/fields/TextField.js.map +1 -1
  128. package/dist/fields/ToggleField.d.ts.map +1 -1
  129. package/dist/fields/ToggleField.js +1 -1
  130. package/dist/fields/ToggleField.js.map +1 -1
  131. package/dist/fields/block-types.d.ts.map +1 -1
  132. package/dist/fields/block-types.js +28 -8
  133. package/dist/fields/block-types.js.map +1 -1
  134. package/dist/fields/index.d.ts.map +1 -1
  135. package/dist/fields/index.js.map +1 -1
  136. package/dist/hooks/useBuilderState.d.ts.map +1 -1
  137. package/dist/hooks/useBuilderState.js.map +1 -1
  138. package/dist/hooks/useContentLock.d.ts.map +1 -1
  139. package/dist/hooks/useContentLock.js.map +1 -1
  140. package/dist/hooks/useDebounce.js.map +1 -1
  141. package/dist/hooks/useKeyboardShortcuts.d.ts.map +1 -1
  142. package/dist/hooks/useKeyboardShortcuts.js.map +1 -1
  143. package/dist/index.d.ts +2 -2
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js.map +1 -1
  146. package/dist/layout/Header.d.ts.map +1 -1
  147. package/dist/layout/Header.js.map +1 -1
  148. package/dist/layout/Layout.d.ts.map +1 -1
  149. package/dist/layout/Layout.js.map +1 -1
  150. package/dist/layout/Sidebar.d.ts +1 -1
  151. package/dist/layout/Sidebar.d.ts.map +1 -1
  152. package/dist/layout/Sidebar.js +5 -8
  153. package/dist/layout/Sidebar.js.map +1 -1
  154. package/dist/lib/api.d.ts.map +1 -1
  155. package/dist/lib/api.js +33 -4
  156. package/dist/lib/api.js.map +1 -1
  157. package/dist/lib/search.d.ts.map +1 -1
  158. package/dist/lib/search.js +3 -5
  159. package/dist/lib/search.js.map +1 -1
  160. package/dist/lib/useApiData.d.ts.map +1 -1
  161. package/dist/lib/useApiData.js.map +1 -1
  162. package/dist/lib/utils.d.ts.map +1 -1
  163. package/dist/lib/utils.js.map +1 -1
  164. package/dist/router/index.d.ts.map +1 -1
  165. package/dist/router/index.js +1 -3
  166. package/dist/router/index.js.map +1 -1
  167. package/dist/views/CollectionList.d.ts.map +1 -1
  168. package/dist/views/CollectionList.js +56 -17
  169. package/dist/views/CollectionList.js.map +1 -1
  170. package/dist/views/Dashboard.d.ts.map +1 -1
  171. package/dist/views/Dashboard.js +26 -13
  172. package/dist/views/Dashboard.js.map +1 -1
  173. package/dist/views/DocumentEdit.d.ts +1 -1
  174. package/dist/views/DocumentEdit.d.ts.map +1 -1
  175. package/dist/views/DocumentEdit.js +33 -15
  176. package/dist/views/DocumentEdit.js.map +1 -1
  177. package/dist/views/ForgotPassword.d.ts.map +1 -1
  178. package/dist/views/ForgotPassword.js.map +1 -1
  179. package/dist/views/FormEditor.d.ts.map +1 -1
  180. package/dist/views/FormEditor.js +8 -2
  181. package/dist/views/FormEditor.js.map +1 -1
  182. package/dist/views/FormSubmissions.d.ts.map +1 -1
  183. package/dist/views/FormSubmissions.js +6 -6
  184. package/dist/views/FormSubmissions.js.map +1 -1
  185. package/dist/views/Forms.d.ts.map +1 -1
  186. package/dist/views/Forms.js.map +1 -1
  187. package/dist/views/Login.d.ts.map +1 -1
  188. package/dist/views/Login.js +5 -2
  189. package/dist/views/Login.js.map +1 -1
  190. package/dist/views/MediaBrowser.d.ts.map +1 -1
  191. package/dist/views/MediaBrowser.js +39 -19
  192. package/dist/views/MediaBrowser.js.map +1 -1
  193. package/dist/views/PageEditor.d.ts.map +1 -1
  194. package/dist/views/PageEditor.js.map +1 -1
  195. package/dist/views/Pages.d.ts.map +1 -1
  196. package/dist/views/Pages.js +20 -10
  197. package/dist/views/Pages.js.map +1 -1
  198. package/dist/views/PostEditor.d.ts.map +1 -1
  199. package/dist/views/PostEditor.js.map +1 -1
  200. package/dist/views/Posts.d.ts.map +1 -1
  201. package/dist/views/Posts.js +13 -7
  202. package/dist/views/Posts.js.map +1 -1
  203. package/dist/views/Redirects.d.ts.map +1 -1
  204. package/dist/views/Redirects.js +17 -5
  205. package/dist/views/Redirects.js.map +1 -1
  206. package/dist/views/ResetPassword.d.ts.map +1 -1
  207. package/dist/views/ResetPassword.js.map +1 -1
  208. package/dist/views/SEO.d.ts.map +1 -1
  209. package/dist/views/SEO.js +39 -16
  210. package/dist/views/SEO.js.map +1 -1
  211. package/dist/views/ScriptTagEditor.d.ts.map +1 -1
  212. package/dist/views/ScriptTagEditor.js +2 -1
  213. package/dist/views/ScriptTagEditor.js.map +1 -1
  214. package/dist/views/ScriptTags.d.ts.map +1 -1
  215. package/dist/views/ScriptTags.js.map +1 -1
  216. package/dist/views/Settings.d.ts.map +1 -1
  217. package/dist/views/Settings.js +38 -11
  218. package/dist/views/Settings.js.map +1 -1
  219. package/dist/views/SetupWizard.d.ts.map +1 -1
  220. package/dist/views/SetupWizard.js.map +1 -1
  221. package/dist/views/Users.d.ts.map +1 -1
  222. package/dist/views/Users.js +5 -3
  223. package/dist/views/Users.js.map +1 -1
  224. package/dist/views/page-builder/AIBlockAssist.d.ts.map +1 -1
  225. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  226. package/dist/views/page-builder/AIBlockAssist.js.map +1 -1
  227. package/dist/views/page-builder/AIGenerateDialog.d.ts.map +1 -1
  228. package/dist/views/page-builder/AIGenerateDialog.js +4 -1
  229. package/dist/views/page-builder/AIGenerateDialog.js.map +1 -1
  230. package/dist/views/page-builder/BlockEditor.d.ts.map +1 -1
  231. package/dist/views/page-builder/BlockEditor.js +94 -3
  232. package/dist/views/page-builder/BlockEditor.js.map +1 -1
  233. package/dist/views/page-builder/BlockPicker.d.ts.map +1 -1
  234. package/dist/views/page-builder/BlockPicker.js.map +1 -1
  235. package/dist/views/page-builder/BottomBar.d.ts.map +1 -1
  236. package/dist/views/page-builder/BottomBar.js.map +1 -1
  237. package/dist/views/page-builder/BuilderToolbar.d.ts.map +1 -1
  238. package/dist/views/page-builder/BuilderToolbar.js.map +1 -1
  239. package/dist/views/page-builder/ContextPanel.d.ts.map +1 -1
  240. package/dist/views/page-builder/ContextPanel.js +4 -1
  241. package/dist/views/page-builder/ContextPanel.js.map +1 -1
  242. package/dist/views/page-builder/DesignScore.d.ts.map +1 -1
  243. package/dist/views/page-builder/DesignScore.js.map +1 -1
  244. package/dist/views/page-builder/NodeSettings.d.ts.map +1 -1
  245. package/dist/views/page-builder/NodeSettings.js +1 -1
  246. package/dist/views/page-builder/NodeSettings.js.map +1 -1
  247. package/dist/views/page-builder/PageBuilder.d.ts +1 -1
  248. package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
  249. package/dist/views/page-builder/PageBuilder.js +25 -3
  250. package/dist/views/page-builder/PageBuilder.js.map +1 -1
  251. package/dist/views/page-builder/PageSettings.d.ts.map +1 -1
  252. package/dist/views/page-builder/PageSettings.js.map +1 -1
  253. package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
  254. package/dist/views/page-builder/PageTemplates.js.map +1 -1
  255. package/dist/views/page-builder/SEOPanel.d.ts.map +1 -1
  256. package/dist/views/page-builder/SEOPanel.js +1 -3
  257. package/dist/views/page-builder/SEOPanel.js.map +1 -1
  258. package/dist/views/page-builder/SavedSections.d.ts.map +1 -1
  259. package/dist/views/page-builder/SavedSections.js +3 -7
  260. package/dist/views/page-builder/SavedSections.js.map +1 -1
  261. package/dist/views/page-builder/TemplatePicker.d.ts.map +1 -1
  262. package/dist/views/page-builder/TemplatePicker.js.map +1 -1
  263. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +1 -1
  264. package/dist/views/page-builder/block-renderers/CTAPreview.js +1 -1
  265. package/dist/views/page-builder/block-renderers/CTAPreview.js.map +1 -1
  266. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +1 -1
  267. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  268. package/dist/views/page-builder/block-renderers/CardsPreview.js.map +1 -1
  269. package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +1 -1
  270. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -5
  271. package/dist/views/page-builder/block-renderers/CodePreview.js.map +1 -1
  272. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +1 -1
  273. package/dist/views/page-builder/block-renderers/FAQPreview.js +4 -1
  274. package/dist/views/page-builder/block-renderers/FAQPreview.js.map +1 -1
  275. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +1 -1
  276. package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +1 -1
  277. package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +1 -1
  278. package/dist/views/page-builder/block-renderers/FormPreview.js +2 -2
  279. package/dist/views/page-builder/block-renderers/FormPreview.js.map +1 -1
  280. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +1 -1
  281. package/dist/views/page-builder/block-renderers/GalleryPreview.js +1 -3
  282. package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +1 -1
  283. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +1 -1
  284. package/dist/views/page-builder/block-renderers/HeroPreview.js.map +1 -1
  285. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +1 -1
  286. package/dist/views/page-builder/block-renderers/ImagePreview.js.map +1 -1
  287. package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +1 -1
  288. package/dist/views/page-builder/block-renderers/TextPreview.js +2 -6
  289. package/dist/views/page-builder/block-renderers/TextPreview.js.map +1 -1
  290. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +1 -1
  291. package/dist/views/page-builder/block-renderers/VideoPreview.js +2 -5
  292. package/dist/views/page-builder/block-renderers/VideoPreview.js.map +1 -1
  293. package/dist/views/page-builder/block-renderers/index.d.ts.map +1 -1
  294. package/dist/views/page-builder/block-renderers/index.js.map +1 -1
  295. package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +1 -1
  296. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -5
  297. package/dist/views/page-builder/canvas/BlockRenderer.js.map +1 -1
  298. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +1 -1
  299. package/dist/views/page-builder/canvas/BuilderCanvas.js.map +1 -1
  300. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +1 -1
  301. package/dist/views/page-builder/canvas/ColumnRenderer.js +1 -5
  302. package/dist/views/page-builder/canvas/ColumnRenderer.js.map +1 -1
  303. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +1 -1
  304. package/dist/views/page-builder/canvas/ContainerRenderer.js +1 -5
  305. package/dist/views/page-builder/canvas/ContainerRenderer.js.map +1 -1
  306. package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +1 -1
  307. package/dist/views/page-builder/canvas/RowRenderer.js +1 -5
  308. package/dist/views/page-builder/canvas/RowRenderer.js.map +1 -1
  309. package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +1 -1
  310. package/dist/views/page-builder/canvas/SectionRenderer.js +1 -5
  311. package/dist/views/page-builder/canvas/SectionRenderer.js.map +1 -1
  312. package/dist/views/page-builder/canvas/index.d.ts.map +1 -1
  313. package/dist/views/page-builder/canvas/index.js.map +1 -1
  314. package/package.json +2 -2
  315. package/src/AdminRoot.tsx +302 -177
  316. package/src/__tests__/lib/search.test.ts +60 -69
  317. package/src/__tests__/lib/utils.test.ts +12 -12
  318. package/src/__tests__/router/match-route.test.ts +24 -26
  319. package/src/__tests__/router/strip-base.test.ts +15 -15
  320. package/src/components/Breadcrumbs.tsx +27 -24
  321. package/src/components/CommandPalette.tsx +115 -99
  322. package/src/components/ContentOverviewChart.tsx +19 -14
  323. package/src/components/ErrorBoundary.tsx +13 -13
  324. package/src/components/FocalPointPicker.tsx +31 -20
  325. package/src/components/FolderTree.tsx +172 -139
  326. package/src/components/LivePreview.tsx +68 -41
  327. package/src/components/LocaleProvider.tsx +26 -20
  328. package/src/components/LocaleSwitcher.tsx +9 -11
  329. package/src/components/MediaPickerModal.tsx +46 -45
  330. package/src/components/PresenceIndicator.tsx +30 -27
  331. package/src/components/SEOPanel.tsx +378 -228
  332. package/src/components/SEOPerformance.tsx +52 -30
  333. package/src/components/ThemeProvider.tsx +46 -46
  334. package/src/components/TipTapEditor.tsx +60 -64
  335. package/src/components/VersionHistory.tsx +63 -52
  336. package/src/components/ui/Avatar.tsx +8 -8
  337. package/src/components/ui/Badge.tsx +7 -5
  338. package/src/components/ui/Button.tsx +24 -13
  339. package/src/components/ui/CommandPalette.tsx +56 -42
  340. package/src/components/ui/ConfirmDialog.tsx +14 -14
  341. package/src/components/ui/DataTable.tsx +37 -39
  342. package/src/components/ui/EmptyState.tsx +9 -11
  343. package/src/components/ui/Modal.tsx +21 -15
  344. package/src/components/ui/Pagination.tsx +34 -19
  345. package/src/components/ui/SearchInput.tsx +17 -7
  346. package/src/components/ui/Skeleton.tsx +7 -7
  347. package/src/components/ui/Toast.tsx +29 -22
  348. package/src/components/ui/index.ts +24 -24
  349. package/src/fields/ArrayField.tsx +43 -25
  350. package/src/fields/BlockBuilderField.tsx +80 -99
  351. package/src/fields/DateField.tsx +20 -12
  352. package/src/fields/FieldRenderer.tsx +34 -34
  353. package/src/fields/GroupField.tsx +8 -10
  354. package/src/fields/MediaField.tsx +8 -10
  355. package/src/fields/NavBuilderField.tsx +24 -25
  356. package/src/fields/NumberField.tsx +21 -14
  357. package/src/fields/RelationshipField.tsx +105 -91
  358. package/src/fields/RichTextField.tsx +16 -12
  359. package/src/fields/SelectField.tsx +42 -34
  360. package/src/fields/SlugField.tsx +29 -17
  361. package/src/fields/TextField.tsx +24 -16
  362. package/src/fields/ToggleField.tsx +7 -9
  363. package/src/fields/block-types.ts +50 -24
  364. package/src/fields/index.ts +17 -17
  365. package/src/hooks/useBuilderState.ts +260 -221
  366. package/src/hooks/useContentLock.ts +23 -20
  367. package/src/hooks/useDebounce.ts +7 -7
  368. package/src/hooks/useKeyboardShortcuts.ts +16 -16
  369. package/src/index.ts +69 -58
  370. package/src/layout/Header.tsx +21 -20
  371. package/src/layout/Layout.tsx +22 -24
  372. package/src/layout/Sidebar.tsx +107 -72
  373. package/src/lib/api.ts +58 -30
  374. package/src/lib/search.ts +30 -34
  375. package/src/lib/useApiData.ts +65 -62
  376. package/src/lib/utils.ts +3 -3
  377. package/src/router/index.ts +33 -35
  378. package/src/styles/build-input.css +2 -2
  379. package/src/styles/tailwind.css +1 -1
  380. package/src/styles/theme.css +7 -1
  381. package/src/views/CollectionList.tsx +275 -121
  382. package/src/views/Dashboard.tsx +164 -117
  383. package/src/views/DocumentEdit.tsx +298 -253
  384. package/src/views/ForgotPassword.tsx +27 -23
  385. package/src/views/FormEditor.tsx +165 -99
  386. package/src/views/FormSubmissions.tsx +261 -117
  387. package/src/views/Forms.tsx +56 -26
  388. package/src/views/Login.tsx +107 -84
  389. package/src/views/MediaBrowser.tsx +717 -523
  390. package/src/views/PageEditor.tsx +44 -46
  391. package/src/views/Pages.tsx +312 -149
  392. package/src/views/PostEditor.tsx +57 -51
  393. package/src/views/Posts.tsx +206 -74
  394. package/src/views/Redirects.tsx +173 -117
  395. package/src/views/ResetPassword.tsx +43 -32
  396. package/src/views/SEO.tsx +589 -160
  397. package/src/views/ScriptTagEditor.tsx +69 -69
  398. package/src/views/ScriptTags.tsx +54 -42
  399. package/src/views/Settings.tsx +430 -220
  400. package/src/views/SetupWizard.tsx +69 -46
  401. package/src/views/Users.tsx +154 -120
  402. package/src/views/page-builder/AIBlockAssist.tsx +21 -25
  403. package/src/views/page-builder/AIGenerateDialog.tsx +134 -127
  404. package/src/views/page-builder/BlockEditor.tsx +258 -81
  405. package/src/views/page-builder/BlockPicker.tsx +73 -88
  406. package/src/views/page-builder/BottomBar.tsx +15 -11
  407. package/src/views/page-builder/BuilderToolbar.tsx +32 -29
  408. package/src/views/page-builder/ContextPanel.tsx +57 -57
  409. package/src/views/page-builder/DesignScore.tsx +52 -59
  410. package/src/views/page-builder/NodeSettings.tsx +59 -59
  411. package/src/views/page-builder/PageBuilder.tsx +164 -146
  412. package/src/views/page-builder/PageSettings.tsx +16 -15
  413. package/src/views/page-builder/PageTemplates.tsx +23 -17
  414. package/src/views/page-builder/SEOPanel.tsx +90 -111
  415. package/src/views/page-builder/SavedSections.tsx +99 -105
  416. package/src/views/page-builder/TemplatePicker.tsx +44 -48
  417. package/src/views/page-builder/block-renderers/CTAPreview.tsx +11 -13
  418. package/src/views/page-builder/block-renderers/CardsPreview.tsx +13 -15
  419. package/src/views/page-builder/block-renderers/CodePreview.tsx +16 -16
  420. package/src/views/page-builder/block-renderers/FAQPreview.tsx +20 -23
  421. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +5 -5
  422. package/src/views/page-builder/block-renderers/FormPreview.tsx +9 -13
  423. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +22 -28
  424. package/src/views/page-builder/block-renderers/HeroPreview.tsx +17 -30
  425. package/src/views/page-builder/block-renderers/ImagePreview.tsx +12 -12
  426. package/src/views/page-builder/block-renderers/TextPreview.tsx +22 -22
  427. package/src/views/page-builder/block-renderers/VideoPreview.tsx +13 -18
  428. package/src/views/page-builder/block-renderers/index.ts +17 -17
  429. package/src/views/page-builder/canvas/BlockRenderer.tsx +19 -23
  430. package/src/views/page-builder/canvas/BuilderCanvas.tsx +17 -20
  431. package/src/views/page-builder/canvas/ColumnRenderer.tsx +22 -26
  432. package/src/views/page-builder/canvas/ContainerRenderer.tsx +20 -24
  433. package/src/views/page-builder/canvas/RowRenderer.tsx +19 -23
  434. package/src/views/page-builder/canvas/SectionRenderer.tsx +30 -34
  435. package/src/views/page-builder/canvas/index.ts +2 -2
@@ -1,17 +1,30 @@
1
- 'use client';
2
-
3
- import { Plus, Search, Trash2, SlidersHorizontal, Pencil, ArrowUpDown, ArrowUp, ArrowDown, Loader2, AlertTriangle, GripVertical, FolderInput } from 'lucide-react';
4
- import { useState, useMemo, useCallback } from 'react';
5
- import { toast } from 'sonner';
6
- import { sortByRelevance, type SortConfig, toggleSort } from '../lib/search.js';
7
- import { useApiData } from '../lib/useApiData.js';
8
- import { cmsApi } from '../lib/api.js';
9
- import { FolderTree, type FolderSelection } from '../components/FolderTree.js';
10
-
11
- type PageSortKey = 'title' | 'author' | 'template' | 'status' | 'date';
1
+ 'use client'
2
+
3
+ import {
4
+ Plus,
5
+ Search,
6
+ Trash2,
7
+ SlidersHorizontal,
8
+ Pencil,
9
+ ArrowUpDown,
10
+ ArrowUp,
11
+ ArrowDown,
12
+ Loader2,
13
+ AlertTriangle,
14
+ GripVertical,
15
+ FolderInput,
16
+ } from 'lucide-react'
17
+ import { useState, useMemo, useCallback } from 'react'
18
+ import { toast } from 'sonner'
19
+ import { sortByRelevance, type SortConfig, toggleSort } from '../lib/search.js'
20
+ import { useApiData } from '../lib/useApiData.js'
21
+ import { cmsApi } from '../lib/api.js'
22
+ import { FolderTree, type FolderSelection } from '../components/FolderTree.js'
23
+
24
+ type PageSortKey = 'title' | 'author' | 'template' | 'status' | 'date'
12
25
 
13
26
  export interface PagesProps {
14
- onNavigate?: (path: string) => void;
27
+ onNavigate?: (path: string) => void
15
28
  }
16
29
 
17
30
  const COLOR_PALETTE = [
@@ -23,177 +36,195 @@ const COLOR_PALETTE = [
23
36
  { bg: 'bg-teal-100', text: 'text-teal-700' },
24
37
  { bg: 'bg-indigo-100', text: 'text-indigo-700' },
25
38
  { bg: 'bg-rose-100', text: 'text-rose-700' },
26
- ];
39
+ ]
27
40
 
28
41
  function hashString(s: string): number {
29
- let hash = 0;
42
+ let hash = 0
30
43
  for (let i = 0; i < s.length; i++) {
31
- hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
44
+ hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0
32
45
  }
33
- return Math.abs(hash);
46
+ return Math.abs(hash)
34
47
  }
35
48
 
36
- const folderColorCache: Record<string, (typeof COLOR_PALETTE)[0]> = {};
49
+ const folderColorCache: Record<string, (typeof COLOR_PALETTE)[0]> = {}
37
50
 
38
51
  function getFolderColor(name: string) {
39
52
  if (!folderColorCache[name]) {
40
- folderColorCache[name] = COLOR_PALETTE[hashString(name) % COLOR_PALETTE.length]!;
53
+ folderColorCache[name] = COLOR_PALETTE[hashString(name) % COLOR_PALETTE.length]!
41
54
  }
42
- return folderColorCache[name]!;
55
+ return folderColorCache[name]!
43
56
  }
44
57
 
45
58
  function computeSeoScore(data: Record<string, unknown> | null | undefined): number {
46
- if (!data) return 0;
47
- let score = 0;
48
- if (data.metaTitle || data.seoTitle) score += 25;
49
- if (data.metaDescription || data.seoDescription) score += 25;
50
- if (data.canonical) score += 25;
51
- if (data.schemaType) score += 25;
52
- return score;
59
+ if (!data) return 0
60
+ let score = 0
61
+ if (data.metaTitle || data.seoTitle) score += 25
62
+ if (data.metaDescription || data.seoDescription) score += 25
63
+ if (data.canonical) score += 25
64
+ if (data.schemaType) score += 25
65
+ return score
53
66
  }
54
67
 
55
68
  function textValue(value: unknown): string {
56
- return String(value ?? '');
69
+ return String(value ?? '')
57
70
  }
58
71
 
59
72
  function SeoScoreBadge({ score }: { score: number }) {
60
- const color = score >= 80 ? 'bg-green-500' : score >= 60 ? 'bg-amber-500' : 'bg-red-500';
73
+ const color = score >= 80 ? 'bg-green-500' : score >= 60 ? 'bg-amber-500' : 'bg-red-500'
61
74
  return (
62
75
  <div className="flex items-center gap-1.5">
63
76
  <span className={`w-2.5 h-2.5 rounded-full ${color}`} />
64
77
  <span className="text-xs text-gray-600">{score}</span>
65
78
  </div>
66
- );
79
+ )
67
80
  }
68
81
 
69
82
  function FolderBadge({ name }: { name: string }) {
70
- const colors = getFolderColor(name);
83
+ const colors = getFolderColor(name)
71
84
  return (
72
- <span className={`inline-flex px-2 py-0.5 rounded text-xs font-medium ${colors.bg} ${colors.text}`}>
85
+ <span
86
+ className={`inline-flex px-2 py-0.5 rounded text-xs font-medium ${colors.bg} ${colors.text}`}
87
+ >
73
88
  {name}
74
89
  </span>
75
- );
90
+ )
76
91
  }
77
92
 
78
93
  function buildApiUrl(folderSel: FolderSelection): string {
79
- const base = '/collections/pages?pageSize=100';
94
+ const base = '/collections/pages?pageSize=100'
80
95
  if (folderSel.type === 'smart') {
81
- if (folderSel.smart === 'recent') return `${base}&sort=updatedAt&order=desc&pageSize=20`;
82
- if (folderSel.smart === 'uncategorized') return `${base}&folderId=none`;
83
- return base;
96
+ if (folderSel.smart === 'recent') return `${base}&sort=updatedAt&order=desc&pageSize=20`
97
+ if (folderSel.smart === 'uncategorized') return `${base}&folderId=none`
98
+ return base
84
99
  }
85
- return `${base}&folderId=${folderSel.folderId}`;
100
+ return `${base}&folderId=${folderSel.folderId}`
86
101
  }
87
102
 
88
103
  export function Pages({ onNavigate }: PagesProps) {
89
- const [folderSel, setFolderSel] = useState<FolderSelection>({ type: 'smart', smart: 'all' });
90
- const [sidebarOpen, setSidebarOpen] = useState(true);
104
+ const [folderSel, setFolderSel] = useState<FolderSelection>({ type: 'smart', smart: 'all' })
105
+ const [sidebarOpen, setSidebarOpen] = useState(true)
91
106
 
92
- const apiUrl = useMemo(() => buildApiUrl(folderSel), [folderSel]);
93
- const { data, loading, error, refetch } = useApiData<{ docs: any[]; total: number }>(apiUrl);
107
+ const apiUrl = useMemo(() => buildApiUrl(folderSel), [folderSel])
108
+ const { data, loading, error, refetch } = useApiData<{ docs: any[]; total: number }>(apiUrl)
94
109
 
95
- const allData = useApiData<{ docs: any[]; total: number }>('/collections/pages?pageSize=1');
96
- const uncatData = useApiData<{ docs: any[]; total: number }>('/collections/pages?pageSize=1&folderId=none');
110
+ const allData = useApiData<{ docs: any[]; total: number }>('/collections/pages?pageSize=1')
111
+ const uncatData = useApiData<{ docs: any[]; total: number }>(
112
+ '/collections/pages?pageSize=1&folderId=none',
113
+ )
97
114
 
98
- const [searchQuery, setSearchQuery] = useState('');
99
- const [filterStatus, setFilterStatus] = useState<string>('all');
100
- const [filterTemplate, setFilterTemplate] = useState<string>('all');
101
- const [selectedPages, setSelectedPages] = useState<number[]>([]);
102
- const [sortConfig, setSortConfig] = useState<SortConfig<PageSortKey> | null>(null);
115
+ const [searchQuery, setSearchQuery] = useState('')
116
+ const [filterStatus, setFilterStatus] = useState<string>('all')
117
+ const [filterTemplate, setFilterTemplate] = useState<string>('all')
118
+ const [selectedPages, setSelectedPages] = useState<number[]>([])
119
+ const [sortConfig, setSortConfig] = useState<SortConfig<PageSortKey> | null>(null)
103
120
 
104
- const pages = data?.docs ?? [];
105
- const totalCount = data?.total ?? pages.length;
121
+ const pages = data?.docs ?? []
122
+ const totalCount = data?.total ?? pages.length
106
123
 
107
124
  const filteredAndSorted = useMemo(() => {
108
125
  let results = pages.filter((page: any) => {
109
- const matchesSearch = textValue(page.title).toLowerCase().includes(searchQuery.toLowerCase()) ||
110
- textValue(page.author).toLowerCase().includes(searchQuery.toLowerCase());
111
- const matchesStatus = filterStatus === 'all' || textValue(page.status).toLowerCase() === filterStatus.toLowerCase();
112
- const matchesTemplate = filterTemplate === 'all' || textValue(page.template).toLowerCase() === filterTemplate.toLowerCase();
113
- return matchesSearch && matchesStatus && matchesTemplate;
114
- });
126
+ const matchesSearch =
127
+ textValue(page.title).toLowerCase().includes(searchQuery.toLowerCase()) ||
128
+ textValue(page.author).toLowerCase().includes(searchQuery.toLowerCase())
129
+ const matchesStatus =
130
+ filterStatus === 'all' ||
131
+ textValue(page.status).toLowerCase() === filterStatus.toLowerCase()
132
+ const matchesTemplate =
133
+ filterTemplate === 'all' ||
134
+ textValue(page.template).toLowerCase() === filterTemplate.toLowerCase()
135
+ return matchesSearch && matchesStatus && matchesTemplate
136
+ })
115
137
 
116
138
  if (searchQuery.trim()) {
117
- results = sortByRelevance(results, searchQuery, (p: any) => [p.title, p.author ?? '', p.template ?? '']);
139
+ results = sortByRelevance(results, searchQuery, (p: any) => [
140
+ p.title,
141
+ p.author ?? '',
142
+ p.template ?? '',
143
+ ])
118
144
  } else if (sortConfig) {
119
145
  results = [...results].sort((a: any, b: any) => {
120
- const aVal = a[sortConfig.key] ?? '';
121
- const bVal = b[sortConfig.key] ?? '';
122
- const cmp = String(aVal).localeCompare(String(bVal));
123
- return sortConfig.direction === 'asc' ? cmp : -cmp;
124
- });
146
+ const aVal = a[sortConfig.key] ?? ''
147
+ const bVal = b[sortConfig.key] ?? ''
148
+ const cmp = String(aVal).localeCompare(String(bVal))
149
+ return sortConfig.direction === 'asc' ? cmp : -cmp
150
+ })
125
151
  }
126
- return results;
127
- }, [pages, searchQuery, filterStatus, filterTemplate, sortConfig]);
152
+ return results
153
+ }, [pages, searchQuery, filterStatus, filterTemplate, sortConfig])
128
154
 
129
155
  const handleSelectAll = (checked: boolean) => {
130
- setSelectedPages(checked ? filteredAndSorted.map((p: any) => p.id) : []);
131
- };
156
+ setSelectedPages(checked ? filteredAndSorted.map((p: any) => p.id) : [])
157
+ }
132
158
 
133
159
  const handleSelectPage = (id: number) => {
134
- setSelectedPages(prev => prev.includes(id) ? prev.filter(pid => pid !== id) : [...prev, id]);
135
- };
160
+ setSelectedPages((prev) =>
161
+ prev.includes(id) ? prev.filter((pid) => pid !== id) : [...prev, id],
162
+ )
163
+ }
136
164
 
137
165
  const handleBulkDelete = async () => {
138
166
  for (const id of selectedPages) {
139
- await cmsApi(`/collections/pages/${id}`, { method: 'DELETE' });
167
+ await cmsApi(`/collections/pages/${id}`, { method: 'DELETE' })
140
168
  }
141
- toast.success(`${selectedPages.length} pages deleted`);
142
- setSelectedPages([]);
143
- refetch();
144
- };
169
+ toast.success(`${selectedPages.length} pages deleted`)
170
+ setSelectedPages([])
171
+ refetch()
172
+ }
145
173
 
146
174
  const handleBulkPublish = async () => {
147
175
  for (const id of selectedPages) {
148
176
  await cmsApi(`/collections/pages/${id}`, {
149
177
  method: 'PUT',
150
178
  body: JSON.stringify({ status: 'PUBLISHED' }),
151
- });
179
+ })
152
180
  }
153
- toast.success(`${selectedPages.length} pages published`);
154
- setSelectedPages([]);
155
- refetch();
156
- };
181
+ toast.success(`${selectedPages.length} pages published`)
182
+ setSelectedPages([])
183
+ refetch()
184
+ }
157
185
 
158
186
  const handleBulkUnpublish = async () => {
159
187
  for (const id of selectedPages) {
160
188
  await cmsApi(`/collections/pages/${id}`, {
161
189
  method: 'PUT',
162
190
  body: JSON.stringify({ status: 'DRAFT' }),
163
- });
191
+ })
164
192
  }
165
- toast.success(`${selectedPages.length} pages unpublished`);
166
- setSelectedPages([]);
167
- refetch();
168
- };
193
+ toast.success(`${selectedPages.length} pages unpublished`)
194
+ setSelectedPages([])
195
+ refetch()
196
+ }
169
197
 
170
198
  const handleDelete = async (id: number) => {
171
- await cmsApi(`/collections/pages/${id}`, { method: 'DELETE' });
172
- toast.success('Page deleted');
173
- setSelectedPages(prev => prev.filter(pid => pid !== id));
174
- refetch();
175
- };
176
-
177
- const handleDropItem = useCallback(async (itemId: string, folderId: string | null) => {
178
- const res = await cmsApi(`/documents/${itemId}/folder`, {
179
- method: 'PUT',
180
- body: JSON.stringify({ folderId }),
181
- });
182
- if (res.error) {
183
- toast.error(res.error);
184
- } else {
185
- toast.success(folderId ? 'Moved to folder' : 'Removed from folder');
186
- refetch();
187
- }
188
- }, [refetch]);
199
+ await cmsApi(`/collections/pages/${id}`, { method: 'DELETE' })
200
+ toast.success('Page deleted')
201
+ setSelectedPages((prev) => prev.filter((pid) => pid !== id))
202
+ refetch()
203
+ }
204
+
205
+ const handleDropItem = useCallback(
206
+ async (itemId: string, folderId: string | null) => {
207
+ const res = await cmsApi(`/documents/${itemId}/folder`, {
208
+ method: 'PUT',
209
+ body: JSON.stringify({ folderId }),
210
+ })
211
+ if (res.error) {
212
+ toast.error(res.error)
213
+ } else {
214
+ toast.success(folderId ? 'Moved to folder' : 'Removed from folder')
215
+ refetch()
216
+ }
217
+ },
218
+ [refetch],
219
+ )
189
220
 
190
221
  const handleDragStart = (e: React.DragEvent, id: string) => {
191
- e.dataTransfer.setData('text/actuate-item-id', id);
192
- e.dataTransfer.effectAllowed = 'move';
193
- };
222
+ e.dataTransfer.setData('text/actuate-item-id', id)
223
+ e.dataTransfer.effectAllowed = 'move'
224
+ }
194
225
 
195
226
  function SortHeader({ label, sortKey }: { label: string; sortKey: PageSortKey }) {
196
- const active = sortConfig?.key === sortKey;
227
+ const active = sortConfig?.key === sortKey
197
228
  return (
198
229
  <button
199
230
  type="button"
@@ -202,12 +233,16 @@ export function Pages({ onNavigate }: PagesProps) {
202
233
  >
203
234
  {label}
204
235
  {active ? (
205
- sortConfig!.direction === 'asc' ? <ArrowUp className="w-3 h-3" /> : <ArrowDown className="w-3 h-3" />
236
+ sortConfig!.direction === 'asc' ? (
237
+ <ArrowUp className="w-3 h-3" />
238
+ ) : (
239
+ <ArrowDown className="w-3 h-3" />
240
+ )
206
241
  ) : (
207
242
  <ArrowUpDown className="w-3 h-3 text-gray-400" />
208
243
  )}
209
244
  </button>
210
- );
245
+ )
211
246
  }
212
247
 
213
248
  if (loading) {
@@ -215,7 +250,7 @@ export function Pages({ onNavigate }: PagesProps) {
215
250
  <div className="p-3 pr-6 sm:p-4 sm:pr-8 flex items-center justify-center h-64">
216
251
  <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
217
252
  </div>
218
- );
253
+ )
219
254
  }
220
255
 
221
256
  return (
@@ -224,7 +259,12 @@ export function Pages({ onNavigate }: PagesProps) {
224
259
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
225
260
  <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
226
261
  <span className="text-sm text-red-800 flex-1">{error}</span>
227
- <button onClick={refetch} className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors">Retry</button>
262
+ <button
263
+ onClick={refetch}
264
+ className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
265
+ >
266
+ Retry
267
+ </button>
228
268
  </div>
229
269
  )}
230
270
 
@@ -232,7 +272,7 @@ export function Pages({ onNavigate }: PagesProps) {
232
272
  <div className="flex items-center gap-3">
233
273
  <button
234
274
  type="button"
235
- onClick={() => setSidebarOpen(prev => !prev)}
275
+ onClick={() => setSidebarOpen((prev) => !prev)}
236
276
  className="p-1.5 rounded-lg hover:bg-gray-100 transition-colors"
237
277
  title={sidebarOpen ? 'Hide folders' : 'Show folders'}
238
278
  >
@@ -240,7 +280,9 @@ export function Pages({ onNavigate }: PagesProps) {
240
280
  </button>
241
281
  <div>
242
282
  <h1 className="text-xl sm:text-2xl font-semibold text-gray-900">Pages</h1>
243
- <p className="text-sm text-gray-500">{totalCount} page{totalCount !== 1 ? 's' : ''}</p>
283
+ <p className="text-sm text-gray-500">
284
+ {totalCount} page{totalCount !== 1 ? 's' : ''}
285
+ </p>
244
286
  </div>
245
287
  </div>
246
288
  <button
@@ -259,7 +301,10 @@ export function Pages({ onNavigate }: PagesProps) {
259
301
  <FolderTree
260
302
  scope="pages"
261
303
  selected={folderSel}
262
- onSelect={(sel) => { setFolderSel(sel); setSelectedPages([]); }}
304
+ onSelect={(sel) => {
305
+ setFolderSel(sel)
306
+ setSelectedPages([])
307
+ }}
263
308
  totalCount={allData.data?.total}
264
309
  uncategorizedCount={uncatData.data?.total}
265
310
  onDropItem={handleDropItem}
@@ -272,22 +317,39 @@ export function Pages({ onNavigate }: PagesProps) {
272
317
  <div className="p-3 flex flex-col gap-3">
273
318
  <div className="relative">
274
319
  <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
275
- <input type="text" placeholder="Search pages..." value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} className="w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" />
320
+ <input
321
+ type="text"
322
+ placeholder="Search pages..."
323
+ value={searchQuery}
324
+ onChange={(e) => setSearchQuery(e.target.value)}
325
+ className="w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
326
+ />
276
327
  </div>
277
328
  <div className="flex flex-col sm:flex-row gap-2">
278
- <select value={filterStatus} onChange={(e) => setFilterStatus(e.target.value)} className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
329
+ <select
330
+ value={filterStatus}
331
+ onChange={(e) => setFilterStatus(e.target.value)}
332
+ className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
333
+ >
279
334
  <option value="all">All Status</option>
280
335
  <option value="published">Published</option>
281
336
  <option value="draft">Draft</option>
282
337
  </select>
283
- <select value={filterTemplate} onChange={(e) => setFilterTemplate(e.target.value)} className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
338
+ <select
339
+ value={filterTemplate}
340
+ onChange={(e) => setFilterTemplate(e.target.value)}
341
+ className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
342
+ >
284
343
  <option value="all">All Templates</option>
285
344
  <option value="landing">Landing</option>
286
345
  <option value="standard">Standard</option>
287
346
  <option value="marketing">Marketing</option>
288
347
  <option value="blog">Blog</option>
289
348
  </select>
290
- <button type="button" className="flex items-center justify-center gap-2 px-3 py-2 text-sm border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">
349
+ <button
350
+ type="button"
351
+ className="flex items-center justify-center gap-2 px-3 py-2 text-sm border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
352
+ >
291
353
  <SlidersHorizontal className="w-4 h-4" />
292
354
  <span className="hidden sm:inline">More Filters</span>
293
355
  </button>
@@ -298,12 +360,38 @@ export function Pages({ onNavigate }: PagesProps) {
298
360
  {selectedPages.length > 0 && (
299
361
  <div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mb-4">
300
362
  <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2">
301
- <span className="text-sm text-blue-900">{selectedPages.length} page{selectedPages.length !== 1 ? 's' : ''} selected</span>
363
+ <span className="text-sm text-blue-900">
364
+ {selectedPages.length} page{selectedPages.length !== 1 ? 's' : ''} selected
365
+ </span>
302
366
  <div className="flex items-center gap-2">
303
- <button type="button" onClick={handleBulkPublish} className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors">Publish</button>
304
- <button type="button" onClick={handleBulkUnpublish} className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 transition-colors">Unpublish</button>
305
- <button type="button" onClick={handleBulkDelete} className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors">Delete</button>
306
- <button type="button" onClick={() => setSelectedPages([])} className="flex-1 sm:flex-none px-3 py-1.5 text-sm border border-gray-300 bg-white rounded-lg hover:bg-gray-50 transition-colors">Cancel</button>
367
+ <button
368
+ type="button"
369
+ onClick={handleBulkPublish}
370
+ className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
371
+ >
372
+ Publish
373
+ </button>
374
+ <button
375
+ type="button"
376
+ onClick={handleBulkUnpublish}
377
+ className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 transition-colors"
378
+ >
379
+ Unpublish
380
+ </button>
381
+ <button
382
+ type="button"
383
+ onClick={handleBulkDelete}
384
+ className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
385
+ >
386
+ Delete
387
+ </button>
388
+ <button
389
+ type="button"
390
+ onClick={() => setSelectedPages([])}
391
+ className="flex-1 sm:flex-none px-3 py-1.5 text-sm border border-gray-300 bg-white rounded-lg hover:bg-gray-50 transition-colors"
392
+ >
393
+ Cancel
394
+ </button>
307
395
  </div>
308
396
  </div>
309
397
  </div>
@@ -315,10 +403,15 @@ export function Pages({ onNavigate }: PagesProps) {
315
403
  {folderSel.type === 'smart' && folderSel.smart === 'uncategorized'
316
404
  ? 'No uncategorized pages'
317
405
  : folderSel.type === 'folder'
318
- ? 'No pages in this folder'
319
- : 'No pages yet'}
406
+ ? 'No pages in this folder'
407
+ : 'No pages yet'}
320
408
  </p>
321
- <button onClick={() => onNavigate?.('/pages/new')} className="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">Create your first page</button>
409
+ <button
410
+ onClick={() => onNavigate?.('/pages/new')}
411
+ className="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
412
+ >
413
+ Create your first page
414
+ </button>
322
415
  </div>
323
416
  ) : (
324
417
  <>
@@ -328,22 +421,44 @@ export function Pages({ onNavigate }: PagesProps) {
328
421
  <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
329
422
  <tr>
330
423
  <th className="w-8 px-3 py-2 text-left">
331
- <input type="checkbox" checked={selectedPages.length === filteredAndSorted.length && filteredAndSorted.length > 0} onChange={(e) => handleSelectAll(e.target.checked)} className="rounded border-gray-300" />
424
+ <input
425
+ type="checkbox"
426
+ checked={
427
+ selectedPages.length === filteredAndSorted.length &&
428
+ filteredAndSorted.length > 0
429
+ }
430
+ onChange={(e) => handleSelectAll(e.target.checked)}
431
+ className="rounded border-gray-300"
432
+ />
332
433
  </th>
333
434
  <th className="w-6 px-1 py-2"></th>
334
- <th className="px-3 py-2 text-left"><SortHeader label="Title" sortKey="title" /></th>
335
- <th className="px-3 py-2 text-left text-xs font-medium text-gray-700">Folder</th>
336
- <th className="px-3 py-2 text-left"><SortHeader label="Author" sortKey="author" /></th>
337
- <th className="px-3 py-2 text-left text-xs font-medium text-gray-700">SEO</th>
338
- <th className="px-3 py-2 text-left"><SortHeader label="Status" sortKey="status" /></th>
339
- <th className="px-3 py-2 text-left"><SortHeader label="Date" sortKey="date" /></th>
340
- <th className="px-3 py-2 text-left text-xs font-medium text-gray-700">Actions</th>
435
+ <th className="px-3 py-2 text-left">
436
+ <SortHeader label="Title" sortKey="title" />
437
+ </th>
438
+ <th className="px-3 py-2 text-left text-xs font-medium text-gray-700">
439
+ Folder
440
+ </th>
441
+ <th className="px-3 py-2 text-left">
442
+ <SortHeader label="Author" sortKey="author" />
443
+ </th>
444
+ <th className="px-3 py-2 text-left text-xs font-medium text-gray-700">
445
+ SEO
446
+ </th>
447
+ <th className="px-3 py-2 text-left">
448
+ <SortHeader label="Status" sortKey="status" />
449
+ </th>
450
+ <th className="px-3 py-2 text-left">
451
+ <SortHeader label="Date" sortKey="date" />
452
+ </th>
453
+ <th className="px-3 py-2 text-left text-xs font-medium text-gray-700">
454
+ Actions
455
+ </th>
341
456
  </tr>
342
457
  </thead>
343
458
  <tbody className="divide-y divide-gray-200">
344
459
  {filteredAndSorted.map((page: any) => {
345
- const seoScore = computeSeoScore(page.data);
346
- const folderName = page.folder?.name ?? page.folderName;
460
+ const seoScore = computeSeoScore(page.data)
461
+ const folderName = page.folder?.name ?? page.folderName
347
462
  return (
348
463
  <tr
349
464
  key={page.id}
@@ -352,37 +467,66 @@ export function Pages({ onNavigate }: PagesProps) {
352
467
  onDragStart={(e) => handleDragStart(e, page.id)}
353
468
  >
354
469
  <td className="px-3 py-2">
355
- <input type="checkbox" checked={selectedPages.includes(page.id)} onChange={() => handleSelectPage(page.id)} className="rounded border-gray-300" />
470
+ <input
471
+ type="checkbox"
472
+ checked={selectedPages.includes(page.id)}
473
+ onChange={() => handleSelectPage(page.id)}
474
+ className="rounded border-gray-300"
475
+ />
356
476
  </td>
357
477
  <td className="px-1 py-2 cursor-grab">
358
478
  <GripVertical className="w-4 h-4 text-gray-300" />
359
479
  </td>
360
480
  <td className="px-3 py-2">
361
- <button type="button" onClick={() => onNavigate?.(`/pages/${page.id}`)} className="font-medium text-gray-900 hover:text-blue-600 text-sm text-left">{page.title}</button>
481
+ <button
482
+ type="button"
483
+ onClick={() => onNavigate?.(`/pages/${page.id}`)}
484
+ className="font-medium text-gray-900 hover:text-blue-600 text-sm text-left"
485
+ >
486
+ {page.title}
487
+ </button>
362
488
  </td>
363
489
  <td className="px-3 py-2">
364
- {folderName ? <FolderBadge name={folderName} /> : <span className="text-xs text-gray-400">—</span>}
490
+ {folderName ? (
491
+ <FolderBadge name={folderName} />
492
+ ) : (
493
+ <span className="text-xs text-gray-400">—</span>
494
+ )}
365
495
  </td>
366
496
  <td className="px-3 py-2 text-sm text-gray-600">{page.author}</td>
367
497
  <td className="px-3 py-2">
368
498
  <SeoScoreBadge score={seoScore} />
369
499
  </td>
370
500
  <td className="px-3 py-2">
371
- <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${page.status === 'Published' || page.status === 'PUBLISHED' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}>{page.status}</span>
501
+ <span
502
+ className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${page.status === 'Published' || page.status === 'PUBLISHED' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
503
+ >
504
+ {page.status}
505
+ </span>
372
506
  </td>
373
507
  <td className="px-3 py-2 text-sm text-gray-600">{page.date}</td>
374
508
  <td className="px-3 py-2">
375
509
  <div className="flex items-center gap-2">
376
- <button type="button" onClick={() => onNavigate?.(`/pages/${page.id}`)} className="p-1.5 hover:bg-gray-100 rounded transition-colors" title="Edit">
510
+ <button
511
+ type="button"
512
+ onClick={() => onNavigate?.(`/pages/${page.id}`)}
513
+ className="p-1.5 hover:bg-gray-100 rounded transition-colors"
514
+ title="Edit"
515
+ >
377
516
  <Pencil className="w-4 h-4 text-gray-600" />
378
517
  </button>
379
- <button type="button" onClick={() => handleDelete(page.id)} className="p-1.5 hover:bg-gray-100 rounded transition-colors" title="Delete">
518
+ <button
519
+ type="button"
520
+ onClick={() => handleDelete(page.id)}
521
+ className="p-1.5 hover:bg-gray-100 rounded transition-colors"
522
+ title="Delete"
523
+ >
380
524
  <Trash2 className="w-4 h-4 text-red-600" />
381
525
  </button>
382
526
  </div>
383
527
  </td>
384
528
  </tr>
385
- );
529
+ )
386
530
  })}
387
531
  </tbody>
388
532
  </table>
@@ -392,8 +536,8 @@ export function Pages({ onNavigate }: PagesProps) {
392
536
  <div className="md:hidden bg-white rounded-lg border border-gray-200 flex-1 overflow-auto">
393
537
  <div className="divide-y divide-gray-200">
394
538
  {filteredAndSorted.map((page: any) => {
395
- const seoScore = computeSeoScore(page.data);
396
- const folderName = page.folder?.name ?? page.folderName;
539
+ const seoScore = computeSeoScore(page.data)
540
+ const folderName = page.folder?.name ?? page.folderName
397
541
  return (
398
542
  <div
399
543
  key={page.id}
@@ -402,24 +546,43 @@ export function Pages({ onNavigate }: PagesProps) {
402
546
  onDragStart={(e) => handleDragStart(e, page.id)}
403
547
  >
404
548
  <div className="flex items-start gap-3">
405
- <input type="checkbox" checked={selectedPages.includes(page.id)} onChange={() => handleSelectPage(page.id)} className="rounded border-gray-300 mt-1" />
549
+ <input
550
+ type="checkbox"
551
+ checked={selectedPages.includes(page.id)}
552
+ onChange={() => handleSelectPage(page.id)}
553
+ className="rounded border-gray-300 mt-1"
554
+ />
406
555
  <div className="flex-1 min-w-0">
407
- <button type="button" onClick={() => onNavigate?.(`/pages/${page.id}`)} className="font-medium text-sm text-gray-900 hover:text-blue-600 block mb-1 text-left">{page.title}</button>
556
+ <button
557
+ type="button"
558
+ onClick={() => onNavigate?.(`/pages/${page.id}`)}
559
+ className="font-medium text-sm text-gray-900 hover:text-blue-600 block mb-1 text-left"
560
+ >
561
+ {page.title}
562
+ </button>
408
563
  <div className="flex flex-wrap items-center gap-2 text-xs text-gray-600 mb-2">
409
564
  {folderName && <FolderBadge name={folderName} />}
410
565
  <span>{page.author}</span>
411
566
  <span>&middot;</span>
412
567
  <span>{page.date}</span>
413
568
  <SeoScoreBadge score={seoScore} />
414
- <span className={`px-2 py-0.5 rounded-full text-xs font-medium ${page.status === 'Published' || page.status === 'PUBLISHED' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}>{page.status}</span>
569
+ <span
570
+ className={`px-2 py-0.5 rounded-full text-xs font-medium ${page.status === 'Published' || page.status === 'PUBLISHED' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
571
+ >
572
+ {page.status}
573
+ </span>
415
574
  </div>
416
575
  </div>
417
- <button type="button" onClick={() => handleDelete(page.id)} className="p-1.5 hover:bg-gray-100 rounded transition-colors">
576
+ <button
577
+ type="button"
578
+ onClick={() => handleDelete(page.id)}
579
+ className="p-1.5 hover:bg-gray-100 rounded transition-colors"
580
+ >
418
581
  <Trash2 className="w-4 h-4 text-red-600" />
419
582
  </button>
420
583
  </div>
421
584
  </div>
422
- );
585
+ )
423
586
  })}
424
587
  </div>
425
588
  </div>
@@ -428,5 +591,5 @@ export function Pages({ onNavigate }: PagesProps) {
428
591
  </div>
429
592
  </div>
430
593
  </div>
431
- );
594
+ )
432
595
  }