@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
@@ -17,11 +17,11 @@ export function FAQPreview({ data, variant = 'accordion' }) {
17
17
  const mid = Math.ceil(placeholderItems.length / 2);
18
18
  const col1 = placeholderItems.slice(0, mid);
19
19
  const col2 = placeholderItems.slice(mid);
20
- return (_jsx("div", { className: "rounded-md border border-border p-4", children: _jsx("div", { className: "grid grid-cols-2 gap-4", children: [col1, col2].map((column, colIdx) => (_jsx("div", { className: "flex flex-col gap-3", children: column.map((item, i) => (_jsxs("div", { className: "rounded-md border border-border p-3", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: item.question || 'Question?' }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground line-clamp-2", children: item.answer || 'Answer text…' })] }, i))) }, colIdx))) }) }));
20
+ return (_jsx("div", { className: "border-border rounded-md border p-4", children: _jsx("div", { className: "grid grid-cols-2 gap-4", children: [col1, col2].map((column, colIdx) => (_jsx("div", { className: "flex flex-col gap-3", children: column.map((item, i) => (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: item.question || 'Question?' }), _jsx("p", { className: "text-muted-foreground mt-1 line-clamp-2 text-xs", children: item.answer || 'Answer text…' })] }, i))) }, colIdx))) }) }));
21
21
  }
22
22
  if (variant === 'list') {
23
- return (_jsx("div", { className: "rounded-md border border-border p-4", children: _jsx("div", { className: "flex flex-col gap-3", children: placeholderItems.map((item, i) => (_jsxs("div", { className: "border-b border-border pb-3 last:border-b-0 last:pb-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: item.question || 'Question?' }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground line-clamp-2", children: item.answer || 'Answer text…' })] }, i))) }) }));
23
+ return (_jsx("div", { className: "border-border rounded-md border p-4", children: _jsx("div", { className: "flex flex-col gap-3", children: placeholderItems.map((item, i) => (_jsxs("div", { className: "border-border border-b pb-3 last:border-b-0 last:pb-0", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: item.question || 'Question?' }), _jsx("p", { className: "text-muted-foreground mt-1 line-clamp-2 text-xs", children: item.answer || 'Answer text…' })] }, i))) }) }));
24
24
  }
25
- return (_jsx("div", { className: "rounded-md border border-border p-4", children: _jsx("div", { className: "flex flex-col gap-2", children: placeholderItems.map((item, i) => (_jsxs("div", { className: "rounded-md border border-border p-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: item.question || 'Question?' }), _jsx(ChevronDown, { size: 14, className: "shrink-0 text-muted-foreground" })] }), i === 0 && (_jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: item.answer || 'Answer text…' }))] }, i))) }) }));
25
+ return (_jsx("div", { className: "border-border rounded-md border p-4", children: _jsx("div", { className: "flex flex-col gap-2", children: placeholderItems.map((item, i) => (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: item.question || 'Question?' }), _jsx(ChevronDown, { size: 14, className: "text-muted-foreground shrink-0" })] }), i === 0 && (_jsx("p", { className: "text-muted-foreground mt-2 text-xs", children: item.answer || 'Answer text…' }))] }, i))) }) }));
26
26
  }
27
27
  //# sourceMappingURL=FAQPreview.js.map
@@ -2,6 +2,6 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Box } from 'lucide-react';
4
4
  export function FallbackPreview({ blockType }) {
5
- return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 rounded-md border border-dashed border-border bg-muted/50 p-8", children: [_jsx(Box, { size: 24, className: "text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: blockType }), _jsx("p", { className: "text-xs text-muted-foreground", children: "No preview available" })] }));
5
+ return (_jsxs("div", { className: "border-border bg-muted/50 flex flex-col items-center justify-center gap-2 rounded-md border border-dashed p-8", children: [_jsx(Box, { size: 24, className: "text-muted-foreground" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: blockType }), _jsx("p", { className: "text-muted-foreground text-xs", children: "No preview available" })] }));
6
6
  }
7
7
  //# sourceMappingURL=FallbackPreview.js.map
@@ -4,11 +4,11 @@ import { FileText, Mail, Send } from 'lucide-react';
4
4
  export function FormPreview({ data, variant = 'contact' }) {
5
5
  const formId = data.formId || '';
6
6
  if (variant === 'newsletter') {
7
- return (_jsxs("div", { className: "rounded-md border border-border p-6 text-center", children: [_jsx(Mail, { size: 24, className: "mx-auto text-muted-foreground" }), _jsx("p", { className: "mt-3 text-sm font-medium text-foreground", children: "Newsletter Signup" }), formId && _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["Form: ", formId] }), _jsxs("div", { className: "mx-auto mt-4 flex max-w-xs gap-2", children: [_jsx("div", { className: "h-9 flex-1 rounded-md border border-border bg-input-background" }), _jsx("div", { className: "flex h-9 items-center rounded-md bg-primary px-3", children: _jsx(Send, { size: 14, className: "text-primary-foreground" }) })] })] }));
7
+ return (_jsxs("div", { className: "border-border rounded-md border p-6 text-center", children: [_jsx(Mail, { size: 24, className: "text-muted-foreground mx-auto" }), _jsx("p", { className: "text-foreground mt-3 text-sm font-medium", children: "Newsletter Signup" }), formId && _jsxs("p", { className: "text-muted-foreground mt-1 text-xs", children: ["Form: ", formId] }), _jsxs("div", { className: "mx-auto mt-4 flex max-w-xs gap-2", children: [_jsx("div", { className: "border-border bg-input-background h-9 flex-1 rounded-md border" }), _jsx("div", { className: "bg-primary flex h-9 items-center rounded-md px-3", children: _jsx(Send, { size: 14, className: "text-primary-foreground" }) })] })] }));
8
8
  }
