@actuate-media/cms-admin 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +8 -5
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/__tests__/layout/primitives.test.d.ts +2 -0
  5. package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
  6. package/dist/__tests__/layout/primitives.test.js +34 -0
  7. package/dist/__tests__/layout/primitives.test.js.map +1 -0
  8. package/dist/__tests__/lib/cv.test.d.ts +2 -0
  9. package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
  10. package/dist/__tests__/lib/cv.test.js +66 -0
  11. package/dist/__tests__/lib/cv.test.js.map +1 -0
  12. package/dist/actuate-admin.css +1 -1
  13. package/dist/assets/actuate-logo.d.ts +36 -0
  14. package/dist/assets/actuate-logo.d.ts.map +1 -0
  15. package/dist/assets/actuate-logo.js +15 -0
  16. package/dist/assets/actuate-logo.js.map +1 -0
  17. package/dist/components/Breadcrumbs.js +2 -2
  18. package/dist/components/CommandPalette.js +10 -10
  19. package/dist/components/ContentOverviewChart.js +3 -3
  20. package/dist/components/ErrorBoundary.js +1 -1
  21. package/dist/components/FocalPointPicker.js +2 -2
  22. package/dist/components/FolderTree.js +20 -20
  23. package/dist/components/LivePreview.js +3 -3
  24. package/dist/components/LocaleSwitcher.js +1 -1
  25. package/dist/components/MediaPickerModal.js +4 -4
  26. package/dist/components/PresenceIndicator.js +1 -1
  27. package/dist/components/SEOConfigPanel.d.ts +2 -0
  28. package/dist/components/SEOConfigPanel.d.ts.map +1 -0
  29. package/dist/components/SEOConfigPanel.js +174 -0
  30. package/dist/components/SEOConfigPanel.js.map +1 -0
  31. package/dist/components/SEOPanel.js +9 -9
  32. package/dist/components/SEOPerformance.js +2 -2
  33. package/dist/components/SchedulePublishDialog.js +1 -1
  34. package/dist/components/SharePreviewLinkDialog.js +1 -1
  35. package/dist/components/TipTapEditor.js +5 -5
  36. package/dist/components/VersionHistory.js +2 -2
  37. package/dist/components/ui/Badge.d.ts +33 -3
  38. package/dist/components/ui/Badge.d.ts.map +1 -1
  39. package/dist/components/ui/Badge.js +42 -8
  40. package/dist/components/ui/Badge.js.map +1 -1
  41. package/dist/components/ui/Button.d.ts +19 -8
  42. package/dist/components/ui/Button.d.ts.map +1 -1
  43. package/dist/components/ui/Button.js +35 -14
  44. package/dist/components/ui/Button.js.map +1 -1
  45. package/dist/components/ui/Card.d.ts +26 -0
  46. package/dist/components/ui/Card.d.ts.map +1 -0
  47. package/dist/components/ui/Card.js +45 -0
  48. package/dist/components/ui/Card.js.map +1 -0
  49. package/dist/components/ui/DataTable.js +1 -1
  50. package/dist/components/ui/Input.d.ts +15 -0
  51. package/dist/components/ui/Input.d.ts.map +1 -0
  52. package/dist/components/ui/Input.js +23 -0
  53. package/dist/components/ui/Input.js.map +1 -0
  54. package/dist/components/ui/SearchInput.js +1 -1
  55. package/dist/components/ui/Select.d.ts +16 -0
  56. package/dist/components/ui/Select.d.ts.map +1 -0
  57. package/dist/components/ui/Select.js +25 -0
  58. package/dist/components/ui/Select.js.map +1 -0
  59. package/dist/components/ui/Toast.js +1 -1
  60. package/dist/components/ui/index.d.ts +10 -4
  61. package/dist/components/ui/index.d.ts.map +1 -1
  62. package/dist/components/ui/index.js +5 -2
  63. package/dist/components/ui/index.js.map +1 -1
  64. package/dist/fields/BlockBuilderField.js +3 -3
  65. package/dist/fields/DateField.js +1 -1
  66. package/dist/fields/RelationshipField.js +3 -3
  67. package/dist/fields/TextField.js +1 -1
  68. package/dist/index.d.ts +2 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +3 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/layout/Header.js +1 -1
  73. package/dist/layout/Layout.d.ts +14 -0
  74. package/dist/layout/Layout.d.ts.map +1 -1
  75. package/dist/layout/Layout.js +17 -11
  76. package/dist/layout/Layout.js.map +1 -1
  77. package/dist/layout/Sidebar.d.ts.map +1 -1
  78. package/dist/layout/Sidebar.js +21 -11
  79. package/dist/layout/Sidebar.js.map +1 -1
  80. package/dist/layout/primitives/AdminShell.d.ts +43 -0
  81. package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
  82. package/dist/layout/primitives/AdminShell.js +51 -0
  83. package/dist/layout/primitives/AdminShell.js.map +1 -0
  84. package/dist/layout/primitives/Box.d.ts +19 -0
  85. package/dist/layout/primitives/Box.d.ts.map +1 -0
  86. package/dist/layout/primitives/Box.js +12 -0
  87. package/dist/layout/primitives/Box.js.map +1 -0
  88. package/dist/layout/primitives/Cluster.d.ts +27 -0
  89. package/dist/layout/primitives/Cluster.d.ts.map +1 -0
  90. package/dist/layout/primitives/Cluster.js +37 -0
  91. package/dist/layout/primitives/Cluster.js.map +1 -0
  92. package/dist/layout/primitives/Grid.d.ts +45 -0
  93. package/dist/layout/primitives/Grid.d.ts.map +1 -0
  94. package/dist/layout/primitives/Grid.js +59 -0
  95. package/dist/layout/primitives/Grid.js.map +1 -0
  96. package/dist/layout/primitives/PageContainer.d.ts +36 -0
  97. package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
  98. package/dist/layout/primitives/PageContainer.js +41 -0
  99. package/dist/layout/primitives/PageContainer.js.map +1 -0
  100. package/dist/layout/primitives/Split.d.ts +34 -0
  101. package/dist/layout/primitives/Split.d.ts.map +1 -0
  102. package/dist/layout/primitives/Split.js +27 -0
  103. package/dist/layout/primitives/Split.js.map +1 -0
  104. package/dist/layout/primitives/Stack.d.ts +23 -0
  105. package/dist/layout/primitives/Stack.d.ts.map +1 -0
  106. package/dist/layout/primitives/Stack.js +34 -0
  107. package/dist/layout/primitives/Stack.js.map +1 -0
  108. package/dist/layout/primitives/index.d.ts +30 -0
  109. package/dist/layout/primitives/index.d.ts.map +1 -0
  110. package/dist/layout/primitives/index.js +22 -0
  111. package/dist/layout/primitives/index.js.map +1 -0
  112. package/dist/layout/primitives/tokens.d.ts +48 -0
  113. package/dist/layout/primitives/tokens.d.ts.map +1 -0
  114. package/dist/layout/primitives/tokens.js +54 -0
  115. package/dist/layout/primitives/tokens.js.map +1 -0
  116. package/dist/lib/cv.d.ts +53 -0
  117. package/dist/lib/cv.d.ts.map +1 -0
  118. package/dist/lib/cv.js +39 -0
  119. package/dist/lib/cv.js.map +1 -0
  120. package/dist/views/ApiKeys.js +7 -7
  121. package/dist/views/CollectionList.js +8 -8
  122. package/dist/views/Dashboard.d.ts.map +1 -1
  123. package/dist/views/Dashboard.js +333 -78
  124. package/dist/views/Dashboard.js.map +1 -1
  125. package/dist/views/DocumentEdit.js +3 -3
  126. package/dist/views/ForgotPassword.js +2 -2
  127. package/dist/views/FormEditor.js +5 -5
  128. package/dist/views/FormSubmissions.js +6 -6
  129. package/dist/views/Forms.js +2 -2
  130. package/dist/views/Login.d.ts +16 -1
  131. package/dist/views/Login.d.ts.map +1 -1
  132. package/dist/views/Login.js +17 -7
  133. package/dist/views/Login.js.map +1 -1
  134. package/dist/views/MediaBrowser.js +16 -16
  135. package/dist/views/PageEditor.js +2 -2
  136. package/dist/views/Pages.js +10 -10
  137. package/dist/views/PostEditor.js +2 -2
  138. package/dist/views/Posts.js +4 -4
  139. package/dist/views/Redirects.js +4 -4
  140. package/dist/views/ResetPassword.js +2 -2
  141. package/dist/views/SEO.js +6 -6
  142. package/dist/views/ScriptTagEditor.js +4 -4
  143. package/dist/views/ScriptTags.js +2 -2
  144. package/dist/views/Settings.d.ts.map +1 -1
  145. package/dist/views/Settings.js +9 -8
  146. package/dist/views/Settings.js.map +1 -1
  147. package/dist/views/SetupWizard.js +2 -2
  148. package/dist/views/Users.js +4 -4
  149. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  150. package/dist/views/page-builder/AIGenerateDialog.js +10 -10
  151. package/dist/views/page-builder/BlockEditor.js +10 -10
  152. package/dist/views/page-builder/BlockPicker.js +4 -4
  153. package/dist/views/page-builder/BottomBar.js +1 -1
  154. package/dist/views/page-builder/BuilderToolbar.js +2 -2
  155. package/dist/views/page-builder/ContextPanel.js +2 -2
  156. package/dist/views/page-builder/DesignScore.js +9 -9
  157. package/dist/views/page-builder/NodeSettings.js +8 -8
  158. package/dist/views/page-builder/PageBuilder.js +3 -3
  159. package/dist/views/page-builder/PageSettings.js +1 -1
  160. package/dist/views/page-builder/PageTemplates.js +2 -2
  161. package/dist/views/page-builder/SEOPanel.js +13 -13
  162. package/dist/views/page-builder/SavedSections.js +5 -5
  163. package/dist/views/page-builder/TemplatePicker.js +2 -2
  164. package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
  165. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  166. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
  167. package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
  168. package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
  169. package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
  170. package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
  171. package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
  172. package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
  173. package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
  174. package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
  175. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
  176. package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
  177. package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
  178. package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
  179. package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
  180. package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
  181. package/package.json +6 -2
  182. package/src/AdminRoot.tsx +21 -11
  183. package/src/__tests__/layout/primitives.test.ts +37 -0
  184. package/src/__tests__/lib/cv.test.ts +74 -0
  185. package/src/assets/actuate-logo.tsx +72 -0
  186. package/src/components/Breadcrumbs.tsx +6 -6
  187. package/src/components/CommandPalette.tsx +34 -34
  188. package/src/components/ContentOverviewChart.tsx +3 -3
  189. package/src/components/ErrorBoundary.tsx +3 -3
  190. package/src/components/FocalPointPicker.tsx +4 -4
  191. package/src/components/FolderTree.tsx +38 -38
  192. package/src/components/LivePreview.tsx +16 -16
  193. package/src/components/LocaleSwitcher.tsx +7 -7
  194. package/src/components/MediaPickerModal.tsx +21 -21
  195. package/src/components/PresenceIndicator.tsx +2 -2
  196. package/src/components/SEOConfigPanel.tsx +582 -0
  197. package/src/components/SEOPanel.tsx +46 -46
  198. package/src/components/SEOPerformance.tsx +21 -21
  199. package/src/components/SchedulePublishDialog.tsx +4 -4
  200. package/src/components/SharePreviewLinkDialog.tsx +1 -1
  201. package/src/components/TipTapEditor.tsx +33 -33
  202. package/src/components/VersionHistory.tsx +16 -16
  203. package/src/components/ui/Badge.tsx +66 -14
  204. package/src/components/ui/Button.tsx +70 -33
  205. package/src/components/ui/Card.tsx +101 -0
  206. package/src/components/ui/DataTable.tsx +1 -1
  207. package/src/components/ui/Input.tsx +35 -0
  208. package/src/components/ui/SearchInput.tsx +4 -4
  209. package/src/components/ui/Select.tsx +56 -0
  210. package/src/components/ui/Toast.tsx +1 -1
  211. package/src/components/ui/index.ts +18 -4
  212. package/src/fields/BlockBuilderField.tsx +3 -3
  213. package/src/fields/DateField.tsx +1 -1
  214. package/src/fields/RelationshipField.tsx +10 -10
  215. package/src/fields/TextField.tsx +1 -1
  216. package/src/index.ts +28 -0
  217. package/src/layout/Header.tsx +28 -28
  218. package/src/layout/Layout.tsx +39 -46
  219. package/src/layout/Sidebar.tsx +37 -64
  220. package/src/layout/primitives/AdminShell.tsx +118 -0
  221. package/src/layout/primitives/Box.tsx +30 -0
  222. package/src/layout/primitives/Cluster.tsx +74 -0
  223. package/src/layout/primitives/Grid.tsx +120 -0
  224. package/src/layout/primitives/PageContainer.tsx +96 -0
  225. package/src/layout/primitives/Split.tsx +73 -0
  226. package/src/layout/primitives/Stack.tsx +67 -0
  227. package/src/layout/primitives/index.ts +36 -0
  228. package/src/layout/primitives/tokens.ts +76 -0
  229. package/src/lib/cv.ts +96 -0
  230. package/src/styles/build-input.css +1 -1
  231. package/src/views/ApiKeys.tsx +57 -57
  232. package/src/views/CollectionList.tsx +30 -30
  233. package/src/views/Dashboard.tsx +737 -186
  234. package/src/views/DocumentEdit.tsx +9 -9
  235. package/src/views/ForgotPassword.tsx +18 -18
  236. package/src/views/FormEditor.tsx +75 -75
  237. package/src/views/FormSubmissions.tsx +76 -76
  238. package/src/views/Forms.tsx +27 -27
  239. package/src/views/Login.tsx +65 -25
  240. package/src/views/MediaBrowser.tsx +127 -127
  241. package/src/views/PageEditor.tsx +25 -25
  242. package/src/views/Pages.tsx +59 -59
  243. package/src/views/PostEditor.tsx +37 -37
  244. package/src/views/Posts.tsx +48 -48
  245. package/src/views/Redirects.tsx +21 -21
  246. package/src/views/ResetPassword.tsx +28 -28
  247. package/src/views/SEO.tsx +144 -144
  248. package/src/views/ScriptTagEditor.tsx +24 -24
  249. package/src/views/ScriptTags.tsx +10 -10
  250. package/src/views/Settings.tsx +88 -80
  251. package/src/views/SetupWizard.tsx +28 -28
  252. package/src/views/Users.tsx +20 -20
  253. package/src/views/page-builder/AIBlockAssist.tsx +1 -1
  254. package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
  255. package/src/views/page-builder/BlockEditor.tsx +26 -26
  256. package/src/views/page-builder/BlockPicker.tsx +22 -22
  257. package/src/views/page-builder/BottomBar.tsx +8 -8
  258. package/src/views/page-builder/BuilderToolbar.tsx +17 -17
  259. package/src/views/page-builder/ContextPanel.tsx +3 -3
  260. package/src/views/page-builder/DesignScore.tsx +21 -21
  261. package/src/views/page-builder/NodeSettings.tsx +27 -27
  262. package/src/views/page-builder/PageBuilder.tsx +11 -11
  263. package/src/views/page-builder/PageSettings.tsx +4 -4
  264. package/src/views/page-builder/PageTemplates.tsx +18 -18
  265. package/src/views/page-builder/SEOPanel.tsx +53 -53
  266. package/src/views/page-builder/SavedSections.tsx +37 -37
  267. package/src/views/page-builder/TemplatePicker.tsx +17 -17
  268. package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
  269. package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
  270. package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
  271. package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
  272. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
  273. package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
  274. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
  275. package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
  276. package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
  277. package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
  278. package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
  279. package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
  280. package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
  281. package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
  282. package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
  283. package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
  284. package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
