@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,120 +1,136 @@
1
- 'use client';
1
+ 'use client'
2
2
 
3
- import { useState, useMemo } from 'react';
3
+ import { useState, useMemo } from 'react'
4
4
  import {
5
- ArrowLeft, Download, Trash2, Search, Globe, ChevronDown, ChevronUp,
6
- MousePointerClick, MapPin, Smartphone, Monitor, Tablet, ExternalLink,
7
- Loader2, AlertTriangle,
8
- } from 'lucide-react';
9
- import { toast } from 'sonner';
10
- import { sortByRelevance } from '../lib/search.js';
11
- import { useApiData } from '../lib/useApiData.js';
5
+ ArrowLeft,
6
+ Download,
7
+ Trash2,
8
+ Search,
9
+ Globe,
10
+ ChevronDown,
11
+ ChevronUp,
12
+ MousePointerClick,
13
+ MapPin,
14
+ Smartphone,
15
+ Monitor,
16
+ Tablet,
17
+ ExternalLink,
18
+ Loader2,
19
+ AlertTriangle,
20
+ } from 'lucide-react'
21
+ import { toast } from 'sonner'
22
+ import { sortByRelevance } from '../lib/search.js'
23
+ import { useApiData } from '../lib/useApiData.js'
12
24
 
13
25
  interface Attribution {
14
- source: string;
15
- medium: string;
16
- campaign: string;
17
- term: string;
18
- content: string;
19
- landingPage: string;
20
- referrer: string;
21
- deviceType: 'Desktop' | 'Mobile' | 'Tablet';
22
- clickIds: Record<string, string | null>;
23
- capturedAt: string;
26
+ source: string
27
+ medium: string
28
+ campaign: string
29
+ term: string
30
+ content: string
31
+ landingPage: string
32
+ referrer: string
33
+ deviceType: 'Desktop' | 'Mobile' | 'Tablet'
34
+ clickIds: Record<string, string | null>
35
+ capturedAt: string
24
36
  }
25
37
 
26
38
  interface Submission {
27
- id: number;
28
- name: string;
29
- email: string;
30
- phone?: string;
31
- message: string;
32
- submittedAt: string;
33
- status: 'new' | 'read' | 'replied';
34
- attribution: Attribution;
39
+ id: number
40
+ name: string
41
+ email: string
42
+ phone?: string
43
+ message: string
44
+ submittedAt: string
45
+ status: 'new' | 'read' | 'replied'
46
+ attribution: Attribution
35
47
  }
36
48
 
37
49
  function sourceColor(source: string): string {
38
- const s = (source ?? '').toLowerCase();
39
- if (s === 'google') return 'bg-blue-100 text-blue-800';
40
- if (s === 'facebook' || s === 'meta') return 'bg-indigo-100 text-indigo-800';
41
- if (s === 'linkedin') return 'bg-sky-100 text-sky-800';
42
- if (s === 'bing') return 'bg-teal-100 text-teal-800';
43
- if (s === '(direct)') return 'bg-gray-100 text-gray-800';
44
- return 'bg-purple-100 text-purple-800';
50
+ const s = (source ?? '').toLowerCase()
51
+ if (s === 'google') return 'bg-blue-100 text-blue-800'
52
+ if (s === 'facebook' || s === 'meta') return 'bg-indigo-100 text-indigo-800'
53
+ if (s === 'linkedin') return 'bg-sky-100 text-sky-800'
54
+ if (s === 'bing') return 'bg-teal-100 text-teal-800'
55
+ if (s === '(direct)') return 'bg-gray-100 text-gray-800'
56
+ return 'bg-purple-100 text-purple-800'
45
57
  }
46
58
 