9
9
  if (variant === 'custom') {
10
- return (_jsxs("div", { className: "rounded-md border border-border p-5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FileText, { size: 16, className: "text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-foreground", children: formId ? `Form: ${formId}` : 'Custom Form' })] }), _jsxs("div", { className: "mt-3 flex flex-col gap-2", children: [_jsx("div", { className: "h-8 rounded-md border border-border bg-input-background" }), _jsx("div", { className: "h-8 rounded-md border border-border bg-input-background" }), _jsx("div", { className: "h-20 rounded-md border border-border bg-input-background" })] }), _jsx("div", { className: "mt-3", children: _jsx("span", { className: "inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground", children: "Submit" }) })] }));
10
+ return (_jsxs("div", { className: "border-border rounded-md border p-5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FileText, { size: 16, className: "text-muted-foreground" }), _jsx("p", { className: "text-foreground text-sm font-medium", children: formId ? `Form: ${formId}` : 'Custom Form' })] }), _jsxs("div", { className: "mt-3 flex flex-col gap-2", children: [_jsx("div", { className: "border-border bg-input-background h-8 rounded-md border" }), _jsx("div", { className: "border-border bg-input-background h-8 rounded-md border" }), _jsx("div", { className: "border-border bg-input-background h-20 rounded-md border" })] }), _jsx("div", { className: "mt-3", children: _jsx("span", { className: "bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm", children: "Submit" }) })] }));
11
11
  }
12
- return (_jsxs("div", { className: "rounded-md border border-border p-5", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Contact Form" }), formId && _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["Form: ", formId] }), _jsxs("div", { className: "mt-3 grid grid-cols-2 gap-2", children: [_jsx("div", { className: "h-8 rounded-md border border-border bg-input-background" }), _jsx("div", { className: "h-8 rounded-md border border-border bg-input-background" })] }), _jsx("div", { className: "mt-2 h-8 rounded-md border border-border bg-input-background" }), _jsx("div", { className: "mt-2 h-20 rounded-md border border-border bg-input-background" }), _jsx("div", { className: "mt-3", children: _jsx("span", { className: "inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground", children: "Send Message" }) })] }));
12
+ return (_jsxs("div", { className: "border-border rounded-md border p-5", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: "Contact Form" }), formId && _jsxs("p", { className: "text-muted-foreground mt-1 text-xs", children: ["Form: ", formId] }), _jsxs("div", { className: "mt-3 grid grid-cols-2 gap-2", children: [_jsx("div", { className: "border-border bg-input-background h-8 rounded-md border" }), _jsx("div", { className: "border-border bg-input-background h-8 rounded-md border" })] }), _jsx("div", { className: "border-border bg-input-background mt-2 h-8 rounded-md border" }), _jsx("div", { className: "border-border bg-input-background mt-2 h-20 rounded-md border" }), _jsx("div", { className: "mt-3", children: _jsx("span", { className: "bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm", children: "Send Message" }) })] }));
13
13
  }
14
14
  //# sourceMappingURL=FormPreview.js.map
@@ -4,16 +4,16 @@ import { Image } from 'lucide-react';
4
4
  export function GalleryPreview({ data, variant = 'grid' }) {
5
5
  const images = data.images || [];
6
6
  const placeholders = images.length > 0 ? images : Array.from({ length: 6 }, (_, i) => ({ alt: `Image ${i + 1}` }));
7
- const Thumbnail = ({ item, className = '' }) => (_jsx("div", { className: `flex items-center justify-center overflow-hidden rounded-md bg-muted ${className}`, children: item.src ? (_jsx("img", { src: item.src, alt: item.alt || '', className: "h-full w-full object-cover" })) : (_jsx(Image, { size: 20, className: "text-muted-foreground" })) }));
7
+ const Thumbnail = ({ item, className = '' }) => (_jsx("div", { className: `bg-muted flex items-center justify-center overflow-hidden rounded-md ${className}`, children: item.src ? (_jsx("img", { src: item.src, alt: item.alt || '', className: "h-full w-full object-cover" })) : (_jsx(Image, { size: 20, className: "text-muted-foreground" })) }));
8
8
  if (variant === 'masonry') {
9
- return (_jsx("div", { className: "rounded-md border border-border p-4", children: _jsx("div", { className: "columns-3 gap-3 space-y-3", children: placeholders.map((item, i) => (_jsx(Thumbnail, { item: item, className: i % 3 === 0 ? 'aspect-square' : i % 3 === 1 ? 'aspect-[3/4]' : 'aspect-[4/3]' }, i))) }) }));
9
+ return (_jsx("div", { className: "border-border rounded-md border p-4", children: _jsx("div", { className: "columns-3 gap-3 space-y-3", children: placeholders.map((item, i) => (_jsx(Thumbnail, { item: item, className: i % 3 === 0 ? 'aspect-square' : i % 3 === 1 ? 'aspect-[3/4]' : 'aspect-[4/3]' }, i))) }) }));
10
10
  }
11
11
  if (variant === 'carousel') {
12
- return (_jsx("div", { className: "overflow-hidden rounded-md border border-border p-4", children: _jsxs("div", { className: "flex gap-3 overflow-hidden", children: [placeholders.slice(0, 4).map((item, i) => (_jsx(Thumbnail, { item: item, className: "aspect-square min-w-[120px] flex-1" }, i))), placeholders.length > 4 && (_jsx("div", { className: "flex min-w-[120px] flex-1 items-center justify-center rounded-md bg-muted", children: _jsxs("span", { className: "text-sm text-muted-foreground", children: ["+", placeholders.length - 4] }) }))] }) }));
12
+ return (_jsx("div", { className: "border-border overflow-hidden rounded-md border p-4", children: _jsxs("div", { className: "flex gap-3 overflow-hidden", children: [placeholders.slice(0, 4).map((item, i) => (_jsx(Thumbnail, { item: item, className: "aspect-square min-w-[120px] flex-1" }, i))), placeholders.length > 4 && (_jsx("div", { className: "bg-muted flex min-w-[120px] flex-1 items-center justify-center rounded-md", children: _jsxs("span", { className: "text-muted-foreground text-sm", children: ["+", placeholders.length - 4] }) }))] }) }));
13
13
  }
14
14
  if (variant === 'lightbox') {
15
- return (_jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "grid grid-cols-3 gap-3", children: placeholders.map((item, i) => (_jsx(Thumbnail, { item: item, className: "aspect-square" }, i))) }), _jsx("p", { className: "mt-2 text-center text-xs text-muted-foreground", children: "Click to open lightbox" })] }));
15
+ return (_jsxs("div", { className: "border-border rounded-md border p-4", children: [_jsx("div", { className: "grid grid-cols-3 gap-3", children: placeholders.map((item, i) => (_jsx(Thumbnail, { item: item, className: "aspect-square" }, i))) }), _jsx("p", { className: "text-muted-foreground mt-2 text-center text-xs", children: "Click to open lightbox" })] }));
16
16
  }
17
- return (_jsx("div", { className: "rounded-md border border-border p-4", children: _jsx("div", { className: "grid grid-cols-3 gap-3", children: placeholders.map((item, i) => (_jsx(Thumbnail, { item: item, className: "aspect-square" }, i))) }) }));
17
+ return (_jsx("div", { className: "border-border rounded-md border p-4", children: _jsx("div", { className: "grid grid-cols-3 gap-3", children: placeholders.map((item, i) => (_jsx(Thumbnail, { item: item, className: "aspect-square" }, i))) }) }));
18
18
  }
19
19
  //# sourceMappingURL=GalleryPreview.js.map