@@ -8,13 +8,13 @@ export function FormPreview({ data, variant = 'contact' }: BlockPreviewProps) {
8
8
 
9
9
  if (variant === 'newsletter') {
10
10
  return (
11
- <div className="rounded-md border border-border p-6 text-center">
12
- <Mail size={24} className="mx-auto text-muted-foreground" />
13
- <p className="mt-3 text-sm font-medium text-foreground">Newsletter Signup</p>
14
- {formId && <p className="mt-1 text-xs text-muted-foreground">Form: {formId}</p>}
11
+ <div className="border-border rounded-md border p-6 text-center">
12
+ <Mail size={24} className="text-muted-foreground mx-auto" />
13
+ <p className="text-foreground mt-3 text-sm font-medium">Newsletter Signup</p>
14
+ {formId && <p className="text-muted-foreground mt-1 text-xs">Form: {formId}</p>}
15
15
  <div className="mx-auto mt-4 flex max-w-xs gap-2">
16
- <div className="h-9 flex-1 rounded-md border border-border bg-input-background" />
17
- <div className="flex h-9 items-center rounded-md bg-primary px-3">
16
+ <div className="border-border bg-input-background h-9 flex-1 rounded-md border" />
17
+ <div className="bg-primary flex h-9 items-center rounded-md px-3">
18
18
  <Send size={14} className="text-primary-foreground" />
19
19
  </div>
20
20
  </div>
@@ -24,20 +24,20 @@ export function FormPreview({ data, variant = 'contact' }: BlockPreviewProps) {
24
24
 
25
25
  if (variant === 'custom') {
26
26
  return (
27
- <div className="rounded-md border border-border p-5">
27
+ <div className="border-border rounded-md border p-5">
28
28
  <div className="flex items-center gap-2">
29
29
  <FileText size={16} className="text-muted-foreground" />
30
- <p className="text-sm font-medium text-foreground">
30
+ <p className="text-foreground text-sm font-medium">
31
31
  {formId ? `Form: ${formId}` : 'Custom Form'}
32
32
  </p>
33
33
  </div>
34
34
  <div className="mt-3 flex flex-col gap-2">
35
- <div className="h-8 rounded-md border border-border bg-input-background" />
36
- <div className="h-8 rounded-md border border-border bg-input-background" />
37
- <div className="h-20 rounded-md border border-border bg-input-background" />
35
+ <div className="border-border bg-input-background h-8 rounded-md border" />
36
+ <div className="border-border bg-input-background h-8 rounded-md border" />
37
+ <div className="border-border bg-input-background h-20 rounded-md border" />
38
38
  </div>
39
39
  <div className="mt-3">
40
- <span className="inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground">
40
+ <span className="bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm">
41
41
  Submit
42
42
  </span>
43
43
  </div>
@@ -46,17 +46,17 @@ export function FormPreview({ data, variant = 'contact' }: BlockPreviewProps) {
46
46
  }
47
47
 
48
48
  return (
49
- <div className="rounded-md border border-border p-5">
50
- <p className="text-sm font-medium text-foreground">Contact Form</p>
51
- {formId && <p className="mt-1 text-xs text-muted-foreground">Form: {formId}</p>}
49
+ <div className="border-border rounded-md border p-5">
50
+ <p className="text-foreground text-sm font-medium">Contact Form</p>
51
+ {formId && <p className="text-muted-foreground mt-1 text-xs">Form: {formId}</p>}
52
52
  <div className="mt-3 grid grid-cols-2 gap-2">
53
- <div className="h-8 rounded-md border border-border bg-input-background" />
54
- <div className="h-8 rounded-md border border-border bg-input-background" />
53
+ <div className="border-border bg-input-background h-8 rounded-md border" />
54
+ <div className="border-border bg-input-background h-8 rounded-md border" />
55
55
  </div>
56
- <div className="mt-2 h-8 rounded-md border border-border bg-input-background" />
57
- <div className="mt-2 h-20 rounded-md border border-border bg-input-background" />
56
+ <div className="border-border bg-input-background mt-2 h-8 rounded-md border" />
57
+ <div className="border-border bg-input-background mt-2 h-20 rounded-md border" />
58
58
  <div className="mt-3">
59
- <span className="inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground">
59
+ <span className="bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm">
60
60
  Send Message
61
61
  </span>
62
62
  </div>
@@ -17,7 +17,7 @@ export function GalleryPreview({ data, variant = 'grid' }: BlockPreviewProps) {
17
17
 
18
18
  const Thumbnail = ({ item, className = '' }: { item: GalleryImage; className?: string }) => (
19
19
  <div
20
- className={`flex items-center justify-center overflow-hidden rounded-md bg-muted ${className}`}
20
+ className={`bg-muted flex items-center justify-center overflow-hidden rounded-md ${className}`}
21
21
  >
22
22
  {item.src ? (
23
23
  <img src={item.src} alt={item.alt || ''} className="h-full w-full object-cover" />
@@ -29,7 +29,7 @@ export function GalleryPreview({ data, variant = 'grid' }: BlockPreviewProps) {
29
29
 
30
30
  if (variant === 'masonry') {
31
31
  return (
32
- <div className="rounded-md border border-border p-4">
32
+ <div className="border-border rounded-md border p-4">
33
33
  <div className="columns-3 gap-3 space-y-3">
34
34
  {placeholders.map((item, i) => (
35
35
  <Thumbnail
@@ -47,14 +47,14 @@ export function GalleryPreview({ data, variant = 'grid' }: BlockPreviewProps) {
47
47
 
48
48
  if (variant === 'carousel') {
49
49
  return (
50
- <div className="overflow-hidden rounded-md border border-border p-4">
50
+ <div className="border-border overflow-hidden rounded-md border p-4">
51
51
  <div className="flex gap-3 overflow-hidden">
52
52
  {placeholders.slice(0, 4).map((item, i) => (
53
53
  <Thumbnail key={i} item={item} className="aspect-square min-w-[120px] flex-1" />
54
54
  ))}
55
55
  {placeholders.length > 4 && (
56
- <div className="flex min-w-[120px] flex-1 items-center justify-center rounded-md bg-muted">
57
- <span className="text-sm text-muted-foreground">+{placeholders.length - 4}</span>
56
+ <div className="bg-muted flex min-w-[120px] flex-1 items-center justify-center rounded-md">
57
+ <span className="text-muted-foreground text-sm">+{placeholders.length - 4}</span>
58
58
  </div>
59
59
  )}
60
60
  </div>
@@ -64,19 +64,19 @@ export function GalleryPreview({ data, variant = 'grid' }: BlockPreviewProps) {
64
64
 
65
65
  if (variant === 'lightbox') {
66
66
  return (
67
- <div className="rounded-md border border-border p-4">
67
+ <div className="border-border rounded-md border p-4">
68
68
  <div className="grid grid-cols-3 gap-3">
69
69
  {placeholders.map((item, i) => (
70
70
  <Thumbnail key={i} item={item} className="aspect-square" />
71
71
  ))}
72
72
  </div>
73
- <p className="mt-2 text-center text-xs text-muted-foreground">Click to open lightbox</p>
73
+ <p className="text-muted-foreground mt-2 text-center text-xs">Click to open lightbox</p>
74
74
  </div>
75
75
  )
76
76
  }
77
77
 
78
78
  return (
79
- <div className="rounded-md border border-border p-4">
79
+ <div className="border-border rounded-md border p-4">
80
80
  <div className="grid grid-cols-3 gap-3">
81
81
  {placeholders.map((item, i) => (
82
82
  <Thumbnail key={i} item={item} className="aspect-square" />
@@ -12,23 +12,23 @@ export function HeroPreview({ data, variant = 'centered' }: BlockPreviewProps) {
12
12
 
13
13
  if (variant === 'split-image') {
14
14
  return (
15
- <div className="flex min-h-[200px] overflow-hidden rounded-md border border-border">
15
+ <div className="border-border flex min-h-[200px] overflow-hidden rounded-md border">
16
16
  <div className="flex flex-1 flex-col justify-center gap-3 p-6">
17
- <h2 className="text-2xl font-medium text-foreground">
17
+ <h2 className="text-foreground text-2xl font-medium">
18
18
  {title || <span className="text-muted-foreground">Hero Title</span>}
19
19
  </h2>
20
20
  {(subtitle || !title) && (
21
- <p className="text-sm text-muted-foreground">{subtitle || 'Subtitle text goes here'}</p>
21
+ <p className="text-muted-foreground text-sm">{subtitle || 'Subtitle text goes here'}</p>
22
22
  )}
23
23
  {ctaText && (
24
24
  <div className="mt-2">
25
- <span className="inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground">
25
+ <span className="bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm">
26
26
  {ctaText}
27
27
  </span>
28
28
  </div>
29
29
  )}
30
30
  </div>
31
- <div className="flex flex-1 items-center justify-center bg-muted">
31
+ <div className="bg-muted flex flex-1 items-center justify-center">
32
32
  {image ? (
33
33
  <img src={image} alt="" className="h-full w-full object-cover" />
34
34
  ) : (
@@ -41,15 +41,15 @@ export function HeroPreview({ data, variant = 'centered' }: BlockPreviewProps) {
41
41
 
42
42
  if (variant === 'minimal') {
43
43
  return (
44
- <div className="flex flex-col items-center gap-3 rounded-md border border-border p-8">
45
- <h2 className="text-2xl font-medium text-foreground">
44
+ <div className="border-border flex flex-col items-center gap-3 rounded-md border p-8">
45
+ <h2 className="text-foreground text-2xl font-medium">
46
46
  {title || <span className="text-muted-foreground">Hero Title</span>}
47
47
  </h2>
48
48
  {(subtitle || !title) && (
49
- <p className="text-sm text-muted-foreground">{subtitle || 'Subtitle text goes here'}</p>
49
+ <p className="text-muted-foreground text-sm">{subtitle || 'Subtitle text goes here'}</p>
50
50
  )}
51
51
  {ctaText && (
52
- <span className="mt-2 inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground">
52
+ <span className="bg-primary text-primary-foreground mt-2 inline-block rounded-md px-4 py-2 text-sm">
53
53
  {ctaText}
54
54
  </span>
55
55
  )}
@@ -60,27 +60,27 @@ export function HeroPreview({ data, variant = 'centered' }: BlockPreviewProps) {
60
60
  const isVideo = variant === 'video-bg'
61
61
 
62
62
  return (
63
- <div className="relative flex min-h-[220px] flex-col items-center justify-center gap-3 overflow-hidden rounded-md border border-border p-8">
63
+ <div className="border-border relative flex min-h-[220px] flex-col items-center justify-center gap-3 overflow-hidden rounded-md border p-8">
64
64
  {image ? (
65
65
  <img src={image} alt="" className="absolute inset-0 h-full w-full object-cover" />
66
66
  ) : (
67
- <div className="absolute inset-0 bg-muted" />
67
+ <div className="bg-muted absolute inset-0" />
68
68
  )}
69
- <div className="absolute inset-0 bg-background" style={{ opacity: overlayOpacity }} />
69
+ <div className="bg-background absolute inset-0" style={{ opacity: overlayOpacity }} />
70
70
  <div className="relative z-10 flex flex-col items-center gap-3 text-center">
71
71
  {isVideo && (
72
- <div className="mb-2 flex h-12 w-12 items-center justify-center rounded-full bg-primary/90">
72
+ <div className="bg-primary/90 mb-2 flex h-12 w-12 items-center justify-center rounded-full">
73
73
  <Play size={20} className="text-primary-foreground" />
74
74
  </div>
75
75
  )}
76
- <h2 className="text-2xl font-medium text-foreground">
76
+ <h2 className="text-foreground text-2xl font-medium">
77
77
  {title || <span className="text-muted-foreground">Hero Title</span>}
78
78
  </h2>
79
79
  {(subtitle || !title) && (
80
- <p className="text-sm text-muted-foreground">{subtitle || 'Subtitle text goes here'}</p>
80
+ <p className="text-muted-foreground text-sm">{subtitle || 'Subtitle text goes here'}</p>
81
81
  )}
82
82
  {ctaText && (
83
- <span className="mt-2 inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground">
83
+ <span className="bg-primary text-primary-foreground mt-2 inline-block rounded-md px-4 py-2 text-sm">
84
84
  {ctaText}
85
85
  </span>
86
86
  )}
@@ -13,7 +13,7 @@ export function ImagePreview({ data, variant = 'full-width' }: BlockPreviewProps
13
13
 
14
14
  const ImagePlaceholder = ({ className = '' }: { className?: string }) => (
15
15
  <div
16
- className={`flex items-center justify-center bg-muted ${roundedClass} ${className}`}
16
+ className={`bg-muted flex items-center justify-center ${roundedClass} ${className}`}
17
17
  style={{ aspectRatio }}
18
18
  >
19
19
  <Image size={32} className="text-muted-foreground" />
@@ -34,7 +34,7 @@ export function ImagePreview({ data, variant = 'full-width' }: BlockPreviewProps
34
34
 
35
35
  if (variant === 'side-by-side') {
36
36
  return (
37
- <div className="grid grid-cols-2 gap-3 rounded-md border border-border p-4">
37
+ <div className="border-border grid grid-cols-2 gap-3 rounded-md border p-4">
38
38
  <ImageElement />
39
39
  <ImagePlaceholder />
40
40
  </div>
@@ -42,10 +42,10 @@ export function ImagePreview({ data, variant = 'full-width' }: BlockPreviewProps
42
42
  }
43
43
 
44
44
  return (
45
- <figure className="overflow-hidden rounded-md border border-border p-4">
45
+ <figure className="border-border overflow-hidden rounded-md border p-4">
46
46
  <ImageElement />
47
47
  {(variant === 'captioned' || caption) && (
48
- <figcaption className="mt-2 text-center text-sm text-muted-foreground">
48
+ <figcaption className="text-muted-foreground mt-2 text-center text-sm">
49
49
  {caption || 'Image caption'}
50
50
  </figcaption>
51
51
  )}
@@ -26,17 +26,17 @@ export function TextPreview({ data, variant = 'prose' }: BlockPreviewProps) {
26
26
  const col2 = truncatedBody.slice(midpoint)
27
27
 
28
28
  return (
29
- <div className="rounded-md border border-border p-5">
29
+ <div className="border-border rounded-md border p-5">
30
30
  {heading && (
31
- <HeadingTag className={`${headingSizeClass} mb-3 font-medium text-foreground`}>
31
+ <HeadingTag className={`${headingSizeClass} text-foreground mb-3 font-medium`}>
32
32
  {heading}
33
33
  </HeadingTag>
34
34
  )}
35
35
  <div className="grid grid-cols-2 gap-4">
36
- <p className="text-sm leading-relaxed text-muted-foreground">
36
+ <p className="text-muted-foreground text-sm leading-relaxed">
37
37
  {col1 || 'Column one text content…'}
38
38
  </p>
39
- <p className="text-sm leading-relaxed text-muted-foreground">
39
+ <p className="text-muted-foreground text-sm leading-relaxed">
40
40
  {col2 || 'Column two text content…'}
41
41
  </p>
42
42
  </div>
@@ -46,34 +46,34 @@ export function TextPreview({ data, variant = 'prose' }: BlockPreviewProps) {
46
46
 
47
47
  if (variant === 'with-sidebar') {
48
48
  return (
49
- <div className="grid grid-cols-[1fr_200px] gap-4 rounded-md border border-border p-5">
49
+ <div className="border-border grid grid-cols-[1fr_200px] gap-4 rounded-md border p-5">
50
50
  <div>
51
51
  {heading && (
52
- <HeadingTag className={`${headingSizeClass} mb-3 font-medium text-foreground`}>
52
+ <HeadingTag className={`${headingSizeClass} text-foreground mb-3 font-medium`}>
53
53
  {heading}
54
54
  </HeadingTag>
55
55
  )}
56
- <p className="text-sm leading-relaxed text-muted-foreground">
56
+ <p className="text-muted-foreground text-sm leading-relaxed">
57
57
  {truncatedBody || 'Body text content goes here…'}
58
58
  </p>
59
59
  </div>
60
- <aside className="rounded-md bg-muted p-3">
61
- <div className="h-3 w-3/4 rounded bg-border" />
62
- <div className="mt-2 h-2 w-full rounded bg-border" />
63
- <div className="mt-1 h-2 w-2/3 rounded bg-border" />
60
+ <aside className="bg-muted rounded-md p-3">
61
+ <div className="bg-border h-3 w-3/4 rounded" />
62
+ <div className="bg-border mt-2 h-2 w-full rounded" />
63
+ <div className="bg-border mt-1 h-2 w-2/3 rounded" />
64
64
  </aside>
65
65
  </div>
66
66
  )
67
67
  }
68
68
 
69
69
  return (
70
- <div className="rounded-md border border-border p-5">
70
+ <div className="border-border rounded-md border p-5">
71
71
  {heading && (
72
- <HeadingTag className={`${headingSizeClass} mb-3 font-medium text-foreground`}>
72
+ <HeadingTag className={`${headingSizeClass} text-foreground mb-3 font-medium`}>
73
73
  {heading}
74
74
  </HeadingTag>
75
75
  )}
76
- <p className="text-sm leading-relaxed text-muted-foreground">
76
+ <p className="text-muted-foreground text-sm leading-relaxed">
77
77
  {truncatedBody || <span className="italic">Body text content goes here…</span>}
78
78
  </p>
79
79
  </div>
@@ -13,21 +13,21 @@ export function VideoPreview({ data, variant = 'inline' }: BlockPreviewProps) {
13
13
  )
14
14
 
15
15
  const content = (
16
- <div className="relative flex aspect-video items-center justify-center overflow-hidden rounded-md bg-muted">
16
+ <div className="bg-muted relative flex aspect-video items-center justify-center overflow-hidden rounded-md">
17
17
  {poster ? (
18
18
  <img src={poster} alt="" className="absolute inset-0 h-full w-full object-cover" />
19
19
  ) : (
20
- <div className="absolute inset-0 bg-card" />
20
+ <div className="bg-card absolute inset-0" />
21
21
  )}
22
- <div className="relative z-10 flex h-12 w-12 items-center justify-center rounded-full bg-primary/90 shadow-sm">
22
+ <div className="bg-primary/90 relative z-10 flex h-12 w-12 items-center justify-center rounded-full shadow-sm">
23
23
  <Play size={20} className="text-primary-foreground" />
24
24
  </div>
25
25
  {badges.length > 0 && (
26
- <div className="absolute bottom-2 right-2 z-10 flex gap-1">
26
+ <div className="absolute right-2 bottom-2 z-10 flex gap-1">
27
27
  {badges.map((badge) => (
28
28
  <span
29
29
  key={badge}
30
- className="rounded bg-background/80 px-1.5 py-0.5 text-xs text-muted-foreground"
30
+ className="bg-background/80 text-muted-foreground rounded px-1.5 py-0.5 text-xs"
31
31
  >
32
32
  {badge}
33
33
  </span>
@@ -39,15 +39,15 @@ export function VideoPreview({ data, variant = 'inline' }: BlockPreviewProps) {
39
39
 
40
40
  if (variant === 'background') {
41
41
  return (
42
- <div className="overflow-hidden rounded-md border border-border">
42
+ <div className="border-border overflow-hidden rounded-md border">
43
43
  <div className="relative aspect-[21/9]">
44
44
  {poster ? (
45
45
  <img src={poster} alt="" className="absolute inset-0 h-full w-full object-cover" />
46
46
  ) : (
47
- <div className="absolute inset-0 bg-card" />
47
+ <div className="bg-card absolute inset-0" />
48
48
  )}
49
- <div className="absolute inset-0 flex items-center justify-center bg-background/30">
50
- <div className="flex h-14 w-14 items-center justify-center rounded-full bg-primary/90 shadow-sm">
49
+ <div className="bg-background/30 absolute inset-0 flex items-center justify-center">
50
+ <div className="bg-primary/90 flex h-14 w-14 items-center justify-center rounded-full shadow-sm">
51
51
  <Play size={24} className="text-primary-foreground" />
52
52
  </div>
53
53
  </div>
@@ -58,10 +58,10 @@ export function VideoPreview({ data, variant = 'inline' }: BlockPreviewProps) {
58
58
 
59
59
  if (variant === 'lightbox') {
60
60
  return (
61
- <div className="rounded-md border border-border p-4">
61
+ <div className="border-border rounded-md border p-4">
62
62
  <div className="mx-auto max-w-sm">
63
63
  {content}
64
- <p className="mt-2 text-center text-xs text-muted-foreground">
64
+ <p className="text-muted-foreground mt-2 text-center text-xs">
65
65
  Click to play in lightbox
66
66
  </p>
67
67
  </div>
@@ -69,5 +69,5 @@ export function VideoPreview({ data, variant = 'inline' }: BlockPreviewProps) {
69
69
  )
70
70
  }
71
71
 
72
- return <div className="rounded-md border border-border p-4">{content}</div>
72
+ return <div className="border-border rounded-md border p-4">{content}</div>
73
73
  }
@@ -37,21 +37,21 @@ export function BlockRenderer({ node, selectedNodeId, onSelectNode }: BlockRende
37
37
  <div
38
38
  data-node-id={node.id}
39
39
  className={`relative min-h-[48px] transition-shadow ${
40
- isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''
40
+ isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
41
41
  }`}
42
42
  onClick={handleClick}
43
43
  onMouseEnter={() => setHovered(true)}
44
44
  onMouseLeave={() => setHovered(false)}
45
45
  >
46
46
  {(hovered || isSelected) && (
47
- <span className="absolute -top-2 -left-1 text-xs px-1.5 py-0.5 bg-primary text-primary-foreground rounded font-medium z-10">
47
+ <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
48
48
  {label}
49
49
  </span>
50
50
  )}
51
51
 
52
- <div className="flex items-center justify-center gap-2 p-4 bg-muted/30 border border-dashed border-border rounded-md">
52
+ <div className="bg-muted/30 border-border flex items-center justify-center gap-2 rounded-md border border-dashed p-4">
53
53
  <Icon size={16} className="text-muted-foreground" />
54
- <span className="text-sm text-muted-foreground">{label}</span>
54
+ <span className="text-muted-foreground text-sm">{label}</span>
55
55
  </div>
56
56
  </div>
57
57
  )
@@ -32,11 +32,11 @@ export function BuilderCanvas({
32
32
  }
33
33
 
34
34
  return (
35
- <div className="relative flex-1 overflow-auto bg-muted p-6" onClick={handleCanvasClick}>
35
+ <div className="bg-muted relative flex-1 overflow-auto p-6" onClick={handleCanvasClick}>
36
36
  {showGridOverlay && <GridOverlay deviceMode={deviceMode} />}
37
37
 
38
38
  <div
39
- className={`relative bg-background shadow-sm min-h-full ${DEVICE_CLASSES[deviceMode]}`}
39
+ className={`bg-background relative min-h-full shadow-sm ${DEVICE_CLASSES[deviceMode]}`}
40
40
  onClick={handleCanvasClick}
41
41
  >
42
42
  {tree.children.map((child) => {
@@ -54,10 +54,10 @@ export function BuilderCanvas({
54
54
  })}
55
55
 
56
56
  {tree.children.length === 0 && (
57
- <div className="flex flex-col items-center justify-center min-h-[400px] text-center">
57
+ <div className="flex min-h-[400px] flex-col items-center justify-center text-center">
58
58
  <LayoutGrid size={32} className="text-muted-foreground mb-3" />
59
- <p className="text-sm font-medium text-foreground mb-1">No sections yet</p>
60
- <p className="text-xs text-muted-foreground">
59
+ <p className="text-foreground mb-1 text-sm font-medium">No sections yet</p>
60
+ <p className="text-muted-foreground text-xs">
61
61
  Click "Add Section" below to start building your page
62
62
  </p>
63
63
  </div>
@@ -76,7 +76,7 @@ function GridOverlay({ deviceMode }: { deviceMode: BuilderCanvasProps['deviceMod
76
76
  aria-hidden="true"
77
77
  >
78
78
  <div
79
- className={`grid grid-cols-12 gap-4 h-full opacity-[0.08] ${DEVICE_CLASSES[deviceMode]}`}
79
+ className={`grid h-full grid-cols-12 gap-4 opacity-[0.08] ${DEVICE_CLASSES[deviceMode]}`}
80
80
  >
81
81
  {Array.from({ length: 12 }).map((_, i) => (
82
82
  <div key={i} className="bg-primary h-full rounded-sm" />
@@ -26,7 +26,7 @@ export function ColumnRenderer({ node, selectedNodeId, onSelectNode }: ColumnRen
26
26
  <div
27
27
  data-node-id={node.id}
28
28
  className={`relative transition-shadow ${
29
- isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''
29
+ isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
30
30
  }`}
31
31
  style={{
32
32
  gridColumn: `span ${width}`,
@@ -41,13 +41,13 @@ export function ColumnRenderer({ node, selectedNodeId, onSelectNode }: ColumnRen
41
41
  onMouseLeave={() => setHovered(false)}
42
42
  >
43
43
  {(hovered || isSelected) && (
44
- <span className="absolute -top-2 -left-1 text-xs px-1.5 py-0.5 bg-primary text-primary-foreground rounded font-medium z-10">
44
+ <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
45
45
  Col {width}
46
46
  </span>
47
47
  )}
48
48
 
49
49
  {isEmpty ? (
50
- <div className="flex items-center justify-center min-h-[64px] border-2 border-dashed border-border rounded-md text-sm text-muted-foreground">
50
+ <div className="border-border text-muted-foreground flex min-h-[64px] items-center justify-center rounded-md border-2 border-dashed text-sm">
51
51
  Empty column
52
52
  </div>
53
53
  ) : (
@@ -32,7 +32,7 @@ export function ContainerRenderer({ node, selectedNodeId, onSelectNode }: Contai
32
32
  <div
33
33
  data-node-id={node.id}
34
34
  className={`relative transition-shadow ${
35
- isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''
35
+ isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
36
36
  }`}
37
37
  style={{
38
38
  maxWidth,
@@ -47,7 +47,7 @@ export function ContainerRenderer({ node, selectedNodeId, onSelectNode }: Contai
47
47
  onMouseLeave={() => setHovered(false)}
48
48
  >
49
49
  {(hovered || isSelected) && (
50
- <span className="absolute -top-2 -left-1 text-xs px-1.5 py-0.5 bg-primary text-primary-foreground rounded font-medium z-10">
50
+ <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
51
51
  Container
52
52
  </span>
53
53
  )}
@@ -32,7 +32,7 @@ export function RowRenderer({ node, selectedNodeId, onSelectNode }: RowRendererP
32
32
  <div
33
33
  data-node-id={node.id}
34
34
  className={`relative transition-shadow ${
35
- isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''
35
+ isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
36
36
  }`}
37
37
  onClick={handleClick}
38
38
  onMouseEnter={(e) => {
@@ -42,7 +42,7 @@ export function RowRenderer({ node, selectedNodeId, onSelectNode }: RowRendererP
42
42
  onMouseLeave={() => setHovered(false)}
43
43
  >
44
44
  {(hovered || isSelected) && (
45
- <span className="absolute -top-2 -left-1 text-xs px-1.5 py-0.5 bg-primary text-primary-foreground rounded font-medium z-10">
45
+ <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
46
46
  Row
47
47
  </span>
48
48
  )}
@@ -49,7 +49,7 @@ export function SectionRenderer({ node, selectedNodeId, onSelectNode }: SectionR
49
49
  <div
50
50
  data-node-id={node.id}
51
51
  className={`relative w-full transition-shadow ${
52
- isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''
52
+ isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
53
53
  }`}
54
54
  style={backgroundStyle}
55
55
  onClick={handleClick}
@@ -60,7 +60,7 @@ export function SectionRenderer({ node, selectedNodeId, onSelectNode }: SectionR
60
60
  onMouseLeave={() => setHovered(false)}
61
61
  >
62
62
  {(hovered || isSelected) && (
63
- <span className="absolute -top-2 -left-1 text-xs px-1.5 py-0.5 bg-primary text-primary-foreground rounded font-medium z-10">
63
+ <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
64
64
  Section
65
65
  </span>
66
66
  )}