47
59
  function mediumColor(medium: string): string {
48
- const m = (medium ?? '').toLowerCase();
49
- if (m === 'cpc' || m === 'paid') return 'bg-orange-100 text-orange-800';
50
- if (m === 'organic') return 'bg-green-100 text-green-800';
51
- if (m === 'social') return 'bg-pink-100 text-pink-800';
52
- if (m === 'email') return 'bg-yellow-100 text-yellow-800';
53
- if (m === '(none)') return 'bg-gray-100 text-gray-600';
54
- return 'bg-gray-100 text-gray-800';
60
+ const m = (medium ?? '').toLowerCase()
61
+ if (m === 'cpc' || m === 'paid') return 'bg-orange-100 text-orange-800'
62
+ if (m === 'organic') return 'bg-green-100 text-green-800'
63
+ if (m === 'social') return 'bg-pink-100 text-pink-800'
64
+ if (m === 'email') return 'bg-yellow-100 text-yellow-800'
65
+ if (m === '(none)') return 'bg-gray-100 text-gray-600'
66
+ return 'bg-gray-100 text-gray-800'
55
67
  }
56
68
 
57
69
  function DeviceIcon({ type }: { type: string }) {
58
- if (type === 'Mobile') return <Smartphone className="w-3.5 h-3.5" />;
59
- if (type === 'Tablet') return <Tablet className="w-3.5 h-3.5" />;
60
- return <Monitor className="w-3.5 h-3.5" />;
70
+ if (type === 'Mobile') return <Smartphone className="w-3.5 h-3.5" />
71
+ if (type === 'Tablet') return <Tablet className="w-3.5 h-3.5" />
72
+ return <Monitor className="w-3.5 h-3.5" />
61
73
  }
62
74
 
63
75
  export interface FormSubmissionsProps {
64
- formId: string;
65
- onNavigate?: (path: string) => void;
76
+ formId: string
77
+ onNavigate?: (path: string) => void
66
78
  }
67
79
 
68
80
  export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
69
- const { data, loading, error, refetch } = useApiData<Submission[] | { submissions: Submission[] }>(`/forms/${formId}/submissions`);
70
- const [searchQuery, setSearchQuery] = useState('');
71
- const [filterStatus, setFilterStatus] = useState('all');
72
- const [filterSource, setFilterSource] = useState('all');
73
- const [expandedId, setExpandedId] = useState<number | null>(null);
81
+ const { data, loading, error, refetch } = useApiData<
82
+ Submission[] | { submissions: Submission[] }
83
+ >(`/forms/${formId}/submissions`)
84
+ const [searchQuery, setSearchQuery] = useState('')
85
+ const [filterStatus, setFilterStatus] = useState('all')
86
+ const [filterSource, setFilterSource] = useState('all')
87
+ const [expandedId, setExpandedId] = useState<number | null>(null)
74
88
 
75
- const submissions = Array.isArray(data) ? data : data?.submissions ?? [];
89
+ const submissions = Array.isArray(data) ? data : (data?.submissions ?? [])
76
90
 
77
91
  const filteredSubmissions = useMemo(() => {
78
92
  let results = submissions.filter((s) => {
79
93
  const matchesSearch =
80
94
  (s.name ?? '').toLowerCase().includes(searchQuery.toLowerCase()) ||
81
95
  (s.email ?? '').toLowerCase().includes(searchQuery.toLowerCase()) ||
82
- (s.message ?? '').toLowerCase().includes(searchQuery.toLowerCase());
83
- const matchesStatus = filterStatus === 'all' || s.status === filterStatus;
84
- const matchesSource = filterSource === 'all' || s.attribution?.source === filterSource;
85
- return matchesSearch && matchesStatus && matchesSource;
86
- });
96
+ (s.message ?? '').toLowerCase().includes(searchQuery.toLowerCase())
97
+ const matchesStatus = filterStatus === 'all' || s.status === filterStatus
98
+ const matchesSource = filterSource === 'all' || s.attribution?.source === filterSource
99
+ return matchesSearch && matchesStatus && matchesSource
100
+ })
87
101
 
88
102
  if (searchQuery.trim()) {
89
- results = sortByRelevance(results, searchQuery, (s) => [s.name, s.email, s.message]);
103
+ results = sortByRelevance(results, searchQuery, (s) => [s.name, s.email, s.message])
90
104
  }