@@ -8,12 +8,12 @@ export function HeroPreview({ data, variant = 'centered' }) {
8
8
  const ctaText = data.ctaText || '';
9
9
  const overlayOpacity = data.overlayOpacity ?? 0.4;
10
10
  if (variant === 'split-image') {
11
- return (_jsxs("div", { className: "flex min-h-[200px] overflow-hidden rounded-md border border-border", children: [_jsxs("div", { className: "flex flex-1 flex-col justify-center gap-3 p-6", children: [_jsx("h2", { className: "text-2xl font-medium text-foreground", children: title || _jsx("span", { className: "text-muted-foreground", children: "Hero Title" }) }), (subtitle || !title) && (_jsx("p", { className: "text-sm text-muted-foreground", children: subtitle || 'Subtitle text goes here' })), ctaText && (_jsx("div", { className: "mt-2", children: _jsx("span", { className: "inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground", children: ctaText }) }))] }), _jsx("div", { className: "flex flex-1 items-center justify-center bg-muted", children: image ? (_jsx("img", { src: image, alt: "", className: "h-full w-full object-cover" })) : (_jsx(Image, { size: 32, className: "text-muted-foreground" })) })] }));
11
+ return (_jsxs("div", { className: "border-border flex min-h-[200px] overflow-hidden rounded-md border", children: [_jsxs("div", { className: "flex flex-1 flex-col justify-center gap-3 p-6", children: [_jsx("h2", { className: "text-foreground text-2xl font-medium", children: title || _jsx("span", { className: "text-muted-foreground", children: "Hero Title" }) }), (subtitle || !title) && (_jsx("p", { className: "text-muted-foreground text-sm", children: subtitle || 'Subtitle text goes here' })), ctaText && (_jsx("div", { className: "mt-2", children: _jsx("span", { className: "bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm", children: ctaText }) }))] }), _jsx("div", { className: "bg-muted flex flex-1 items-center justify-center", children: image ? (_jsx("img", { src: image, alt: "", className: "h-full w-full object-cover" })) : (_jsx(Image, { size: 32, className: "text-muted-foreground" })) })] }));
12
12
  }
13
13
  if (variant === 'minimal') {
14
- return (_jsxs("div", { className: "flex flex-col items-center gap-3 rounded-md border border-border p-8", children: [_jsx("h2", { className: "text-2xl font-medium text-foreground", children: title || _jsx("span", { className: "text-muted-foreground", children: "Hero Title" }) }), (subtitle || !title) && (_jsx("p", { className: "text-sm text-muted-foreground", children: subtitle || 'Subtitle text goes here' })), ctaText && (_jsx("span", { className: "mt-2 inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground", children: ctaText }))] }));
14
+ return (_jsxs("div", { className: "border-border flex flex-col items-center gap-3 rounded-md border p-8", children: [_jsx("h2", { className: "text-foreground text-2xl font-medium", children: title || _jsx("span", { className: "text-muted-foreground", children: "Hero Title" }) }), (subtitle || !title) && (_jsx("p", { className: "text-muted-foreground text-sm", children: subtitle || 'Subtitle text goes here' })), ctaText && (_jsx("span", { className: "bg-primary text-primary-foreground mt-2 inline-block rounded-md px-4 py-2 text-sm", children: ctaText }))] }));
15
15
  }
16
16
  const isVideo = variant === 'video-bg';
17
- return (_jsxs("div", { className: "relative flex min-h-[220px] flex-col items-center justify-center gap-3 overflow-hidden rounded-md border border-border p-8", children: [image ? (_jsx("img", { src: image, alt: "", className: "absolute inset-0 h-full w-full object-cover" })) : (_jsx("div", { className: "absolute inset-0 bg-muted" })), _jsx("div", { className: "absolute inset-0 bg-background", style: { opacity: overlayOpacity } }), _jsxs("div", { className: "relative z-10 flex flex-col items-center gap-3 text-center", children: [isVideo && (_jsx("div", { className: "mb-2 flex h-12 w-12 items-center justify-center rounded-full bg-primary/90", children: _jsx(Play, { size: 20, className: "text-primary-foreground" }) })), _jsx("h2", { className: "text-2xl font-medium text-foreground", children: title || _jsx("span", { className: "text-muted-foreground", children: "Hero Title" }) }), (subtitle || !title) && (_jsx("p", { className: "text-sm text-muted-foreground", children: subtitle || 'Subtitle text goes here' })), ctaText && (_jsx("span", { className: "mt-2 inline-block rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground", children: ctaText }))] })] }));
17
+ return (_jsxs("div", { className: "border-border relative flex min-h-[220px] flex-col items-center justify-center gap-3 overflow-hidden rounded-md border p-8", children: [image ? (_jsx("img", { src: image, alt: "", className: "absolute inset-0 h-full w-full object-cover" })) : (_jsx("div", { className: "bg-muted absolute inset-0" })), _jsx("div", { className: "bg-background absolute inset-0", style: { opacity: overlayOpacity } }), _jsxs("div", { className: "relative z-10 flex flex-col items-center gap-3 text-center", children: [isVideo && (_jsx("div", { className: "bg-primary/90 mb-2 flex h-12 w-12 items-center justify-center rounded-full", children: _jsx(Play, { size: 20, className: "text-primary-foreground" }) })), _jsx("h2", { className: "text-foreground text-2xl font-medium", children: title || _jsx("span", { className: "text-muted-foreground", children: "Hero Title" }) }), (subtitle || !title) && (_jsx("p", { className: "text-muted-foreground text-sm", children: subtitle || 'Subtitle text goes here' })), ctaText && (_jsx("span", { className: "bg-primary text-primary-foreground mt-2 inline-block rounded-md px-4 py-2 text-sm", children: ctaText }))] })] }));
18
18
  }
19
19
  //# sourceMappingURL=HeroPreview.js.map
@@ -7,11 +7,11 @@ export function ImagePreview({ data, variant = 'full-width' }) {
7
7
  const caption = data.caption || '';
8
8
  const aspectRatio = data.aspectRatio || '16/9';
9
9
  const roundedClass = variant === 'rounded' ? 'rounded-xl' : 'rounded-md';
10
- const ImagePlaceholder = ({ className = '' }) => (_jsx("div", { className: `flex items-center justify-center bg-muted ${roundedClass} ${className}`, style: { aspectRatio }, children: _jsx(Image, { size: 32, className: "text-muted-foreground" }) }));
10
+ const ImagePlaceholder = ({ className = '' }) => (_jsx("div", { className: `bg-muted flex items-center justify-center ${roundedClass} ${className}`, style: { aspectRatio }, children: _jsx(Image, { size: 32, className: "text-muted-foreground" }) }));
11
11
  const ImageElement = ({ className = '' }) => src ? (_jsx("img", { src: src, alt: alt, className: `h-auto w-full object-cover ${roundedClass} ${className}`, style: { aspectRatio } })) : (_jsx(ImagePlaceholder, { className: className }));
12
12
  if (variant === 'side-by-side') {
13
- return (_jsxs("div", { className: "grid grid-cols-2 gap-3 rounded-md border border-border p-4", children: [_jsx(ImageElement, {}), _jsx(ImagePlaceholder, {})] }));
13
+ return (_jsxs("div", { className: "border-border grid grid-cols-2 gap-3 rounded-md border p-4", children: [_jsx(ImageElement, {}), _jsx(ImagePlaceholder, {})] }));
14
14
  }
15
- return (_jsxs("figure", { className: "overflow-hidden rounded-md border border-border p-4", children: [_jsx(ImageElement, {}), (variant === 'captioned' || caption) && (_jsx("figcaption", { className: "mt-2 text-center text-sm text-muted-foreground", children: caption || 'Image caption' }))] }));
15
+ return (_jsxs("figure", { className: "border-border overflow-hidden rounded-md border p-4", children: [_jsx(ImageElement, {}), (variant === 'captioned' || caption) && (_jsx("figcaption", { className: "text-muted-foreground mt-2 text-center text-sm", children: caption || 'Image caption' }))] }));
16
16
  }
