@actuate-media/cms-admin 0.8.0 → 0.8.2

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 (433) 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/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.js.map +1 -1
  155. package/dist/lib/search.d.ts.map +1 -1
  156. package/dist/lib/search.js +3 -5
  157. package/dist/lib/search.js.map +1 -1
  158. package/dist/lib/useApiData.d.ts.map +1 -1
  159. package/dist/lib/useApiData.js.map +1 -1
  160. package/dist/lib/utils.d.ts.map +1 -1
  161. package/dist/lib/utils.js.map +1 -1
  162. package/dist/router/index.d.ts.map +1 -1
  163. package/dist/router/index.js +1 -3
  164. package/dist/router/index.js.map +1 -1
  165. package/dist/views/CollectionList.d.ts.map +1 -1
  166. package/dist/views/CollectionList.js +56 -17
  167. package/dist/views/CollectionList.js.map +1 -1
  168. package/dist/views/Dashboard.d.ts.map +1 -1
  169. package/dist/views/Dashboard.js +26 -13
  170. package/dist/views/Dashboard.js.map +1 -1
  171. package/dist/views/DocumentEdit.d.ts +1 -1
  172. package/dist/views/DocumentEdit.d.ts.map +1 -1
  173. package/dist/views/DocumentEdit.js +33 -15
  174. package/dist/views/DocumentEdit.js.map +1 -1
  175. package/dist/views/ForgotPassword.d.ts.map +1 -1
  176. package/dist/views/ForgotPassword.js.map +1 -1
  177. package/dist/views/FormEditor.d.ts.map +1 -1
  178. package/dist/views/FormEditor.js +8 -2
  179. package/dist/views/FormEditor.js.map +1 -1
  180. package/dist/views/FormSubmissions.d.ts.map +1 -1
  181. package/dist/views/FormSubmissions.js +6 -6
  182. package/dist/views/FormSubmissions.js.map +1 -1
  183. package/dist/views/Forms.d.ts.map +1 -1
  184. package/dist/views/Forms.js.map +1 -1
  185. package/dist/views/Login.d.ts.map +1 -1
  186. package/dist/views/Login.js +5 -2
  187. package/dist/views/Login.js.map +1 -1
  188. package/dist/views/MediaBrowser.d.ts.map +1 -1
  189. package/dist/views/MediaBrowser.js +39 -19
  190. package/dist/views/MediaBrowser.js.map +1 -1
  191. package/dist/views/PageEditor.d.ts.map +1 -1
  192. package/dist/views/PageEditor.js.map +1 -1
  193. package/dist/views/Pages.d.ts.map +1 -1
  194. package/dist/views/Pages.js +20 -10
  195. package/dist/views/Pages.js.map +1 -1
  196. package/dist/views/PostEditor.d.ts.map +1 -1
  197. package/dist/views/PostEditor.js.map +1 -1
  198. package/dist/views/Posts.d.ts.map +1 -1
  199. package/dist/views/Posts.js +13 -7
  200. package/dist/views/Posts.js.map +1 -1
  201. package/dist/views/Redirects.d.ts.map +1 -1
  202. package/dist/views/Redirects.js +17 -5
  203. package/dist/views/Redirects.js.map +1 -1
  204. package/dist/views/ResetPassword.d.ts.map +1 -1
  205. package/dist/views/ResetPassword.js.map +1 -1
  206. package/dist/views/SEO.d.ts.map +1 -1
  207. package/dist/views/SEO.js +40 -17
  208. package/dist/views/SEO.js.map +1 -1
  209. package/dist/views/ScriptTagEditor.d.ts.map +1 -1
  210. package/dist/views/ScriptTagEditor.js +2 -1
  211. package/dist/views/ScriptTagEditor.js.map +1 -1
  212. package/dist/views/ScriptTags.d.ts.map +1 -1
  213. package/dist/views/ScriptTags.js.map +1 -1
  214. package/dist/views/Settings.d.ts.map +1 -1
  215. package/dist/views/Settings.js +38 -11
  216. package/dist/views/Settings.js.map +1 -1
  217. package/dist/views/SetupWizard.d.ts.map +1 -1
  218. package/dist/views/SetupWizard.js.map +1 -1
  219. package/dist/views/Users.d.ts.map +1 -1
  220. package/dist/views/Users.js +5 -3
  221. package/dist/views/Users.js.map +1 -1
  222. package/dist/views/page-builder/AIBlockAssist.d.ts.map +1 -1
  223. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  224. package/dist/views/page-builder/AIBlockAssist.js.map +1 -1
  225. package/dist/views/page-builder/AIGenerateDialog.d.ts.map +1 -1
  226. package/dist/views/page-builder/AIGenerateDialog.js +4 -1
  227. package/dist/views/page-builder/AIGenerateDialog.js.map +1 -1
  228. package/dist/views/page-builder/BlockEditor.d.ts.map +1 -1
  229. package/dist/views/page-builder/BlockEditor.js +1 -1
  230. package/dist/views/page-builder/BlockEditor.js.map +1 -1
  231. package/dist/views/page-builder/BlockPicker.d.ts.map +1 -1
  232. package/dist/views/page-builder/BlockPicker.js.map +1 -1
  233. package/dist/views/page-builder/BottomBar.d.ts.map +1 -1
  234. package/dist/views/page-builder/BottomBar.js.map +1 -1
  235. package/dist/views/page-builder/BuilderToolbar.d.ts.map +1 -1
  236. package/dist/views/page-builder/BuilderToolbar.js.map +1 -1
  237. package/dist/views/page-builder/ContextPanel.d.ts.map +1 -1
  238. package/dist/views/page-builder/ContextPanel.js +4 -1
  239. package/dist/views/page-builder/ContextPanel.js.map +1 -1
  240. package/dist/views/page-builder/DesignScore.d.ts.map +1 -1
  241. package/dist/views/page-builder/DesignScore.js.map +1 -1
  242. package/dist/views/page-builder/NodeSettings.d.ts.map +1 -1
  243. package/dist/views/page-builder/NodeSettings.js +1 -1
  244. package/dist/views/page-builder/NodeSettings.js.map +1 -1
  245. package/dist/views/page-builder/PageBuilder.d.ts +1 -1
  246. package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
  247. package/dist/views/page-builder/PageBuilder.js +4 -2
  248. package/dist/views/page-builder/PageBuilder.js.map +1 -1
  249. package/dist/views/page-builder/PageSettings.d.ts.map +1 -1
  250. package/dist/views/page-builder/PageSettings.js.map +1 -1
  251. package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
  252. package/dist/views/page-builder/PageTemplates.js.map +1 -1
  253. package/dist/views/page-builder/SEOPanel.d.ts.map +1 -1
  254. package/dist/views/page-builder/SEOPanel.js +1 -3
  255. package/dist/views/page-builder/SEOPanel.js.map +1 -1
  256. package/dist/views/page-builder/SavedSections.d.ts.map +1 -1
  257. package/dist/views/page-builder/SavedSections.js +3 -7
  258. package/dist/views/page-builder/SavedSections.js.map +1 -1
  259. package/dist/views/page-builder/TemplatePicker.d.ts.map +1 -1
  260. package/dist/views/page-builder/TemplatePicker.js.map +1 -1
  261. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +1 -1
  262. package/dist/views/page-builder/block-renderers/CTAPreview.js +1 -1
  263. package/dist/views/page-builder/block-renderers/CTAPreview.js.map +1 -1
  264. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +1 -1
  265. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  266. package/dist/views/page-builder/block-renderers/CardsPreview.js.map +1 -1
  267. package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +1 -1
  268. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -5
  269. package/dist/views/page-builder/block-renderers/CodePreview.js.map +1 -1
  270. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +1 -1
  271. package/dist/views/page-builder/block-renderers/FAQPreview.js +4 -1
  272. package/dist/views/page-builder/block-renderers/FAQPreview.js.map +1 -1
  273. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +1 -1
  274. package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +1 -1
  275. package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +1 -1
  276. package/dist/views/page-builder/block-renderers/FormPreview.js +2 -2
  277. package/dist/views/page-builder/block-renderers/FormPreview.js.map +1 -1
  278. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +1 -1
  279. package/dist/views/page-builder/block-renderers/GalleryPreview.js +1 -3
  280. package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +1 -1
  281. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +1 -1
  282. package/dist/views/page-builder/block-renderers/HeroPreview.js.map +1 -1
  283. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +1 -1
  284. package/dist/views/page-builder/block-renderers/ImagePreview.js.map +1 -1
  285. package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +1 -1
  286. package/dist/views/page-builder/block-renderers/TextPreview.js +2 -6
  287. package/dist/views/page-builder/block-renderers/TextPreview.js.map +1 -1
  288. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +1 -1
  289. package/dist/views/page-builder/block-renderers/VideoPreview.js +2 -5
  290. package/dist/views/page-builder/block-renderers/VideoPreview.js.map +1 -1
  291. package/dist/views/page-builder/block-renderers/index.d.ts.map +1 -1
  292. package/dist/views/page-builder/block-renderers/index.js.map +1 -1
  293. package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +1 -1
  294. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -5
  295. package/dist/views/page-builder/canvas/BlockRenderer.js.map +1 -1
  296. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +1 -1
  297. package/dist/views/page-builder/canvas/BuilderCanvas.js.map +1 -1
  298. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +1 -1
  299. package/dist/views/page-builder/canvas/ColumnRenderer.js +1 -5
  300. package/dist/views/page-builder/canvas/ColumnRenderer.js.map +1 -1
  301. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +1 -1
  302. package/dist/views/page-builder/canvas/ContainerRenderer.js +1 -5
  303. package/dist/views/page-builder/canvas/ContainerRenderer.js.map +1 -1
  304. package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +1 -1
  305. package/dist/views/page-builder/canvas/RowRenderer.js +1 -5
  306. package/dist/views/page-builder/canvas/RowRenderer.js.map +1 -1
  307. package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +1 -1
  308. package/dist/views/page-builder/canvas/SectionRenderer.js +1 -5
  309. package/dist/views/page-builder/canvas/SectionRenderer.js.map +1 -1
  310. package/dist/views/page-builder/canvas/index.d.ts.map +1 -1
  311. package/dist/views/page-builder/canvas/index.js.map +1 -1
  312. package/package.json +2 -2
  313. package/src/AdminRoot.tsx +263 -191
  314. package/src/__tests__/lib/search.test.ts +60 -69
  315. package/src/__tests__/lib/utils.test.ts +12 -12
  316. package/src/__tests__/router/match-route.test.ts +24 -26
  317. package/src/__tests__/router/strip-base.test.ts +15 -15
  318. package/src/components/Breadcrumbs.tsx +27 -24
  319. package/src/components/CommandPalette.tsx +115 -99
  320. package/src/components/ContentOverviewChart.tsx +19 -14
  321. package/src/components/ErrorBoundary.tsx +13 -13
  322. package/src/components/FocalPointPicker.tsx +31 -20
  323. package/src/components/FolderTree.tsx +172 -139
  324. package/src/components/LivePreview.tsx +68 -41
  325. package/src/components/LocaleProvider.tsx +26 -20
  326. package/src/components/LocaleSwitcher.tsx +9 -11
  327. package/src/components/MediaPickerModal.tsx +46 -45
  328. package/src/components/PresenceIndicator.tsx +30 -27
  329. package/src/components/SEOPanel.tsx +378 -228
  330. package/src/components/SEOPerformance.tsx +52 -30
  331. package/src/components/ThemeProvider.tsx +46 -46
  332. package/src/components/TipTapEditor.tsx +60 -64
  333. package/src/components/VersionHistory.tsx +63 -52
  334. package/src/components/ui/Avatar.tsx +8 -8
  335. package/src/components/ui/Badge.tsx +7 -5
  336. package/src/components/ui/Button.tsx +24 -13
  337. package/src/components/ui/CommandPalette.tsx +56 -42
  338. package/src/components/ui/ConfirmDialog.tsx +14 -14
  339. package/src/components/ui/DataTable.tsx +37 -39
  340. package/src/components/ui/EmptyState.tsx +9 -11
  341. package/src/components/ui/Modal.tsx +21 -15
  342. package/src/components/ui/Pagination.tsx +34 -19
  343. package/src/components/ui/SearchInput.tsx +17 -7
  344. package/src/components/ui/Skeleton.tsx +7 -7
  345. package/src/components/ui/Toast.tsx +29 -22
  346. package/src/components/ui/index.ts +24 -24
  347. package/src/fields/ArrayField.tsx +43 -25
  348. package/src/fields/BlockBuilderField.tsx +80 -99
  349. package/src/fields/DateField.tsx +20 -12
  350. package/src/fields/FieldRenderer.tsx +34 -34
  351. package/src/fields/GroupField.tsx +8 -10
  352. package/src/fields/MediaField.tsx +8 -10
  353. package/src/fields/NavBuilderField.tsx +24 -25
  354. package/src/fields/NumberField.tsx +21 -14
  355. package/src/fields/RelationshipField.tsx +105 -91
  356. package/src/fields/RichTextField.tsx +16 -12
  357. package/src/fields/SelectField.tsx +42 -34
  358. package/src/fields/SlugField.tsx +29 -17
  359. package/src/fields/TextField.tsx +24 -16
  360. package/src/fields/ToggleField.tsx +7 -9
  361. package/src/fields/block-types.ts +50 -24
  362. package/src/fields/index.ts +17 -17
  363. package/src/hooks/useBuilderState.ts +260 -221
  364. package/src/hooks/useContentLock.ts +23 -20
  365. package/src/hooks/useDebounce.ts +7 -7
  366. package/src/hooks/useKeyboardShortcuts.ts +16 -16
  367. package/src/index.ts +69 -58
  368. package/src/layout/Header.tsx +21 -20
  369. package/src/layout/Layout.tsx +22 -24
  370. package/src/layout/Sidebar.tsx +107 -72
  371. package/src/lib/api.ts +34 -34
  372. package/src/lib/search.ts +30 -34
  373. package/src/lib/useApiData.ts +65 -62
  374. package/src/lib/utils.ts +3 -3
  375. package/src/router/index.ts +33 -35
  376. package/src/styles/build-input.css +2 -2
  377. package/src/styles/tailwind.css +1 -1
  378. package/src/styles/theme.css +26 -2
  379. package/src/views/CollectionList.tsx +275 -121
  380. package/src/views/Dashboard.tsx +164 -117
  381. package/src/views/DocumentEdit.tsx +298 -253
  382. package/src/views/ForgotPassword.tsx +27 -23
  383. package/src/views/FormEditor.tsx +165 -99
  384. package/src/views/FormSubmissions.tsx +261 -117
  385. package/src/views/Forms.tsx +56 -26
  386. package/src/views/Login.tsx +107 -84
  387. package/src/views/MediaBrowser.tsx +717 -523
  388. package/src/views/PageEditor.tsx +44 -46
  389. package/src/views/Pages.tsx +312 -149
  390. package/src/views/PostEditor.tsx +57 -51
  391. package/src/views/Posts.tsx +206 -74
  392. package/src/views/Redirects.tsx +173 -117
  393. package/src/views/ResetPassword.tsx +43 -32
  394. package/src/views/SEO.tsx +607 -160
  395. package/src/views/ScriptTagEditor.tsx +69 -69
  396. package/src/views/ScriptTags.tsx +54 -42
  397. package/src/views/Settings.tsx +430 -220
  398. package/src/views/SetupWizard.tsx +69 -46
  399. package/src/views/Users.tsx +154 -120
  400. package/src/views/page-builder/AIBlockAssist.tsx +21 -25
  401. package/src/views/page-builder/AIGenerateDialog.tsx +134 -127
  402. package/src/views/page-builder/BlockEditor.tsx +94 -96
  403. package/src/views/page-builder/BlockPicker.tsx +73 -88
  404. package/src/views/page-builder/BottomBar.tsx +15 -11
  405. package/src/views/page-builder/BuilderToolbar.tsx +32 -29
  406. package/src/views/page-builder/ContextPanel.tsx +57 -57
  407. package/src/views/page-builder/DesignScore.tsx +52 -59
  408. package/src/views/page-builder/NodeSettings.tsx +59 -59
  409. package/src/views/page-builder/PageBuilder.tsx +156 -155
  410. package/src/views/page-builder/PageSettings.tsx +16 -15
  411. package/src/views/page-builder/PageTemplates.tsx +23 -17
  412. package/src/views/page-builder/SEOPanel.tsx +90 -111
  413. package/src/views/page-builder/SavedSections.tsx +99 -105
  414. package/src/views/page-builder/TemplatePicker.tsx +44 -48
  415. package/src/views/page-builder/block-renderers/CTAPreview.tsx +11 -13
  416. package/src/views/page-builder/block-renderers/CardsPreview.tsx +13 -15
  417. package/src/views/page-builder/block-renderers/CodePreview.tsx +16 -16
  418. package/src/views/page-builder/block-renderers/FAQPreview.tsx +20 -23
  419. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +5 -5
  420. package/src/views/page-builder/block-renderers/FormPreview.tsx +9 -13
  421. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +22 -28
  422. package/src/views/page-builder/block-renderers/HeroPreview.tsx +17 -30
  423. package/src/views/page-builder/block-renderers/ImagePreview.tsx +12 -12
  424. package/src/views/page-builder/block-renderers/TextPreview.tsx +22 -22
  425. package/src/views/page-builder/block-renderers/VideoPreview.tsx +13 -18
  426. package/src/views/page-builder/block-renderers/index.ts +17 -17
  427. package/src/views/page-builder/canvas/BlockRenderer.tsx +19 -23
  428. package/src/views/page-builder/canvas/BuilderCanvas.tsx +17 -20
  429. package/src/views/page-builder/canvas/ColumnRenderer.tsx +22 -26
  430. package/src/views/page-builder/canvas/ContainerRenderer.tsx +20 -24
  431. package/src/views/page-builder/canvas/RowRenderer.tsx +19 -23
  432. package/src/views/page-builder/canvas/SectionRenderer.tsx +30 -34
  433. package/src/views/page-builder/canvas/index.ts +2 -2