91
- return results;
92
- }, [submissions, searchQuery, filterStatus, filterSource]);
105
+ return results
106
+ }, [submissions, searchQuery, filterStatus, filterSource])
93
107
 
94
- const uniqueSources = [...new Set(submissions.map(s => s.attribution?.source ?? '(direct)'))];
108
+ const uniqueSources = [...new Set(submissions.map((s) => s.attribution?.source ?? '(direct)'))]
95
109
 
96
110
  const sourceSummary = useMemo(() => {
97
- const counts: Record<string, number> = {};
111
+ const counts: Record<string, number> = {}
98
112
  for (const s of submissions) {
99
- const key = `${s.attribution?.source ?? '(direct)'} / ${s.attribution?.medium ?? '(none)'}`;
100
- counts[key] = (counts[key] ?? 0) + 1;
113
+ const key = `${s.attribution?.source ?? '(direct)'} / ${s.attribution?.medium ?? '(none)'}`
114
+ counts[key] = (counts[key] ?? 0) + 1
101
115
  }
102
- return Object.entries(counts).sort(([, a], [, b]) => b - a);
103
- }, [submissions]);
116
+ return Object.entries(counts).sort(([, a], [, b]) => b - a)
117
+ }, [submissions])
104
118
 
105
- const paidCount = submissions.filter(s => ['cpc', 'paid'].includes(s.attribution?.medium ?? '')).length;
106
- const organicCount = submissions.filter(s => s.attribution?.medium === 'organic').length;
119
+ const paidCount = submissions.filter((s) =>
120
+ ['cpc', 'paid'].includes(s.attribution?.medium ?? ''),
121
+ ).length
122
+ const organicCount = submissions.filter((s) => s.attribution?.medium === 'organic').length
107
123
 
108
124
  const handleExport = () => {
109
- toast.success('Submissions exported to CSV (includes attribution data)');
110
- };
125
+ toast.success('Submissions exported to CSV (includes attribution data)')
126
+ }
111
127
 
112
128
  if (loading) {
113
129
  return (
114
130
  <div className="p-3 pr-6 sm:p-4 sm:pr-8 flex items-center justify-center h-64">
115
131
  <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
116
132
  </div>
117
- );
133
+ )
118
134
  }
119
135
 
120
136
  return (
@@ -123,21 +139,38 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
123
139
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
124
140
  <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
125
141
  <span className="text-sm text-red-800 flex-1">{error}</span>
126
- <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>
142
+ <button
143
+ onClick={refetch}
144
+ className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
145
+ >
146
+ Retry
147
+ </button>
127
148
  </div>
128
149
  )}
129
150
 
130
151
  <div className="mb-4">
131
- <button onClick={() => onNavigate?.('/forms')} className="inline-flex items-center gap-2 text-sm text-gray-600 hover:text-gray-900 transition-colors mb-3">
132
- <ArrowLeft className="w-4 h-4" />Back to Forms
152
+ <button
153
+ onClick={() => onNavigate?.('/forms')}
154
+ className="inline-flex items-center gap-2 text-sm text-gray-600 hover:text-gray-900 transition-colors mb-3"
155
+ >
156
+ <ArrowLeft className="w-4 h-4" />
157
+ Back to Forms
133
158
  </button>
134
159
  <div className="flex items-center justify-between">
135
160
  <div>
136
- <h1 className="text-2xl font-semibold text-gray-900 mb-1">Contact Form - Submissions</h1>
137
- <p className="text-sm text-gray-600">{filteredSubmissions.length} submission{filteredSubmissions.length !== 1 ? 's' : ''}</p>
161
+ <h1 className="text-2xl font-semibold text-gray-900 mb-1">
162
+ Contact Form - Submissions
163
+ </h1>
164
+ <p className="text-sm text-gray-600">
165
+ {filteredSubmissions.length} submission{filteredSubmissions.length !== 1 ? 's' : ''}
166
+ </p>
138
167
  </div>