17
17
  //# sourceMappingURL=ImagePreview.js.map
@@ -12,11 +12,11 @@ export function TextPreview({ data, variant = 'prose' }) {
12
12
  const midpoint = Math.ceil(truncatedBody.length / 2);
13
13
  const col1 = truncatedBody.slice(0, midpoint);
14
14
  const col2 = truncatedBody.slice(midpoint);
15
- return (_jsxs("div", { className: "rounded-md border border-border p-5", children: [heading && (_jsx(HeadingTag, { className: `${headingSizeClass} mb-3 font-medium text-foreground`, children: heading })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: col1 || 'Column one text content…' }), _jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: col2 || 'Column two text content…' })] })] }));
15
+ return (_jsxs("div", { className: "border-border rounded-md border p-5", children: [heading && (_jsx(HeadingTag, { className: `${headingSizeClass} text-foreground mb-3 font-medium`, children: heading })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx("p", { className: "text-muted-foreground text-sm leading-relaxed", children: col1 || 'Column one text content…' }), _jsx("p", { className: "text-muted-foreground text-sm leading-relaxed", children: col2 || 'Column two text content…' })] })] }));
16
16
  }
17
17
  if (variant === 'with-sidebar') {
18
- return (_jsxs("div", { className: "grid grid-cols-[1fr_200px] gap-4 rounded-md border border-border p-5", children: [_jsxs("div", { children: [heading && (_jsx(HeadingTag, { className: `${headingSizeClass} mb-3 font-medium text-foreground`, children: heading })), _jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: truncatedBody || 'Body text content goes here…' })] }), _jsxs("aside", { className: "rounded-md bg-muted p-3", children: [_jsx("div", { className: "h-3 w-3/4 rounded bg-border" }), _jsx("div", { className: "mt-2 h-2 w-full rounded bg-border" }), _jsx("div", { className: "mt-1 h-2 w-2/3 rounded bg-border" })] })] }));
18
+ return (_jsxs("div", { className: "border-border grid grid-cols-[1fr_200px] gap-4 rounded-md border p-5", children: [_jsxs("div", { children: [heading && (_jsx(HeadingTag, { className: `${headingSizeClass} text-foreground mb-3 font-medium`, children: heading })), _jsx("p", { className: "text-muted-foreground text-sm leading-relaxed", children: truncatedBody || 'Body text content goes here…' })] }), _jsxs("aside", { className: "bg-muted rounded-md p-3", children: [_jsx("div", { className: "bg-border h-3 w-3/4 rounded" }), _jsx("div", { className: "bg-border mt-2 h-2 w-full rounded" }), _jsx("div", { className: "bg-border mt-1 h-2 w-2/3 rounded" })] })] }));
19
19
  }
20
- return (_jsxs("div", { className: "rounded-md border border-border p-5", children: [heading && (_jsx(HeadingTag, { className: `${headingSizeClass} mb-3 font-medium text-foreground`, children: heading })), _jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: truncatedBody || _jsx("span", { className: "italic", children: "Body text content goes here\u2026" }) })] }));
20
+ return (_jsxs("div", { className: "border-border rounded-md border p-5", children: [heading && (_jsx(HeadingTag, { className: `${headingSizeClass} text-foreground mb-3 font-medium`, children: heading })), _jsx("p", { className: "text-muted-foreground text-sm leading-relaxed", children: truncatedBody || _jsx("span", { className: "italic", children: "Body text content goes here\u2026" }) })] }));
21
21
  }
22
22
  //# sourceMappingURL=TextPreview.js.map