@@ -1,32 +1,29 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
- import { useState } from 'react';
4
- import { Button } from '../components/ui/Button.js';
3
+ import { useState } from 'react'
4
+ import { Button } from '../components/ui/Button.js'
5
5
 
6
6
  interface NavNode {
7
- id: string;
8
- label: string;
9
- url: string;
10
- children: NavNode[];
7
+ id: string
8
+ label: string
9
+ url: string
10
+ children: NavNode[]
11
11
  }
12
12
 
13
13
  export interface NavBuilderFieldProps {
14
- label: string;
15
- value?: NavNode[];
16
- onChange: (value: NavNode[]) => void;
17
- helpText?: string;
14
+ label: string
15
+ value?: NavNode[]
16
+ onChange: (value: NavNode[]) => void
17
+ helpText?: string
18
18
  }
19
19
 
20
20
  export function NavBuilderField({ label, value = [], onChange, helpText }: NavBuilderFieldProps) {
21
21
  function addItem() {
22
- onChange([
23
- ...value,
24
- { id: crypto.randomUUID(), label: 'New Item', url: '/', children: [] },
25
- ]);
22
+ onChange([...value, { id: crypto.randomUUID(), label: 'New Item', url: '/', children: [] }])
26
23
  }
27
24
 
28
25
  function removeItem(id: string) {
29
- onChange(value.filter((n) => n.id !== id));
26
+ onChange(value.filter((n) => n.id !== id))
30
27
  }
31
28
 
32
29
  function renderNode(node: NavNode, depth: number) {
@@ -38,7 +35,13 @@ export function NavBuilderField({ label, value = [], onChange, helpText }: NavBu
38
35
  >
39
36
  <div className="flex items-center justify-between">
40
37
  <div className="flex items-center gap-2 text-sm">
41
- <svg className="h-4 w-4 text-[var(--muted-foreground)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
38
+ <svg
39
+ className="h-4 w-4 text-[var(--muted-foreground)]"
40
+ fill="none"
41
+ viewBox="0 0 24 24"
42
+ stroke="currentColor"
43
+ strokeWidth={2}
44
+ >
42
45
  <path strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 12h16M4 18h16" />
43
46
  </svg>
44
47
  <span className="font-medium">{node.label}</span>
@@ -58,21 +61,17 @@ export function NavBuilderField({ label, value = [], onChange, helpText }: NavBu
58
61
  </div>
59
62
  )}
60
63
  </div>
61
- );
64
+ )
62
65
  }