139
- <button onClick={handleExport} className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm">
140
- <Download className="w-4 h-4" />Export CSV
168
+ <button
169
+ onClick={handleExport}
170
+ className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm"
171
+ >
172
+ <Download className="w-4 h-4" />
173
+ Export CSV
141
174
  </button>
142
175
  </div>
143
176
  </div>
@@ -149,7 +182,9 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
149
182
  </div>
150
183
  <div className="bg-white rounded-lg border border-gray-200 p-4">
151
184
  <div className="text-xs text-gray-600 mb-1">New</div>
152
- <div className="text-2xl font-semibold text-blue-600">{submissions.filter(s => s.status === 'new').length}</div>
185
+ <div className="text-2xl font-semibold text-blue-600">
186
+ {submissions.filter((s) => s.status === 'new').length}
187
+ </div>
153
188
  </div>
154
189
  <div className="bg-white rounded-lg border border-gray-200 p-4">
155
190
  <div className="text-xs text-gray-600 mb-1">Paid Traffic</div>
@@ -166,12 +201,17 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
166
201
  </div>
167
202
 
168
203
  <div className="bg-white rounded-lg border border-gray-200 p-4 mb-4">
169
- <h3 className="text-sm font-semibold text-gray-900 mb-3 flex items-center gap-2"><Globe className="w-4 h-4 text-blue-600" />Lead Source Breakdown</h3>
204
+ <h3 className="text-sm font-semibold text-gray-900 mb-3 flex items-center gap-2">
205
+ <Globe className="w-4 h-4 text-blue-600" />
206
+ Lead Source Breakdown
207
+ </h3>
170
208
  <div className="flex flex-wrap gap-2">
171
209
  {sourceSummary.map(([label, count]) => (
172
210
  <div key={label} className="flex items-center gap-2 px-3 py-1.5 bg-gray-50 rounded-lg">
173
211
  <span className="text-sm font-medium text-gray-800">{label}</span>
174
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">{count}</span>
212
+ <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
213
+ {count}
214
+ </span>
175
215
  </div>
176
216
  ))}
177
217
  </div>
@@ -181,17 +221,35 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
181
221
  <div className="p-3 flex flex-col sm:flex-row gap-3">
182
222
  <div className="flex-1 relative">
183
223
  <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
184
- <input type="text" placeholder="Search submissions..." 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" />
224
+ <input
225
+ type="text"
226
+ placeholder="Search submissions..."
227
+ value={searchQuery}
228
+ onChange={(e) => setSearchQuery(e.target.value)}
229
+ 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"
230
+ />
185
231
  </div>
186
- <select value={filterStatus} onChange={(e) => setFilterStatus(e.target.value)} className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
232
+ <select
233
+ value={filterStatus}
234
+ onChange={(e) => setFilterStatus(e.target.value)}
235
+ className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
236
+ >
187
237
  <option value="all">All Status</option>
188
238
  <option value="new">New</option>
189
239
  <option value="read">Read</option>
190
240
  <option value="replied">Replied</option>
191
241
  </select>
192
- <select value={filterSource} onChange={(e) => setFilterSource(e.target.value)} className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
242
+ <select
243
+ value={filterSource}
244
+ onChange={(e) => setFilterSource(e.target.value)}
245
+ className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
246
+ >
193
247
  <option value="all">All Sources</option>
194
- {uniqueSources.map(src => <option key={src} value={src}>{src}</option>)}
248
+ {uniqueSources.map((src) => (
249
+ <option key={src} value={src}>
250
+ {src}
251
+ </option>
252
+ ))}
195
253
  </select>
196
254
  </div>
197
255
  </div>