@@ -6,13 +6,13 @@ export function VideoPreview({ data, variant = 'inline' }) {
6
6
  const autoplay = data.autoplay;
7
7
  const loop = data.loop;
8
8
  const badges = [autoplay ? 'Autoplay' : '', loop ? 'Loop' : ''].filter((b) => b !== '');
9
- const content = (_jsxs("div", { className: "relative flex aspect-video items-center justify-center overflow-hidden rounded-md bg-muted", children: [poster ? (_jsx("img", { src: poster, alt: "", className: "absolute inset-0 h-full w-full object-cover" })) : (_jsx("div", { className: "absolute inset-0 bg-card" })), _jsx("div", { className: "relative z-10 flex h-12 w-12 items-center justify-center rounded-full bg-primary/90 shadow-sm", children: _jsx(Play, { size: 20, className: "text-primary-foreground" }) }), badges.length > 0 && (_jsx("div", { className: "absolute bottom-2 right-2 z-10 flex gap-1", children: badges.map((badge) => (_jsx("span", { className: "rounded bg-background/80 px-1.5 py-0.5 text-xs text-muted-foreground", children: badge }, badge))) }))] }));
9
+ const content = (_jsxs("div", { className: "bg-muted relative flex aspect-video items-center justify-center overflow-hidden rounded-md", children: [poster ? (_jsx("img", { src: poster, alt: "", className: "absolute inset-0 h-full w-full object-cover" })) : (_jsx("div", { className: "bg-card absolute inset-0" })), _jsx("div", { className: "bg-primary/90 relative z-10 flex h-12 w-12 items-center justify-center rounded-full shadow-sm", children: _jsx(Play, { size: 20, className: "text-primary-foreground" }) }), badges.length > 0 && (_jsx("div", { className: "absolute right-2 bottom-2 z-10 flex gap-1", children: badges.map((badge) => (_jsx("span", { className: "bg-background/80 text-muted-foreground rounded px-1.5 py-0.5 text-xs", children: badge }, badge))) }))] }));
10
10
  if (variant === 'background') {
11
- return (_jsx("div", { className: "overflow-hidden rounded-md border border-border", children: _jsxs("div", { className: "relative aspect-[21/9]", children: [poster ? (_jsx("img", { src: poster, alt: "", className: "absolute inset-0 h-full w-full object-cover" })) : (_jsx("div", { className: "absolute inset-0 bg-card" })), _jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-background/30", children: _jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-primary/90 shadow-sm", children: _jsx(Play, { size: 24, className: "text-primary-foreground" }) }) })] }) }));
11
+ return (_jsx("div", { className: "border-border overflow-hidden rounded-md border", children: _jsxs("div", { className: "relative aspect-[21/9]", children: [poster ? (_jsx("img", { src: poster, alt: "", className: "absolute inset-0 h-full w-full object-cover" })) : (_jsx("div", { className: "bg-card absolute inset-0" })), _jsx("div", { className: "bg-background/30 absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "bg-primary/90 flex h-14 w-14 items-center justify-center rounded-full shadow-sm", children: _jsx(Play, { size: 24, className: "text-primary-foreground" }) }) })] }) }));
12
12
  }
13
13
  if (variant === 'lightbox') {
14
- return (_jsx("div", { className: "rounded-md border border-border p-4", children: _jsxs("div", { className: "mx-auto max-w-sm", children: [content, _jsx("p", { className: "mt-2 text-center text-xs text-muted-foreground", children: "Click to play in lightbox" })] }) }));
14
+ return (_jsx("div", { className: "border-border rounded-md border p-4", children: _jsxs("div", { className: "mx-auto max-w-sm", children: [content, _jsx("p", { className: "text-muted-foreground mt-2 text-center text-xs", children: "Click to play in lightbox" })] }) }));
15
15
  }
16
- return _jsx("div", { className: "rounded-md border border-border p-4", children: content });
16
+ return _jsx("div", { className: "border-border rounded-md border p-4", children: content });
17
17
  }
18
18
  //# sourceMappingURL=VideoPreview.js.map
@@ -21,6 +21,6 @@ export function BlockRenderer({ node, selectedNodeId, onSelectNode }) {
21
21
  e.stopPropagation();
22
22
  onSelectNode(node.id);
23
23
  };
24
- return (_jsxs("div", { "data-node-id": node.id, className: `relative min-h-[48px] transition-shadow ${isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''}`, onClick: handleClick, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: label })), _jsxs("div", { className: "flex items-center justify-center gap-2 p-4 bg-muted/30 border border-dashed border-border rounded-md", children: [_jsx(Icon, { size: 16, className: "text-muted-foreground" }), _jsx("span", { className: "text-sm text-muted-foreground", children: label })] })] }));
24
+ return (_jsxs("div", { "data-node-id": node.id, className: `relative min-h-[48px] transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, onClick: handleClick, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: label })), _jsxs("div", { className: "bg-muted/30 border-border flex items-center justify-center gap-2 rounded-md border border-dashed p-4", children: [_jsx(Icon, { size: 16, className: "text-muted-foreground" }), _jsx("span", { className: "text-muted-foreground text-sm", children: label })] })] }));
25
25
  }
26
26
  //# sourceMappingURL=BlockRenderer.js.map
@@ -13,14 +13,14 @@ export function BuilderCanvas({ tree, selectedNodeId, showGridOverlay, deviceMod
13
13
  onSelectNode(null);
14
14
  }
15
15
  };
16
- return (_jsxs("div", { className: "relative flex-1 overflow-auto bg-muted p-6", onClick: handleCanvasClick, children: [showGridOverlay && _jsx(GridOverlay, { deviceMode: deviceMode }), _jsxs("div", { className: `relative bg-background shadow-sm min-h-full ${DEVICE_CLASSES[deviceMode]}`, onClick: handleCanvasClick, children: [tree.children.map((child) => {
16
+ return (_jsxs("div", { className: "bg-muted relative flex-1 overflow-auto p-6", onClick: handleCanvasClick, children: [showGridOverlay && _jsx(GridOverlay, { deviceMode: deviceMode }), _jsxs("div", { className: `bg-background relative min-h-full shadow-sm ${DEVICE_CLASSES[deviceMode]}`, onClick: handleCanvasClick, children: [tree.children.map((child) => {
17
17
  if (child.type === 'section') {
18
18
  return (_jsx(SectionRenderer, { node: child, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, child.id));
19
19
  }
20
20
  return null;
21
- }), tree.children.length === 0 && (_jsxs("div", { className: "flex flex-col items-center justify-center min-h-[400px] text-center", children: [_jsx(LayoutGrid, { size: 32, className: "text-muted-foreground mb-3" }), _jsx("p", { className: "text-sm font-medium text-foreground mb-1", children: "No sections yet" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Click \"Add Section\" below to start building your page" })] }))] })] }));
21
+ }), tree.children.length === 0 && (_jsxs("div", { className: "flex min-h-[400px] flex-col items-center justify-center text-center", children: [_jsx(LayoutGrid, { size: 32, className: "text-muted-foreground mb-3" }), _jsx("p", { className: "text-foreground mb-1 text-sm font-medium", children: "No sections yet" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Click \"Add Section\" below to start building your page" })] }))] })] }));
22
22
  }
23
23
  function GridOverlay({ deviceMode }) {
24
- return (_jsx("div", { className: `pointer-events-none absolute inset-0 z-50 p-6 ${deviceMode !== 'desktop' ? 'flex justify-center' : ''}`, "aria-hidden": "true", children: _jsx("div", { className: `grid grid-cols-12 gap-4 h-full opacity-[0.08] ${DEVICE_CLASSES[deviceMode]}`, children: Array.from({ length: 12 }).map((_, i) => (_jsx("div", { className: "bg-primary h-full rounded-sm" }, i))) }) }));
24
+ return (_jsx("div", { className: `pointer-events-none absolute inset-0 z-50 p-6 ${deviceMode !== 'desktop' ? 'flex justify-center' : ''}`, "aria-hidden": "true", children: _jsx("div", { className: `grid h-full grid-cols-12 gap-4 opacity-[0.08] ${DEVICE_CLASSES[deviceMode]}`, children: Array.from({ length: 12 }).map((_, i) => (_jsx("div", { className: "bg-primary h-full rounded-sm" }, i))) }) }));
25
25
  }
26
26
  //# sourceMappingURL=BuilderCanvas.js.map
@@ -12,14 +12,14 @@ export function ColumnRenderer({ node, selectedNodeId, onSelectNode }) {
12
12
  e.stopPropagation();
13
13
  onSelectNode(node.id);
14
14
  };
15
- return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''}`, style: {
15
+ return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, style: {
16
16
  gridColumn: `span ${width}`,
17
17
  padding: node.settings.padding,
18
18
  background: node.settings.background,
19
19
  }, onClick: handleClick, onMouseEnter: (e) => {
20
20
  e.stopPropagation();
21
21
  setHovered(true);
22
- }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsxs("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", children: ["Col ", width] })), isEmpty ? (_jsx("div", { className: "flex items-center justify-center min-h-[64px] border-2 border-dashed border-border rounded-md text-sm text-muted-foreground", children: "Empty column" })) : (_jsx("div", { className: "flex flex-col gap-2", children: node.children.map((child) => {
22
+ }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsxs("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", children: ["Col ", width] })), isEmpty ? (_jsx("div", { className: "border-border text-muted-foreground flex min-h-[64px] items-center justify-center rounded-md border-2 border-dashed text-sm", children: "Empty column" })) : (_jsx("div", { className: "flex flex-col gap-2", children: node.children.map((child) => {
23
23
  if (child.type === 'block') {
24
24
  return (_jsx(BlockRenderer, { node: child, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, child.id));
25
25
  }
@@ -17,13 +17,13 @@ export function ContainerRenderer({ node, selectedNodeId, onSelectNode }) {
17
17
  e.stopPropagation();
18
18
  onSelectNode(node.id);
19
19
  };
20
- return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''}`, style: {
20
+ return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, style: {
21
21
  maxWidth,
22
22
  margin: marginMap[alignment] ?? '0 auto',
23
23
  padding,
24
24
  }, onClick: handleClick, onMouseEnter: (e) => {
25
25
  e.stopPropagation();
26
26
  setHovered(true);
27
- }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: "Container" })), _jsx("div", { className: "flex flex-col gap-4", children: node.children.map((row) => (_jsx(RowRenderer, { node: row, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, row.id))) })] }));
27
+ }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: "Container" })), _jsx("div", { className: "flex flex-col gap-4", children: node.children.map((row) => (_jsx(RowRenderer, { node: row, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, row.id))) })] }));
28
28
  }
29
29
  //# sourceMappingURL=ContainerRenderer.js.map
@@ -17,10 +17,10 @@ export function RowRenderer({ node, selectedNodeId, onSelectNode }) {
17
17
  e.stopPropagation();
18
18
  onSelectNode(node.id);
19
19
  };
20
- return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''}`, onClick: handleClick, onMouseEnter: (e) => {
20
+ return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, onClick: handleClick, onMouseEnter: (e) => {
21
21
  e.stopPropagation();
22
22
  setHovered(true);
23
- }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: "Row" })), _jsx("div", { className: "grid grid-cols-12", style: {
23
+ }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: "Row" })), _jsx("div", { className: "grid grid-cols-12", style: {
24
24
  gap,
25
25
  alignItems: alignMap[verticalAlign] ?? 'stretch',
26
26
  }, children: node.children.map((col) => (_jsx(ColumnRenderer, { node: col, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, col.id))) })] }));
@@ -34,10 +34,10 @@ export function SectionRenderer({ node, selectedNodeId, onSelectNode }) {
34
34
  if (node.settings.marginBottom) {
35
35
  backgroundStyle.marginBottom = node.settings.marginBottom;
36
36
  }
37
- return (_jsxs("div", { "data-node-id": node.id, className: `relative w-full transition-shadow ${isSelected ? 'ring-2 ring-primary ring-offset-2' : hovered ? 'ring-1 ring-primary/50' : ''}`, style: backgroundStyle, onClick: handleClick, onMouseEnter: (e) => {
37
+ return (_jsxs("div", { "data-node-id": node.id, className: `relative w-full transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, style: backgroundStyle, onClick: handleClick, onMouseEnter: (e) => {
38
38
  e.stopPropagation();
39
39
  setHovered(true);
40
- }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: "Section" })), node.children.map((child) => {
40
+ }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("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", children: "Section" })), node.children.map((child) => {
41
41
  if (child.type === 'container') {
42
42
  return (_jsx(ContainerRenderer, { node: child, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, child.id));
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuate-media/cms-admin",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/actuate-media/actuatecms.git",
@@ -68,14 +68,18 @@
68
68
  "@tailwindcss/cli": "^4.0.0",
69
69
  "@types/react": "^19.0.0",
70
70
  "@types/react-dom": "^19.0.0",
71
+ "concurrently": "^9.2.1",
71
72
  "tailwindcss": "^4.0.0",
72
73
  "typescript": "^5.7.0",
73
74
  "vitest": "^3.0.0",
74
- "@actuate-media/cms-core": "0.19.0"
75
+ "@actuate-media/cms-core": "0.20.0"
75
76
  },
76
77
  "scripts": {
77
78
  "build": "tsc --project tsconfig.json && npx @tailwindcss/cli -i src/styles/build-input.css -o dist/actuate-admin.css --minify",
78
79
  "build:css": "npx @tailwindcss/cli -i src/styles/build-input.css -o dist/actuate-admin.css --minify",
80
+ "dev": "concurrently -n tsc,css -c blue,magenta \"pnpm run dev:tsc\" \"pnpm run dev:css\"",
81
+ "dev:tsc": "tsc --project tsconfig.json --watch --preserveWatchOutput",
82
+ "dev:css": "npx @tailwindcss/cli -i src/styles/build-input.css -o dist/actuate-admin.css --watch",
79
83
  "type-check": "tsc --noEmit",
80
84
  "test": "vitest run",
81
85
  "clean": "rm -rf dist .turbo"
package/src/AdminRoot.tsx CHANGED
@@ -143,13 +143,23 @@ function AdminShell({
143
143
  }
144
144
 
145
145
  if (onLogin) {
146
- return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig} />
146
+ // Thread `config.admin.branding` through so the login screen matches the
147
+ // sidebar (single source of truth for the logo + brand name).
148
+ const branding = config?.admin?.branding
149
+ return (
150
+ <Login
151
+ onLogin={onLogin}
152
+ onNavigate={navigate}
153
+ captchaConfig={captchaConfig}
154
+ branding={branding}
155
+ />
156
+ )
147
157
  }
148
158
  return (
149
- <div className="min-h-screen flex items-center justify-center bg-background">
159
+ <div className="bg-background flex min-h-screen items-center justify-center">
150
160
  <div className="text-center">
151
- <h1 className="text-xl font-semibold text-foreground mb-2">Unauthorized</h1>
152
- <p className="text-sm text-muted-foreground">Please log in to access the admin panel.</p>
161
+ <h1 className="text-foreground mb-2 text-xl font-semibold">Unauthorized</h1>
162
+ <p className="text-muted-foreground text-sm">Please log in to access the admin panel.</p>
153
163
  </div>
154
164
  </div>
155
165
  )
@@ -331,12 +341,12 @@ function AdminShell({
331
341
  }
332
342
 
333
343
  return (
334
- <div className="flex flex-col items-center justify-center min-h-[400px] text-center p-6">
335
- <h1 className="text-4xl font-bold text-foreground mb-2">404</h1>
344
+ <div className="flex min-h-[400px] flex-col items-center justify-center p-6 text-center">
345
+ <h1 className="text-foreground mb-2 text-4xl font-bold">404</h1>
336
346
  <p className="text-muted-foreground mb-4">The page you are looking for does not exist.</p>
337
347
  <button
338
348
  onClick={() => navigate('/')}
339
- className="px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-md hover:opacity-90"
349
+ className="text-primary-foreground bg-primary rounded-md px-4 py-2 text-sm font-medium hover:opacity-90"
340
350
  >
341
351
  Back to Dashboard
342
352
  </button>
@@ -360,8 +370,8 @@ function ShortcutHelp({ onClose }: { onClose: () => void }) {
360
370
  if (e.target === e.currentTarget) onClose()
361
371
  }}
362
372
  >
363
- <div className="bg-card text-card-foreground rounded-xl shadow-2xl border border-border p-6 max-w-sm w-full mx-4">
364
- <h3 className="text-lg font-semibold mb-4">Keyboard Shortcuts</h3>
373
+ <div className="bg-card text-card-foreground border-border mx-4 w-full max-w-sm rounded-xl border p-6 shadow-2xl">
374
+ <h3 className="mb-4 text-lg font-semibold">Keyboard Shortcuts</h3>
365
375
  <div className="space-y-3 text-sm">
366
376
  {[
367
377
  ['⌘ K', 'Open search'],
@@ -371,13 +381,13 @@ function ShortcutHelp({ onClose }: { onClose: () => void }) {
371
381
  ].map(([key, desc]) => (
372
382
  <div key={key} className="flex items-center justify-between">
373
383
  <span className="text-muted-foreground">{desc}</span>
374
- <kbd className="px-2 py-1 text-xs font-mono bg-muted rounded">{key}</kbd>
384
+ <kbd className="bg-muted rounded px-2 py-1 font-mono text-xs">{key}</kbd>
375
385
  </div>
376
386
  ))}
377
387
  </div>
378
388
  <button
379
389
  onClick={onClose}
380
- className="mt-4 w-full py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90"
390
+ className="bg-primary text-primary-foreground mt-4 w-full rounded-lg py-2 text-sm hover:opacity-90"
381
391
  >
382
392
  Close
383
393
  </button>
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { tokens } from '../../layout/primitives/tokens.js'
3
+ import * as primitives from '../../layout/primitives/index.js'
4
+
5
+ describe('layout primitive tokens', () => {
6
+ it('exposes the canonical spacing scale', () => {
7
+ expect(tokens.space['0']).toBe(0)
8
+ expect(tokens.space['1']).toBe(4)
9
+ expect(tokens.space['4']).toBe(16)
10
+ expect(tokens.space['8']).toBe(32)
11
+ })
12
+
13
+ it('exposes the canonical radius scale', () => {
14
+ expect(tokens.radius.none).toBe(0)
15
+ expect(tokens.radius.md).toBe(6)
16
+ expect(tokens.radius.full).toBe(9999)
17
+ })
18
+
19
+ it('exposes the canonical breakpoint scale', () => {
20
+ expect(tokens.breakpoint.sm).toBe(640)
21
+ expect(tokens.breakpoint.md).toBe(768)
22
+ expect(tokens.breakpoint.lg).toBe(1024)
23
+ })
24
+ })
25
+
26
+ describe('layout primitives exports', () => {
27
+ it('re-exports every public primitive', () => {
28
+ expect(typeof primitives.AdminShell).toBe('function')
29
+ expect(typeof primitives.PageContainer).toBe('function')
30
+ expect(typeof primitives.Stack).toBe('function')
31
+ expect(typeof primitives.Cluster).toBe('function')
32
+ expect(typeof primitives.Grid).toBe('function')
33
+ expect(typeof primitives.Split).toBe('function')
34
+ expect(typeof primitives.Box).toBe('object')
35
+ expect(typeof primitives.tokens).toBe('object')
36
+ })
37
+ })
@@ -0,0 +1,74 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { cv } from '../../lib/cv.js'
3
+
4
+ describe('cv()', () => {
5
+ const button = cv('inline-flex items-center', {
6
+ variants: {
7
+ intent: {
8
+ primary: 'bg-primary text-white',
9
+ secondary: 'bg-secondary text-foreground',
10
+ },
11
+ size: {
12
+ sm: 'px-2 py-1 text-xs',
13
+ md: 'px-4 py-2 text-sm',
14
+ lg: 'px-6 py-3 text-base',
15
+ },
16
+ },
17
+ defaultVariants: { intent: 'primary', size: 'md' },
18
+ })
19
+
20
+ it('returns the base class and default variant classes when no props supplied', () => {
21
+ const out = button()
22
+ expect(out).toContain('inline-flex')
23
+ expect(out).toContain('bg-primary')
24
+ expect(out).toContain('text-white')
25
+ expect(out).toContain('px-4 py-2 text-sm')
26
+ })
27
+
28
+ it('overrides default variants when explicit values are supplied', () => {
29
+ const out = button({ intent: 'secondary', size: 'sm' })
30
+ expect(out).toContain('bg-secondary')
31
+ expect(out).toContain('text-foreground')
32
+ expect(out).toContain('px-2 py-1 text-xs')
33
+ expect(out).not.toContain('bg-primary')
34
+ })
35
+
36
+ it('appends the `class` escape hatch', () => {
37
+ const out = button({ class: 'shadow-md' })
38
+ expect(out).toContain('shadow-md')
39
+ })
40
+
41
+ it('appends the `className` escape hatch', () => {
42
+ const out = button({ className: 'rounded-full' })
43
+ expect(out).toContain('rounded-full')
44
+ })
45
+
46
+ it('applies compound variants when their match criteria are satisfied', () => {
47
+ const card = cv('rounded-md', {
48
+ variants: {
49
+ tone: { neutral: 'bg-gray-100', danger: 'bg-red-100' },
50
+ emphasis: { low: 'border', high: 'border-2' },
51
+ },
52
+ defaultVariants: { tone: 'neutral', emphasis: 'low' },
53
+ compoundVariants: [{ tone: 'danger', emphasis: 'high', class: 'ring-2 ring-red-500' }],
54
+ })
55
+
56
+ expect(card({ tone: 'danger', emphasis: 'high' })).toContain('ring-2 ring-red-500')
57
+ expect(card({ tone: 'danger', emphasis: 'low' })).not.toContain('ring-2')
58
+ expect(card({ tone: 'neutral', emphasis: 'high' })).not.toContain('ring-2')
59
+ })
60
+
61
+ it('applies compound variants with array (any-of) matching', () => {
62
+ const alert = cv('alert', {
63
+ variants: {
64
+ tone: { info: 'bg-blue-50', warn: 'bg-amber-50', danger: 'bg-red-50' },
65
+ },
66
+ defaultVariants: { tone: 'info' },
67
+ compoundVariants: [{ tone: ['warn', 'danger'], class: 'font-medium' }],
68
+ })
69
+
70
+ expect(alert({ tone: 'warn' })).toContain('font-medium')
71
+ expect(alert({ tone: 'danger' })).toContain('font-medium')
72
+ expect(alert({ tone: 'info' })).not.toContain('font-medium')
73
+ })
74
+ })
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Default Actuate Media brand logo for the admin sidebar (top-left) and the
3
+ * login screen.
4
+ *
5
+ * Source: the official 2021 Actuate Media SVG. The original asset has a
6
+ * 1000×800 viewBox with a white background polygon and the artwork
7
+ * concentrated in the middle band — we strip the white polygon so the logo
8
+ * is transparent on any surface, and crop the viewBox to the actual content
9
+ * bounds so `h-9 w-auto` renders at a sensible aspect ratio instead of
10
+ * leaving 60% empty space.
11
+ *
12
+ * Integrators override this default via:
13
+ * defineConfig({
14
+ * admin: { branding: { logo: '/my-logo.svg', name: 'Acme' } }
15
+ * })
16
+ *
17
+ * Both the sidebar (top-left) and the login screen read from the same
18
+ * `admin.branding` config so swapping logos is a one-line change.
19
+ */
20
+
21
+ import type { ReactElement } from 'react'
22
+
23
+ export interface BrandLogoProps {
24
+ /** Tailwind / CSS class applied to the root `<svg>` element. */
25
+ className?: string
26
+ }
27
+
28
+ /**
29
+ * Inline SVG renderer for the official Actuate Media lockup. Transparent
30
+ * background, scales cleanly at any size, and ships as JSX (no bundler asset
31
+ * pipeline required — works under Next.js, Vite, Webpack, esbuild, etc.).
32
+ *
33
+ * Colour palette is baked into the path fills so the logo stays on-brand
34
+ * regardless of the surrounding theme:
35
+ * - Coral / red `#F05E65` for the "C" mark + ACTUATE wordmark
36
+ * - Neutral grey `#818386` for the MEDIA sub-line
37
+ */
38
+ export function ActuateBrandLogo({ className }: BrandLogoProps): ReactElement {
39
+ return (
40
+ <svg
41
+ viewBox="160 250 730 290"
42
+ xmlns="http://www.w3.org/2000/svg"
43
+ className={className}
44
+ role="img"
45
+ aria-label="Actuate Media"
46
+ style={{ shapeRendering: 'geometricPrecision' }}
47
+ >
48
+ {/* "C" mark: upward arrow + three vertical bars (coral) */}
49
+ <polygon
50
+ fill="#F05E65"
51
+ fillRule="nonzero"
52
+ points="253,266 167,433 196,433 253,323 309,433 339,433"
53
+ />
54
+ <path
55
+ fill="#F05E65"
56
+ d="M216 433l16 0 0 59 -16 0 0 -59zm57 0l17 0 0 59 -17 0 0 -59zm-28 0l16 0 0 101 -16 0 0 -101z"
57
+ />
58
+ {/* "MEDIA" subtitle (neutral grey) */}
59
+ <path
60
+ fill="#818386"
61
+ fillRule="nonzero"
62
+ d="M707 447l-12 0 6 -14 6 14zm-241 -11l0 25 6 0 0 -35 -7 0 -11 17 -10 -17 -7 0 0 35 6 0 0 -25 11 17 1 0 11 -17zm70 -10l-26 0 0 35 26 0 0 -5 -20 0 0 -10 20 0 0 -5 -20 0 0 -10 20 0 0 -5zm62 18c0,1 0,3 -1,5 0,1 -1,2 -2,3 -1,1 -3,2 -4,3 -2,1 -3,1 -5,1l-7 0 0 -25 7 0c2,0 3,1 5,1 1,1 3,2 4,3 1,1 2,2 2,4 1,1 1,3 1,5zm7 0c0,-3 -1,-5 -2,-7 -1,-3 -2,-5 -4,-6 -1,-2 -3,-3 -6,-4 -2,-1 -5,-1 -7,-1l-14 0 0 35 14 0c2,0 5,0 7,-1 3,-1 5,-2 6,-4 2,-1 3,-3 4,-5 1,-3 2,-5 2,-7zm36 -18l0 35 6 0 0 -35 -6 0zm63 0l-6 0 -16 35 7 0 3 -8 17 0 4 8 7 0 -16 -35z"
63
+ />
64
+ {/* "ACTUATE" main wordmark (coral) */}
65
+ <path
66
+ fill="#F05E65"
67
+ fillRule="nonzero"
68
+ d="M406 386l-10 -10c-4,3 -7,6 -11,8 -4,2 -8,3 -13,3 -5,0 -8,-1 -12,-2 -3,-2 -6,-4 -9,-7 -2,-3 -4,-6 -6,-10 -1,-3 -2,-7 -2,-12 0,-4 1,-8 2,-11 2,-4 4,-7 6,-10 3,-3 6,-5 9,-7 4,-1 7,-2 12,-2 4,0 9,1 13,3 3,2 7,5 11,8l9 -11c-2,-2 -4,-4 -6,-6 -3,-1 -5,-3 -8,-4 -2,-1 -5,-2 -9,-3 -3,0 -6,-1 -10,-1 -7,0 -13,1 -18,4 -6,2 -10,5 -14,9 -4,4 -7,9 -9,14 -2,6 -4,12 -4,18 0,6 2,12 4,17 2,5 5,10 9,14 4,4 8,7 14,9 5,3 11,4 17,4 4,0 8,0 11,-1 3,-1 6,-2 9,-3 3,-2 5,-3 8,-5 2,-2 5,-4 7,-6zm230 -73l-45 86 16 0 29 -57 29 57 15 0 -44 -86zm197 1l-63 0 0 85 63 0 0 -13 -48 0 0 -23 48 0 0 -14 -48 0 0 -22 48 0 0 -13zm-110 14l27 0 0 -14 -70 0 0 14 28 0 0 71 15 0 0 -71zm-140 -14l-15 0 0 49c0,8 -2,14 -6,18 -4,4 -9,6 -16,6 -7,0 -12,-2 -16,-6 -4,-4 -6,-11 -6,-19l0 -48 -15 0 0 49c0,6 1,12 3,16 2,5 4,9 7,12 3,3 7,6 12,7 4,2 9,3 15,3 5,0 11,-1 15,-3 5,-1 8,-4 12,-7 3,-3 5,-7 7,-12 2,-5 3,-10 3,-17l0 -48zm-118 14l27 0 0 -14 -69 0 0 14 27 0 0 71 15 0 0 -71z"
69
+ />
70
+ </svg>
71
+ )
72
+ }