63
66
 
64
67
  return (
65
68
  <div>
66
69
  <label className="mb-2 block text-sm font-medium">{label}</label>
67
- <div className="space-y-2">
68
- {value.map((node) => renderNode(node, 0))}
69
- </div>
70
+ <div className="space-y-2">{value.map((node) => renderNode(node, 0))}</div>
70
71
  <Button variant="secondary" size="sm" onClick={addItem} className="mt-2">
71
72
  Add Nav Item
72
73
  </Button>
73
- {helpText && (
74
- <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>
75
- )}
74
+ {helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
76
75
  </div>
77
- );
76
+ )
78
77
  }
@@ -1,17 +1,26 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
3
  export interface NumberFieldProps {
4
- label: string;
5
- value?: number;
6
- onChange: (value: number) => void;
7
- min?: number;
8
- max?: number;
9
- required?: boolean;
10
- helpText?: string;
11
- error?: string;
4
+ label: string
5
+ value?: number
6
+ onChange: (value: number) => void
7
+ min?: number
8
+ max?: number
9
+ required?: boolean
10
+ helpText?: string
11
+ error?: string
12
12
  }
13
13
 
14
- export function NumberField({ label, value, onChange, min, max, required, helpText, error }: NumberFieldProps) {
14
+ export function NumberField({
15
+ label,
16
+ value,
17
+ onChange,
18
+ min,
19
+ max,
20
+ required,
21
+ helpText,
22
+ error,
23
+ }: NumberFieldProps) {
15
24
  return (
16
25
  <div>
17
26
  <label className="mb-1 block text-sm font-medium">
@@ -37,9 +46,7 @@ export function NumberField({ label, value, onChange, min, max, required, helpTe
37
46
  {helpText && !error && (
38
47
  <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>
39
48
  )}
40
- {error && (
41
- <p className="mt-1 text-xs text-[var(--destructive)]">{error}</p>
42
- )}
49
+ {error && <p className="mt-1 text-xs text-[var(--destructive)]">{error}</p>}
43
50
  </div>
44
- );
51
+ )
45
52
  }
@@ -1,28 +1,28 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
- import { useState, useEffect, useRef, useCallback } from 'react';
4
- import { Search, X, Loader2, Plus } from 'lucide-react';
5
- import { cmsApi } from '../lib/api.js';
3
+ import { useState, useEffect, useRef, useCallback } from 'react'
4
+ import { Search, X, Loader2, Plus } from 'lucide-react'
5
+ import { cmsApi } from '../lib/api.js'
6
6
 
7
7
  export interface RelationshipFieldProps {
8
- label: string;
9
- value?: string | string[];
10
- onChange: (value: string | string[]) => void;
11
- multi?: boolean;
12
- required?: boolean;
13
- helpText?: string;
14
- relationTo?: string;
15
- useAsTitle?: string;
16
- onNavigate?: (path: string) => void;
8
+ label: string
9
+ value?: string | string[]
10
+ onChange: (value: string | string[]) => void
11
+ multi?: boolean
12
+ required?: boolean
13
+ helpText?: string
14
+ relationTo?: string
15
+ useAsTitle?: string
16
+ onNavigate?: (path: string) => void
17
17
  }
18
18
 
19
19
  interface RelatedDoc {
20
- id: string;
21
- title?: string;
22
- status?: string;
23
- collection?: string;
24
- updatedAt?: string;
25
- data?: Record<string, any>;
20
+ id: string
21
+ title?: string
22
+ status?: string
23
+ collection?: string
24
+ updatedAt?: string
25
+ data?: Record<string, any>
26
26
  }
27
27
 
28
28
  const STATUS_STYLES: Record<string, string> = {
@@ -30,22 +30,22 @@ const STATUS_STYLES: Record<string, string> = {
30
30
  DRAFT: 'bg-yellow-100 text-yellow-800',
31
31
  ARCHIVED: 'bg-gray-100 text-gray-600',
32
32
  SCHEDULED: 'bg-blue-100 text-blue-800',
33
- };
33
+ }
34
34
 
35
35
  function relativeTime(dateStr: string | undefined): string {
36
- if (!dateStr) return '';
37
- const diff = Date.now() - new Date(dateStr).getTime();
38
- const seconds = Math.floor(diff / 1000);
39
- if (seconds < 60) return 'just now';
40
- const minutes = Math.floor(seconds / 60);
41
- if (minutes < 60) return `${minutes}m ago`;
42
- const hours = Math.floor(minutes / 60);
43
- if (hours < 24) return `${hours}h ago`;
44
- const days = Math.floor(hours / 24);
45
- if (days < 30) return `${days}d ago`;
46
- const months = Math.floor(days / 30);
47
- if (months < 12) return `${months}mo ago`;
48
- return `${Math.floor(months / 12)}y ago`;
36
+ if (!dateStr) return ''
37
+ const diff = Date.now() - new Date(dateStr).getTime()
38
+ const seconds = Math.floor(diff / 1000)
39
+ if (seconds < 60) return 'just now'
40
+ const minutes = Math.floor(seconds / 60)
41
+ if (minutes < 60) return `${minutes}m ago`
42
+ const hours = Math.floor(minutes / 60)
43
+ if (hours < 24) return `${hours}h ago`
44
+ const days = Math.floor(hours / 24)
45
+ if (days < 30) return `${days}d ago`
46
+ const months = Math.floor(days / 30)
47
+ if (months < 12) return `${months}mo ago`
48
+ return `${Math.floor(months / 12)}y ago`
49
49
  }
50
50
 
51
51
  export function RelationshipField({
@@ -59,88 +59,98 @@ export function RelationshipField({
59
59
  useAsTitle = 'title',
60
60
  onNavigate,
61
61
  }: RelationshipFieldProps) {
62
- const [searchTerm, setSearchTerm] = useState('');
63
- const [open, setOpen] = useState(false);
64
- const [options, setOptions] = useState<RelatedDoc[]>([]);
65
- const [loading, setLoading] = useState(false);
66
- const dropdownRef = useRef<HTMLDivElement>(null);
67
- const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
62
+ const [searchTerm, setSearchTerm] = useState('')
63
+ const [open, setOpen] = useState(false)
64
+ const [options, setOptions] = useState<RelatedDoc[]>([])
65
+ const [loading, setLoading] = useState(false)
66
+ const dropdownRef = useRef<HTMLDivElement>(null)
67
+ const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
68
68
 
69
69
  const selectedIds = multi
70
- ? (Array.isArray(value) ? value : [])
71
- : (typeof value === 'string' && value ? [value] : []);
72
-
73
- const fetchOptions = useCallback(async (query: string) => {
74
- setLoading(true);
75
- const searchParam = query ? `&search=${encodeURIComponent(query)}` : '';
76
- const res = await cmsApi<{ docs: RelatedDoc[] }>(
77
- `/collections/${relationTo}?pageSize=50${searchParam}`,
78
- );
79
- if (res.data) {
80
- const docs: RelatedDoc[] = (res.data as any).docs ?? [];
81
- setOptions(docs);
82
- }
83
- setLoading(false);
84
- }, [relationTo]);
70
+ ? Array.isArray(value)
71
+ ? value
72
+ : []
73
+ : typeof value === 'string' && value
74
+ ? [value]
75
+ : []
76
+
77
+ const fetchOptions = useCallback(
78
+ async (query: string) => {
79
+ setLoading(true)
80
+ const searchParam = query ? `&search=${encodeURIComponent(query)}` : ''
81
+ const res = await cmsApi<{ docs: RelatedDoc[] }>(
82
+ `/collections/${relationTo}?pageSize=50${searchParam}`,
83
+ )
84
+ if (res.data) {
85
+ const docs: RelatedDoc[] = (res.data as any).docs ?? []
86
+ setOptions(docs)
87
+ }
88
+ setLoading(false)
89
+ },
90
+ [relationTo],
91
+ )
85
92
 
86
93
  useEffect(() => {
87
- if (open) fetchOptions(searchTerm);
88
- }, [open]);
94
+ if (open) fetchOptions(searchTerm)
95
+ }, [open])
89
96
 
90
- const handleSearch = useCallback((query: string) => {
91
- setSearchTerm(query);
92
- if (debounceRef.current) clearTimeout(debounceRef.current);
93
- debounceRef.current = setTimeout(() => fetchOptions(query), 300);
94
- }, [fetchOptions]);
97
+ const handleSearch = useCallback(
98
+ (query: string) => {
99
+ setSearchTerm(query)
100
+ if (debounceRef.current) clearTimeout(debounceRef.current)
101
+ debounceRef.current = setTimeout(() => fetchOptions(query), 300)
102
+ },
103
+ [fetchOptions],
104
+ )
95
105
 
96
106
  useEffect(() => {
97
107
  function handleClickOutside(e: MouseEvent) {
98
108
  if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {
99
- setOpen(false);
109
+ setOpen(false)
100
110
  }
101
111
  }
102
- document.addEventListener('mousedown', handleClickOutside);
103
- return () => document.removeEventListener('mousedown', handleClickOutside);
104
- }, []);
112
+ document.addEventListener('mousedown', handleClickOutside)
113
+ return () => document.removeEventListener('mousedown', handleClickOutside)
114
+ }, [])
105
115
 
106
116
  function getDocTitle(doc: RelatedDoc): string {
107
- if (doc.title) return doc.title;
108
- const d = doc.data;
117
+ if (doc.title) return doc.title
118
+ const d = doc.data
109
119
  if (d && typeof d === 'object') {
110
- if (typeof d[useAsTitle] === 'string') return d[useAsTitle];
111
- if (typeof d.title === 'string') return d.title;
112
- if (typeof d.name === 'string') return d.name;
120
+ if (typeof d[useAsTitle] === 'string') return d[useAsTitle]
121
+ if (typeof d.title === 'string') return d.title
122
+ if (typeof d.name === 'string') return d.name
113
123
  }
114
- return doc.id;
124
+ return doc.id
115
125
  }
116
126
 
117
127
  function handleToggle(id: string) {
118
128
  if (multi) {
119
129
  const next = selectedIds.includes(id)
120
130
  ? selectedIds.filter((v) => v !== id)
121
- : [...selectedIds, id];
122
- onChange(next);
131
+ : [...selectedIds, id]
132
+ onChange(next)
123
133
  } else {
124
- onChange(id);
125
- setOpen(false);
134
+ onChange(id)
135
+ setOpen(false)
126
136
  }
127
137
  }
128
138
 
129
139
  function handleRemove(id: string) {
130
140
  if (multi) {
131
- onChange(selectedIds.filter((v) => v !== id));
141
+ onChange(selectedIds.filter((v) => v !== id))
132
142
  } else {
133
- onChange('');
143
+ onChange('')
134
144
  }
135
145
  }
136
146
 
137
- const selectedItems = options.filter((opt) => selectedIds.includes(opt.id));
138
- const unselectedItems = options.filter((opt) => !selectedIds.includes(opt.id));
147
+ const selectedItems = options.filter((opt) => selectedIds.includes(opt.id))
148
+ const unselectedItems = options.filter((opt) => !selectedIds.includes(opt.id))
139
149
 
140
150
  function renderOption(opt: RelatedDoc, isSelected: boolean) {
141
- const status = opt.status ?? (opt.data as any)?.status;
142
- const collection = opt.collection ?? relationTo;
143
- const statusClass = STATUS_STYLES[status] ?? 'bg-gray-100 text-gray-600';
151
+ const status = opt.status ?? (opt.data as any)?.status
152
+ const collection = opt.collection ?? relationTo
153
+ const statusClass = STATUS_STYLES[status] ?? 'bg-gray-100 text-gray-600'
144
154
 
145
155
  return (
146
156
  <button
@@ -156,7 +166,9 @@ export function RelationshipField({
156
166
  <div className="flex items-center gap-2 mt-0.5">
157
167
  <span className="text-[10px] text-[var(--muted-foreground)]">{collection}</span>
158
168
  {opt.updatedAt && (
159
- <span className="text-[10px] text-[var(--muted-foreground)]">{relativeTime(opt.updatedAt)}</span>
169
+ <span className="text-[10px] text-[var(--muted-foreground)]">
170
+ {relativeTime(opt.updatedAt)}
171
+ </span>
160
172
  )}
161
173
  </div>
162
174
  </div>
@@ -166,7 +178,7 @@ export function RelationshipField({
166
178
  </span>
167
179
  )}
168
180
  </button>
169
- );
181
+ )
170
182
  }
171
183
 
172
184
  return (
@@ -184,7 +196,11 @@ export function RelationshipField({
184
196
  className="inline-flex items-center gap-1 rounded-md bg-[var(--accent)] px-2 py-1 text-xs"
185
197
  >
186
198
  {getDocTitle(item)}
187
- <button type="button" onClick={() => handleRemove(item.id)} className="hover:text-[var(--destructive)]">
199
+ <button
200
+ type="button"
201
+ onClick={() => handleRemove(item.id)}
202
+ className="hover:text-[var(--destructive)]"
203
+ >
188
204
  <X className="w-3 h-3" />
189
205
  </button>
190
206
  </span>
@@ -224,8 +240,8 @@ export function RelationshipField({
224
240
  <button
225
241
  type="button"
226
242
  onClick={() => {
227
- setOpen(false);
228
- onNavigate?.(`/${relationTo}/new`);
243
+ setOpen(false)
244
+ onNavigate?.(`/${relationTo}/new`)
229
245
  }}
230
246
  className="flex w-full items-center gap-2 px-3 py-2 text-sm text-[var(--primary)] hover:bg-[var(--accent)]"
231
247
  >
@@ -237,9 +253,7 @@ export function RelationshipField({
237
253
  )}
238
254
  </div>
239
255
 
240
- {helpText && (
241
- <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>
242
- )}
256
+ {helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
243
257
  </div>
244
- );
258
+ )
245
259
  }
@@ -1,16 +1,22 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
- import { TipTapEditor } from '../components/TipTapEditor.js';
3
+ import { TipTapEditor } from '../components/TipTapEditor.js'
4
4
 
5
5
  export interface RichTextFieldProps {
6
- label: string;
7
- value?: string;
8
- onChange: (value: string) => void;
9
- required?: boolean;
10
- helpText?: string;
6
+ label: string
7
+ value?: string
8
+ onChange: (value: string) => void
9
+ required?: boolean
10
+ helpText?: string
11
11
  }
12
12
 
13
- export function RichTextField({ label, value = '', onChange, required, helpText }: RichTextFieldProps) {
13
+ export function RichTextField({
14
+ label,
15
+ value = '',
16
+ onChange,
17
+ required,
18
+ helpText,
19
+ }: RichTextFieldProps) {
14
20
  return (
15
21
  <div>
16
22
  <label className="mb-1 block text-sm font-medium">
@@ -18,9 +24,7 @@ export function RichTextField({ label, value = '', onChange, required, helpText
18
24
  {required && <span className="ml-0.5 text-[var(--destructive)]">*</span>}
19
25
  </label>
20
26
  <TipTapEditor content={value} onChange={onChange} />
21
- {helpText && (
22
- <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>
23
- )}
27
+ {helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
24
28
  </div>
25
- );
29
+ )
26
30
  }
@@ -1,15 +1,15 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
- import { useState } from 'react';
3
+ import { useState } from 'react'
4
4
 
5
5
  export interface SelectFieldProps {
6
- label: string;
7
- value?: string | string[];
8
- onChange: (value: string | string[]) => void;
9
- options?: string[];
10
- multi?: boolean;
11
- required?: boolean;
12
- helpText?: string;
6
+ label: string
7
+ value?: string | string[]
8
+ onChange: (value: string | string[]) => void
9
+ options?: string[]
10
+ multi?: boolean
11
+ required?: boolean
12
+ helpText?: string
13
13
  }
14
14
 
15
15
  export function SelectField({
@@ -21,27 +21,23 @@ export function SelectField({
21
21
  required,
22
22
  helpText,
23
23
  }: SelectFieldProps) {
24
- const [searchTerm, setSearchTerm] = useState('');
25
- const [open, setOpen] = useState(false);
24
+ const [searchTerm, setSearchTerm] = useState('')
25
+ const [open, setOpen] = useState(false)
26
26
 
27
- const selectedValues = multi
28
- ? (Array.isArray(value) ? value : [])
29
- : [];
30
- const singleValue = multi ? '' : (typeof value === 'string' ? value : '');
27
+ const selectedValues = multi ? (Array.isArray(value) ? value : []) : []
28
+ const singleValue = multi ? '' : typeof value === 'string' ? value : ''
31
29
 
32
- const filtered = options.filter((opt) =>
33
- opt.toLowerCase().includes(searchTerm.toLowerCase()),
34
- );
30
+ const filtered = options.filter((opt) => opt.toLowerCase().includes(searchTerm.toLowerCase()))
35
31
 
36
32
  function handleSelect(opt: string) {
37
33
  if (multi) {
38
34
  const next = selectedValues.includes(opt)
39
35
  ? selectedValues.filter((v) => v !== opt)
40
- : [...selectedValues, opt];
41
- onChange(next);
36
+ : [...selectedValues, opt]
37
+ onChange(next)
42
38
  } else {
43
- onChange(opt);
44
- setOpen(false);
39
+ onChange(opt)
40
+ setOpen(false)
45
41
  }
46
42
  }
47
43
 
@@ -57,12 +53,22 @@ export function SelectField({
57
53
  onClick={() => setOpen((o) => !o)}
58
54
  className="flex w-full items-center justify-between rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm"
59
55
  >
60
- <span className={singleValue || selectedValues.length ? '' : 'text-[var(--muted-foreground)]'}>
56
+ <span
57
+ className={singleValue || selectedValues.length ? '' : 'text-[var(--muted-foreground)]'}
58
+ >
61
59
  {multi
62
- ? selectedValues.length ? `${selectedValues.length} selected` : 'Select...'
60
+ ? selectedValues.length
61
+ ? `${selectedValues.length} selected`
62
+ : 'Select...'
63
63
  : singleValue || 'Select...'}
64
64
  </span>
65
- <svg className="h-4 w-4 text-[var(--muted-foreground)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
65
+ <svg
66
+ className="h-4 w-4 text-[var(--muted-foreground)]"
67
+ fill="none"
68
+ viewBox="0 0 24 24"
69
+ stroke="currentColor"
70
+ strokeWidth={2}
71
+ >
66
72
  <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
67
73
  </svg>
68
74
  </button>
@@ -80,7 +86,7 @@ export function SelectField({
80
86
  </div>
81
87
  <ul className="max-h-48 overflow-y-auto py-1">
82
88
  {filtered.map((opt) => {
83
- const isSelected = multi ? selectedValues.includes(opt) : singleValue === opt;
89
+ const isSelected = multi ? selectedValues.includes(opt) : singleValue === opt
84
90
  return (
85
91
  <li key={opt}>
86
92
  <button
@@ -91,16 +97,20 @@ export function SelectField({
91
97
  }`}
92
98
  >
93
99
  {multi && (
94
- <span className={`flex h-4 w-4 items-center justify-center rounded border ${
95
- isSelected ? 'border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-foreground)]' : 'border-[var(--border)]'
96
- }`}>
100
+ <span
101
+ className={`flex h-4 w-4 items-center justify-center rounded border ${
102
+ isSelected
103
+ ? 'border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-foreground)]'
104
+ : 'border-[var(--border)]'
105
+ }`}
106
+ >
97
107
  {isSelected && '✓'}
98
108
  </span>
99
109
  )}
100
110
  {opt}
101
111
  </button>
102
112
  </li>
103
- );
113
+ )
104
114
  })}
105
115
  {filtered.length === 0 && (
106
116
  <li className="px-3 py-2 text-sm text-[var(--muted-foreground)]">No options found</li>
@@ -109,9 +119,7 @@ export function SelectField({
109
119
  </div>
110
120
  )}
111
121
 
112
- {helpText && (
113
- <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>
114
- )}
122
+ {helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
115
123
  </div>
116
- );
124
+ )
117
125
  }
@@ -1,14 +1,14 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
- import { useState, useEffect } from 'react';
3
+ import { useState, useEffect } from 'react'
4
4
 
5
5
  export interface SlugFieldProps {
6
- label: string;
7
- value?: string;
8
- onChange: (value: string) => void;
9
- from?: string;
10
- required?: boolean;
11
- helpText?: string;
6
+ label: string
7
+ value?: string
8
+ onChange: (value: string) => void
9
+ from?: string
10
+ required?: boolean
11
+ helpText?: string
12
12
  }
13
13
 
14
14
  function toSlug(text: string): string {
@@ -16,11 +16,11 @@ function toSlug(text: string): string {
16
16
  .toLowerCase()
17
17
  .replace(/[^\w\s-]/g, '')
18
18
  .replace(/[\s_]+/g, '-')
19
- .replace(/^-+|-+$/g, '');
19
+ .replace(/^-+|-+$/g, '')
20
20
  }
21
21
 
22
22
  export function SlugField({ label, value = '', onChange, required, helpText }: SlugFieldProps) {
23
- const [locked, setLocked] = useState(true);
23
+ const [locked, setLocked] = useState(true)
24
24
 
25
25
  return (
26
26
  <div>
@@ -45,11 +45,25 @@ export function SlugField({ label, value = '', onChange, required, helpText }: S
45
45
  className="rounded-md border border-[var(--border)] p-2 text-sm hover:bg-[var(--accent)]"
46
46
  aria-label={locked ? 'Unlock slug' : 'Lock slug'}
47
47
  >
48
- <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
48
+ <svg
49
+ className="h-4 w-4"
50
+ fill="none"
51
+ viewBox="0 0 24 24"
52
+ stroke="currentColor"
53
+ strokeWidth={2}
54
+ >
49
55
  {locked ? (
50
- <path strokeLinecap="round" strokeLinejoin="round" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
56
+ <path
57
+ strokeLinecap="round"
58
+ strokeLinejoin="round"
59
+ d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
60
+ />
51
61
  ) : (
52
- <path strokeLinecap="round" strokeLinejoin="round" d="M8 11V7a4 4 0 118 0m-4 8v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2z" />
62
+ <path
63
+ strokeLinecap="round"
64
+ strokeLinejoin="round"
65
+ d="M8 11V7a4 4 0 118 0m-4 8v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2z"
66
+ />
53
67
  )}
54
68
  </svg>
55
69
  </button>
@@ -57,9 +71,7 @@ export function SlugField({ label, value = '', onChange, required, helpText }: S
57
71
  {value && (
58
72
  <p className="mt-1 text-xs text-[var(--muted-foreground)]">URL preview: /{value}</p>
59
73
  )}
60
- {helpText && (
61
- <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>
62
- )}
74
+ {helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
63
75
  </div>
64
- );
76
+ )
65
77
  }