@@ -203,12 +261,15 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
203
261
  ) : (
204
262
  <div className="space-y-3">
205
263
  {filteredSubmissions.map((submission) => {
206
- const expanded = expandedId === submission.id;
207
- const attr = submission.attribution;
208
- const activeClickIds = Object.entries(attr.clickIds).filter(([, v]) => v);
264
+ const expanded = expandedId === submission.id
265
+ const attr = submission.attribution
266
+ const activeClickIds = Object.entries(attr.clickIds).filter(([, v]) => v)
209
267
 
210
268
  return (
211
- <div key={submission.id} className="bg-white rounded-lg border border-gray-200 hover:shadow-md transition-shadow">
269
+ <div
270
+ key={submission.id}
271
+ className="bg-white rounded-lg border border-gray-200 hover:shadow-md transition-shadow"
272
+ >
212
273
  <div className="p-4">
213
274
  <div className="flex items-start justify-between mb-3">
214
275
  <div className="flex items-start gap-3 flex-1">
@@ -218,32 +279,67 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
218
279
  <div className="flex-1 min-w-0">
219
280
  <div className="flex items-center gap-2 mb-1">
220
281
  <h3 className="font-semibold text-gray-900 text-sm">{submission.name}</h3>
221
- <span className={`px-2 py-0.5 rounded-full text-xs font-medium ${submission.status === 'new' ? 'bg-blue-100 text-blue-800' : submission.status === 'read' ? 'bg-gray-100 text-gray-800' : 'bg-green-100 text-green-800'}`}>{submission.status}</span>
282
+ <span
283
+ className={`px-2 py-0.5 rounded-full text-xs font-medium ${submission.status === 'new' ? 'bg-blue-100 text-blue-800' : submission.status === 'read' ? 'bg-gray-100 text-gray-800' : 'bg-green-100 text-green-800'}`}
284
+ >
285
+ {submission.status}
286
+ </span>
287
+ </div>
288
+ <div className="text-xs text-gray-600 mb-2">
289
+ {submission.email}
290
+ {submission.phone ? ` · ${submission.phone}` : ''}
222
291
  </div>
223
- <div className="text-xs text-gray-600 mb-2">{submission.email}{submission.phone ? ` · ${submission.phone}` : ''}</div>
224
292
  <p className="text-sm text-gray-700">{submission.message}</p>
225
- <div className="text-xs text-gray-500 mt-2">Submitted {submission.submittedAt}</div>
293
+ <div className="text-xs text-gray-500 mt-2">
294
+ Submitted {submission.submittedAt}
295
+ </div>
226
296
  </div>
227
297
  </div>
228
- <button onClick={() => toast.success('Submission deleted')} className="p-1.5 hover:bg-gray-100 rounded transition-colors" title="Delete">
298
+ <button
299
+ onClick={() => toast.success('Submission deleted')}
300
+ className="p-1.5 hover:bg-gray-100 rounded transition-colors"
301
+ title="Delete"
302
+ >
229
303
  <Trash2 className="w-4 h-4 text-red-600" />
230
304
  </button>
231
305
  </div>
232
306
 
233
307
  <div className="flex flex-wrap items-center gap-2 mt-3 pt-3 border-t border-gray-100">
234
- <span className={`px-2 py-0.5 rounded-full text-xs font-medium ${sourceColor(attr.source)}`}>{attr.source}</span>
308
+ <span
309
+ className={`px-2 py-0.5 rounded-full text-xs font-medium ${sourceColor(attr.source)}`}
310
+ >
311
+ {attr.source}
312
+ </span>
235
313
  <span className="text-gray-400 text-xs">/</span>
236
- <span className={`px-2 py-0.5 rounded-full text-xs font-medium ${mediumColor(attr.medium)}`}>{attr.medium}</span>
237
- {attr.campaign && <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-800">{attr.campaign}</span>}
238
- <span className="flex items-center gap-1 text-xs text-gray-500"><DeviceIcon type={attr.deviceType} />{attr.deviceType}</span>
314
+ <span
315
+ className={`px-2 py-0.5 rounded-full text-xs font-medium ${mediumColor(attr.medium)}`}
316
+ >
317
+ {attr.medium}
318
+ </span>
319
+ {attr.campaign && (
320
+ <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-800">
321
+ {attr.campaign}
322
+ </span>
323
+ )}
324
+ <span className="flex items-center gap-1 text-xs text-gray-500">
325
+ <DeviceIcon type={attr.deviceType} />
326
+ {attr.deviceType}
327
+ </span>
239
328
  {activeClickIds.length > 0 && (
240
329
  <span className="flex items-center gap-1 text-xs text-gray-500">
241
330
  <MousePointerClick className="w-3.5 h-3.5" />
242
331
  {activeClickIds.map(([k]) => k).join(', ')}
243
332
  </span>
244
333
  )}
245
- <button onClick={() => setExpandedId(expanded ? null : submission.id)} className="ml-auto flex items-center gap-1 text-xs text-blue-600 hover:text-blue-800 transition-colors">
246
- {expanded ? <ChevronUp className="w-3.5 h-3.5" /> : <ChevronDown className="w-3.5 h-3.5" />}
334
+ <button
335
+ onClick={() => setExpandedId(expanded ? null : submission.id)}
336
+ className="ml-auto flex items-center gap-1 text-xs text-blue-600 hover:text-blue-800 transition-colors"
337
+ >
338
+ {expanded ? (
339
+ <ChevronUp className="w-3.5 h-3.5" />
340
+ ) : (
341
+ <ChevronDown className="w-3.5 h-3.5" />
342
+ )}
247
343
  {expanded ? 'Hide' : 'Attribution'}
248
344
  </button>
249
345
  </div>
@@ -252,23 +348,50 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
252
348
  <div className="mt-3 pt-3 border-t border-gray-100 bg-gray-50 rounded-lg p-4 text-sm space-y-4">
253
349
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
254
350
  <div>
255
- <h4 className="text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">Traffic Source</h4>
351
+ <h4 className="text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
352
+ Traffic Source
353
+ </h4>
256
354
  <div className="space-y-1.5">
257
- <div className="flex justify-between"><span className="text-gray-500">Source</span><span className="font-medium text-gray-900">{attr.source}</span></div>
258
- <div className="flex justify-between"><span className="text-gray-500">Medium</span><span className="font-medium text-gray-900">{attr.medium}</span></div>
259
- {attr.campaign && <div className="flex justify-between"><span className="text-gray-500">Campaign</span><span className="font-medium text-gray-900">{attr.campaign}</span></div>}
260
- {attr.term && <div className="flex justify-between"><span className="text-gray-500">Keyword</span><span className="font-medium text-gray-900">{attr.term}</span></div>}
261
- {attr.content && <div className="flex justify-between"><span className="text-gray-500">Content</span><span className="font-medium text-gray-900">{attr.content}</span></div>}
355
+ <div className="flex justify-between">
356
+ <span className="text-gray-500">Source</span>
357
+ <span className="font-medium text-gray-900">{attr.source}</span>
358
+ </div>
359
+ <div className="flex justify-between">
360
+ <span className="text-gray-500">Medium</span>
361
+ <span className="font-medium text-gray-900">{attr.medium}</span>
362
+ </div>
363
+ {attr.campaign && (
364
+ <div className="flex justify-between">
365
+ <span className="text-gray-500">Campaign</span>
366
+ <span className="font-medium text-gray-900">{attr.campaign}</span>
367
+ </div>
368
+ )}
369
+ {attr.term && (
370
+ <div className="flex justify-between">
371
+ <span className="text-gray-500">Keyword</span>
372
+ <span className="font-medium text-gray-900">{attr.term}</span>
373
+ </div>
374
+ )}
375
+ {attr.content && (
376
+ <div className="flex justify-between">
377
+ <span className="text-gray-500">Content</span>
378
+ <span className="font-medium text-gray-900">{attr.content}</span>
379
+ </div>
380
+ )}
262
381
  </div>
263
382
  </div>
264
383
  <div>
265
- <h4 className="text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">Page Context</h4>
384
+ <h4 className="text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
385
+ Page Context
386
+ </h4>
266
387
  <div className="space-y-1.5">
267
388
  <div>
268
389
  <span className="text-gray-500 text-xs">Landing Page</span>
269
390
  <div className="flex items-center gap-1 mt-0.5">
270
391
  <MapPin className="w-3 h-3 text-gray-400 shrink-0" />
271
- <span className="font-medium text-gray-900 text-xs break-all">{attr.landingPage}</span>
392
+ <span className="font-medium text-gray-900 text-xs break-all">
393
+ {attr.landingPage}
394
+ </span>
272
395
  </div>
273
396
  </div>
274
397
  {attr.referrer && (
@@ -276,41 +399,62 @@ export function FormSubmissions({ formId, onNavigate }: FormSubmissionsProps) {
276
399
  <span className="text-gray-500 text-xs">Referrer</span>
277
400
  <div className="flex items-center gap-1 mt-0.5">
278
401
  <ExternalLink className="w-3 h-3 text-gray-400 shrink-0" />
279
- <span className="font-medium text-gray-900 text-xs break-all">{attr.referrer}</span>
402
+ <span className="font-medium text-gray-900 text-xs break-all">
403
+ {attr.referrer}
404
+ </span>
280
405
  </div>
281
406
  </div>
282
407
  )}
283
- <div className="flex justify-between"><span className="text-gray-500">Device</span><span className="flex items-center gap-1 font-medium text-gray-900"><DeviceIcon type={attr.deviceType} />{attr.deviceType}</span></div>
408
+ <div className="flex justify-between">
409
+ <span className="text-gray-500">Device</span>
410
+ <span className="flex items-center gap-1 font-medium text-gray-900">
411
+ <DeviceIcon type={attr.deviceType} />
412
+ {attr.deviceType}
413
+ </span>
414
+ </div>
284
415
  </div>
285
416
  </div>
286
417
  </div>
287
418
  {activeClickIds.length > 0 && (
288
419
  <div>
289
- <h4 className="text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">Click IDs</h4>
420
+ <h4 className="text-xs font-semibold text-gray-600 uppercase tracking-wider mb-2">
421
+ Click IDs
422
+ </h4>
290
423
  <div className="flex flex-wrap gap-2">
291
424
  {activeClickIds.map(([key, val]) => (
292
- <div key={key} className="px-2.5 py-1 bg-white border border-gray-200 rounded-lg">
425
+ <div
426
+ key={key}
427
+ className="px-2.5 py-1 bg-white border border-gray-200 rounded-lg"
428
+ >
293
429
  <span className="text-xs text-gray-500">{key}: </span>
294
- <span className="text-xs font-mono text-gray-800">{String(val).slice(0, 20)}...</span>
430
+ <span className="text-xs font-mono text-gray-800">
431
+ {String(val).slice(0, 20)}...
432
+ </span>
295
433
  </div>
296
434
  ))}
297
435
  </div>
298
436
  </div>
299
437
  )}
300
- <div className="text-xs text-gray-500">Attribution captured {attr.capturedAt}</div>
438
+ <div className="text-xs text-gray-500">
439
+ Attribution captured {attr.capturedAt}
440
+ </div>
301
441
  </div>
302
442
  )}
303
443
  </div>
304
444
 
305
445
  <div className="px-4 py-3 border-t border-gray-200 flex items-center gap-2">
306
- <button className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">Reply</button>
307
- <button className="px-3 py-1.5 text-sm border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">Mark as Read</button>
446
+ <button className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
447
+ Reply
448
+ </button>
449
+ <button className="px-3 py-1.5 text-sm border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">
450
+ Mark as Read
451
+ </button>
308
452
  </div>
309
453
  </div>
310
- );
454
+ )
311
455
  })}
312
456
  </div>
313
457
  )}
314
458
  </div>
315
- );
459
+ )
316
460
  }