@prenta/admin 0.98.0 → 1.0.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 (270) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/AdminRoot.d.ts.map +1 -1
  3. package/dist/AdminRoot.js +17 -28
  4. package/dist/AdminRoot.js.map +1 -1
  5. package/dist/__tests__/components/seo-score-bands.test.js +0 -10
  6. package/dist/__tests__/components/seo-score-bands.test.js.map +1 -1
  7. package/dist/__tests__/layout/sidebar-posts.test.js +6 -11
  8. package/dist/__tests__/layout/sidebar-posts.test.js.map +1 -1
  9. package/dist/__tests__/layout/sidebar-submenu.render.test.js +3 -2
  10. package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -1
  11. package/dist/__tests__/lib/page-audit-input.test.js +77 -1
  12. package/dist/__tests__/lib/page-audit-input.test.js.map +1 -1
  13. package/dist/__tests__/lib/page-editor-service-api.test.js +26 -23
  14. package/dist/__tests__/lib/page-editor-service-api.test.js.map +1 -1
  15. package/dist/__tests__/views/page-section-editor.test.js +0 -1
  16. package/dist/__tests__/views/page-section-editor.test.js.map +1 -1
  17. package/dist/__tests__/views/page-tab.render.test.js +0 -1
  18. package/dist/__tests__/views/page-tab.render.test.js.map +1 -1
  19. package/dist/index.d.ts +1 -4
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/layout/Sidebar.d.ts +3 -4
  24. package/dist/layout/Sidebar.d.ts.map +1 -1
  25. package/dist/layout/Sidebar.js +7 -38
  26. package/dist/layout/Sidebar.js.map +1 -1
  27. package/dist/lib/page-audit-input.d.ts +14 -1
  28. package/dist/lib/page-audit-input.d.ts.map +1 -1
  29. package/dist/lib/page-audit-input.js +19 -0
  30. package/dist/lib/page-audit-input.js.map +1 -1
  31. package/dist/lib/page-editor-service.d.ts +0 -7
  32. package/dist/lib/page-editor-service.d.ts.map +1 -1
  33. package/dist/lib/page-editor-service.js +9 -9
  34. package/dist/lib/page-editor-service.js.map +1 -1
  35. package/dist/prenta-admin.css +1 -1
  36. package/dist/views/PageEditor.d.ts +2 -2
  37. package/dist/views/PageEditor.js +2 -2
  38. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  39. package/dist/views/page-editor/PageSectionEditor.js +9 -15
  40. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  41. package/package.json +4 -4
  42. package/src/AdminRoot.tsx +18 -68
  43. package/src/__tests__/components/seo-score-bands.test.ts +0 -10
  44. package/src/__tests__/layout/sidebar-posts.test.ts +6 -11
  45. package/src/__tests__/layout/sidebar-submenu.render.test.tsx +3 -2
  46. package/src/__tests__/lib/page-audit-input.test.ts +91 -1
  47. package/src/__tests__/lib/page-editor-service-api.test.ts +27 -25
  48. package/src/__tests__/views/page-section-editor.test.tsx +0 -1
  49. package/src/__tests__/views/page-tab.render.test.tsx +0 -1
  50. package/src/index.ts +1 -11
  51. package/src/layout/Sidebar.tsx +6 -41
  52. package/src/lib/page-audit-input.ts +36 -1
  53. package/src/lib/page-editor-service.ts +9 -16
  54. package/src/views/PageEditor.tsx +2 -2
  55. package/src/views/page-editor/PageSectionEditor.tsx +8 -37
  56. package/dist/__tests__/views/page-builder-block-renderer.render.test.d.ts +0 -2
  57. package/dist/__tests__/views/page-builder-block-renderer.render.test.d.ts.map +0 -1
  58. package/dist/__tests__/views/page-builder-block-renderer.render.test.js +0 -48
  59. package/dist/__tests__/views/page-builder-block-renderer.render.test.js.map +0 -1
  60. package/dist/__tests__/views/page-builder-form-picker.render.test.d.ts +0 -2
  61. package/dist/__tests__/views/page-builder-form-picker.render.test.d.ts.map +0 -1
  62. package/dist/__tests__/views/page-builder-form-picker.render.test.js +0 -44
  63. package/dist/__tests__/views/page-builder-form-picker.render.test.js.map +0 -1
  64. package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts +0 -2
  65. package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts.map +0 -1
  66. package/dist/__tests__/views/page-builder-sections-panel.render.test.js +0 -121
  67. package/dist/__tests__/views/page-builder-sections-panel.render.test.js.map +0 -1
  68. package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts +0 -2
  69. package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts.map +0 -1
  70. package/dist/__tests__/views/page-builder-template-seed.render.test.js +0 -48
  71. package/dist/__tests__/views/page-builder-template-seed.render.test.js.map +0 -1
  72. package/dist/__tests__/views/page-templates.render.test.d.ts +0 -2
  73. package/dist/__tests__/views/page-templates.render.test.d.ts.map +0 -1
  74. package/dist/__tests__/views/page-templates.render.test.js +0 -126
  75. package/dist/__tests__/views/page-templates.render.test.js.map +0 -1
  76. package/dist/hooks/useBuilderState.d.ts +0 -49
  77. package/dist/hooks/useBuilderState.d.ts.map +0 -1
  78. package/dist/hooks/useBuilderState.js +0 -238
  79. package/dist/hooks/useBuilderState.js.map +0 -1
  80. package/dist/views/page-builder/AIBlockAssist.d.ts +0 -9
  81. package/dist/views/page-builder/AIBlockAssist.d.ts.map +0 -1
  82. package/dist/views/page-builder/AIBlockAssist.js +0 -40
  83. package/dist/views/page-builder/AIBlockAssist.js.map +0 -1
  84. package/dist/views/page-builder/AIGenerateDialog.d.ts +0 -8
  85. package/dist/views/page-builder/AIGenerateDialog.d.ts.map +0 -1
  86. package/dist/views/page-builder/AIGenerateDialog.js +0 -173
  87. package/dist/views/page-builder/AIGenerateDialog.js.map +0 -1
  88. package/dist/views/page-builder/BlockEditor.d.ts +0 -11
  89. package/dist/views/page-builder/BlockEditor.d.ts.map +0 -1
  90. package/dist/views/page-builder/BlockEditor.js +0 -159
  91. package/dist/views/page-builder/BlockEditor.js.map +0 -1
  92. package/dist/views/page-builder/BlockPicker.d.ts +0 -7
  93. package/dist/views/page-builder/BlockPicker.d.ts.map +0 -1
  94. package/dist/views/page-builder/BlockPicker.js +0 -103
  95. package/dist/views/page-builder/BlockPicker.js.map +0 -1
  96. package/dist/views/page-builder/BottomBar.d.ts +0 -9
  97. package/dist/views/page-builder/BottomBar.d.ts.map +0 -1
  98. package/dist/views/page-builder/BottomBar.js +0 -13
  99. package/dist/views/page-builder/BottomBar.js.map +0 -1
  100. package/dist/views/page-builder/BuilderSectionsPanel.d.ts +0 -20
  101. package/dist/views/page-builder/BuilderSectionsPanel.d.ts.map +0 -1
  102. package/dist/views/page-builder/BuilderSectionsPanel.js +0 -105
  103. package/dist/views/page-builder/BuilderSectionsPanel.js.map +0 -1
  104. package/dist/views/page-builder/BuilderToolbar.d.ts +0 -21
  105. package/dist/views/page-builder/BuilderToolbar.d.ts.map +0 -1
  106. package/dist/views/page-builder/BuilderToolbar.js +0 -18
  107. package/dist/views/page-builder/BuilderToolbar.js.map +0 -1
  108. package/dist/views/page-builder/ContextPanel.d.ts +0 -20
  109. package/dist/views/page-builder/ContextPanel.d.ts.map +0 -1
  110. package/dist/views/page-builder/ContextPanel.js +0 -43
  111. package/dist/views/page-builder/ContextPanel.js.map +0 -1
  112. package/dist/views/page-builder/DesignScore.d.ts +0 -6
  113. package/dist/views/page-builder/DesignScore.d.ts.map +0 -1
  114. package/dist/views/page-builder/DesignScore.js +0 -93
  115. package/dist/views/page-builder/DesignScore.js.map +0 -1
  116. package/dist/views/page-builder/NodeSettings.d.ts +0 -12
  117. package/dist/views/page-builder/NodeSettings.d.ts.map +0 -1
  118. package/dist/views/page-builder/NodeSettings.js +0 -80
  119. package/dist/views/page-builder/NodeSettings.js.map +0 -1
  120. package/dist/views/page-builder/PageBuilder.d.ts +0 -10
  121. package/dist/views/page-builder/PageBuilder.d.ts.map +0 -1
  122. package/dist/views/page-builder/PageBuilder.js +0 -222
  123. package/dist/views/page-builder/PageBuilder.js.map +0 -1
  124. package/dist/views/page-builder/PageSettings.d.ts +0 -7
  125. package/dist/views/page-builder/PageSettings.d.ts.map +0 -1
  126. package/dist/views/page-builder/PageSettings.js +0 -27
  127. package/dist/views/page-builder/PageSettings.js.map +0 -1
  128. package/dist/views/page-builder/PageTemplates.d.ts +0 -5
  129. package/dist/views/page-builder/PageTemplates.d.ts.map +0 -1
  130. package/dist/views/page-builder/PageTemplates.js +0 -146
  131. package/dist/views/page-builder/PageTemplates.js.map +0 -1
  132. package/dist/views/page-builder/RelationshipField.d.ts +0 -15
  133. package/dist/views/page-builder/RelationshipField.d.ts.map +0 -1
  134. package/dist/views/page-builder/RelationshipField.js +0 -65
  135. package/dist/views/page-builder/RelationshipField.js.map +0 -1
  136. package/dist/views/page-builder/SEOPanel.d.ts +0 -10
  137. package/dist/views/page-builder/SEOPanel.d.ts.map +0 -1
  138. package/dist/views/page-builder/SEOPanel.js +0 -103
  139. package/dist/views/page-builder/SEOPanel.js.map +0 -1
  140. package/dist/views/page-builder/SavedSections.d.ts +0 -6
  141. package/dist/views/page-builder/SavedSections.d.ts.map +0 -1
  142. package/dist/views/page-builder/SavedSections.js +0 -141
  143. package/dist/views/page-builder/SavedSections.js.map +0 -1
  144. package/dist/views/page-builder/TemplatePicker.d.ts +0 -7
  145. package/dist/views/page-builder/TemplatePicker.d.ts.map +0 -1
  146. package/dist/views/page-builder/TemplatePicker.js +0 -68
  147. package/dist/views/page-builder/TemplatePicker.js.map +0 -1
  148. package/dist/views/page-builder/Widgets.d.ts +0 -13
  149. package/dist/views/page-builder/Widgets.d.ts.map +0 -1
  150. package/dist/views/page-builder/Widgets.js +0 -15
  151. package/dist/views/page-builder/Widgets.js.map +0 -1
  152. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts +0 -3
  153. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +0 -1
  154. package/dist/views/page-builder/block-renderers/CTAPreview.js +0 -19
  155. package/dist/views/page-builder/block-renderers/CTAPreview.js.map +0 -1
  156. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts +0 -3
  157. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +0 -1
  158. package/dist/views/page-builder/block-renderers/CardsPreview.js +0 -22
  159. package/dist/views/page-builder/block-renderers/CardsPreview.js.map +0 -1
  160. package/dist/views/page-builder/block-renderers/CodePreview.d.ts +0 -3
  161. package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +0 -1
  162. package/dist/views/page-builder/block-renderers/CodePreview.js +0 -12
  163. package/dist/views/page-builder/block-renderers/CodePreview.js.map +0 -1
  164. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts +0 -3
  165. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +0 -1
  166. package/dist/views/page-builder/block-renderers/FAQPreview.js +0 -27
  167. package/dist/views/page-builder/block-renderers/FAQPreview.js.map +0 -1
  168. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts +0 -6
  169. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +0 -1
  170. package/dist/views/page-builder/block-renderers/FallbackPreview.js +0 -7
  171. package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +0 -1
  172. package/dist/views/page-builder/block-renderers/FormPreview.d.ts +0 -9
  173. package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +0 -1
  174. package/dist/views/page-builder/block-renderers/FormPreview.js +0 -52
  175. package/dist/views/page-builder/block-renderers/FormPreview.js.map +0 -1
  176. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts +0 -3
  177. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +0 -1
  178. package/dist/views/page-builder/block-renderers/GalleryPreview.js +0 -19
  179. package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +0 -1
  180. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts +0 -3
  181. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +0 -1
  182. package/dist/views/page-builder/block-renderers/HeroPreview.js +0 -19
  183. package/dist/views/page-builder/block-renderers/HeroPreview.js.map +0 -1
  184. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts +0 -3
  185. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +0 -1
  186. package/dist/views/page-builder/block-renderers/ImagePreview.js +0 -17
  187. package/dist/views/page-builder/block-renderers/ImagePreview.js.map +0 -1
  188. package/dist/views/page-builder/block-renderers/TextPreview.d.ts +0 -3
  189. package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +0 -1
  190. package/dist/views/page-builder/block-renderers/TextPreview.js +0 -22
  191. package/dist/views/page-builder/block-renderers/TextPreview.js.map +0 -1
  192. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts +0 -3
  193. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +0 -1
  194. package/dist/views/page-builder/block-renderers/VideoPreview.js +0 -18
  195. package/dist/views/page-builder/block-renderers/VideoPreview.js.map +0 -1
  196. package/dist/views/page-builder/block-renderers/index.d.ts +0 -9
  197. package/dist/views/page-builder/block-renderers/index.d.ts.map +0 -1
  198. package/dist/views/page-builder/block-renderers/index.js +0 -25
  199. package/dist/views/page-builder/block-renderers/index.js.map +0 -1
  200. package/dist/views/page-builder/canvas/BlockRenderer.d.ts +0 -8
  201. package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +0 -1
  202. package/dist/views/page-builder/canvas/BlockRenderer.js +0 -20
  203. package/dist/views/page-builder/canvas/BlockRenderer.js.map +0 -1
  204. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts +0 -10
  205. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +0 -1
  206. package/dist/views/page-builder/canvas/BuilderCanvas.js +0 -26
  207. package/dist/views/page-builder/canvas/BuilderCanvas.js.map +0 -1
  208. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts +0 -8
  209. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +0 -1
  210. package/dist/views/page-builder/canvas/ColumnRenderer.js +0 -32
  211. package/dist/views/page-builder/canvas/ColumnRenderer.js.map +0 -1
  212. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts +0 -8
  213. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +0 -1
  214. package/dist/views/page-builder/canvas/ContainerRenderer.js +0 -29
  215. package/dist/views/page-builder/canvas/ContainerRenderer.js.map +0 -1
  216. package/dist/views/page-builder/canvas/RowRenderer.d.ts +0 -8
  217. package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +0 -1
  218. package/dist/views/page-builder/canvas/RowRenderer.js +0 -28
  219. package/dist/views/page-builder/canvas/RowRenderer.js.map +0 -1
  220. package/dist/views/page-builder/canvas/SectionRenderer.d.ts +0 -8
  221. package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +0 -1
  222. package/dist/views/page-builder/canvas/SectionRenderer.js +0 -50
  223. package/dist/views/page-builder/canvas/SectionRenderer.js.map +0 -1
  224. package/dist/views/page-builder/canvas/index.d.ts +0 -3
  225. package/dist/views/page-builder/canvas/index.d.ts.map +0 -1
  226. package/dist/views/page-builder/canvas/index.js +0 -2
  227. package/dist/views/page-builder/canvas/index.js.map +0 -1
  228. package/src/__tests__/views/page-builder-block-renderer.render.test.tsx +0 -66
  229. package/src/__tests__/views/page-builder-form-picker.render.test.tsx +0 -54
  230. package/src/__tests__/views/page-builder-sections-panel.render.test.tsx +0 -138
  231. package/src/__tests__/views/page-builder-template-seed.render.test.tsx +0 -59
  232. package/src/__tests__/views/page-templates.render.test.tsx +0 -182
  233. package/src/hooks/useBuilderState.ts +0 -361
  234. package/src/views/page-builder/AIBlockAssist.tsx +0 -64
  235. package/src/views/page-builder/AIGenerateDialog.tsx +0 -593
  236. package/src/views/page-builder/BlockEditor.tsx +0 -523
  237. package/src/views/page-builder/BlockPicker.tsx +0 -324
  238. package/src/views/page-builder/BottomBar.tsx +0 -65
  239. package/src/views/page-builder/BuilderSectionsPanel.tsx +0 -304
  240. package/src/views/page-builder/BuilderToolbar.tsx +0 -221
  241. package/src/views/page-builder/ContextPanel.tsx +0 -145
  242. package/src/views/page-builder/DesignScore.tsx +0 -251
  243. package/src/views/page-builder/NodeSettings.tsx +0 -500
  244. package/src/views/page-builder/PageBuilder.tsx +0 -405
  245. package/src/views/page-builder/PageSettings.tsx +0 -162
  246. package/src/views/page-builder/PageTemplates.tsx +0 -435
  247. package/src/views/page-builder/RelationshipField.tsx +0 -113
  248. package/src/views/page-builder/SEOPanel.tsx +0 -464
  249. package/src/views/page-builder/SavedSections.tsx +0 -480
  250. package/src/views/page-builder/TemplatePicker.tsx +0 -197
  251. package/src/views/page-builder/Widgets.tsx +0 -44
  252. package/src/views/page-builder/block-renderers/CTAPreview.tsx +0 -79
  253. package/src/views/page-builder/block-renderers/CardsPreview.tsx +0 -69
  254. package/src/views/page-builder/block-renderers/CodePreview.tsx +0 -46
  255. package/src/views/page-builder/block-renderers/FAQPreview.tsx +0 -87
  256. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +0 -18
  257. package/src/views/page-builder/block-renderers/FormPreview.tsx +0 -117
  258. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +0 -87
  259. package/src/views/page-builder/block-renderers/HeroPreview.tsx +0 -90
  260. package/src/views/page-builder/block-renderers/ImagePreview.tsx +0 -54
  261. package/src/views/page-builder/block-renderers/TextPreview.tsx +0 -81
  262. package/src/views/page-builder/block-renderers/VideoPreview.tsx +0 -73
  263. package/src/views/page-builder/block-renderers/index.ts +0 -34
  264. package/src/views/page-builder/canvas/BlockRenderer.tsx +0 -56
  265. package/src/views/page-builder/canvas/BuilderCanvas.tsx +0 -87
  266. package/src/views/page-builder/canvas/ColumnRenderer.tsx +0 -82
  267. package/src/views/page-builder/canvas/ContainerRenderer.tsx +0 -67
  268. package/src/views/page-builder/canvas/RowRenderer.tsx +0 -68
  269. package/src/views/page-builder/canvas/SectionRenderer.tsx +0 -93
  270. package/src/views/page-builder/canvas/index.ts +0 -2
@@ -1,44 +0,0 @@
1
- 'use client'
2
-
3
- import { LayoutGrid } from 'lucide-react'
4
-
5
- export interface WidgetsProps {
6
- onNavigate?: (path: string) => void
7
- }
8
-
9
- /**
10
- * /widgets — placeholder for the embeddable Widgets library.
11
- *
12
- * Widgets are reusable, embeddable components (forms, CTAs, banners)
13
- * that can be dropped into pages and saved sections. The management UI
14
- * ships in a later release; this view establishes the route and nav
15
- * entry with an honest empty state rather than a dead link.
16
- */
17
- export function Widgets({ onNavigate }: WidgetsProps) {
18
- return (
19
- <div className="p-4 pr-8">
20
- <div className="mb-4">
21
- <h1 className="text-foreground mb-1">Widgets</h1>
22
- <p className="text-muted-foreground text-sm">
23
- Reusable, embeddable components for pages and saved sections.
24
- </p>
25
- </div>
26
-
27
- <div className="border-border bg-card rounded-lg border p-8 text-center">
28
- <LayoutGrid className="text-muted-foreground mx-auto mb-3 h-8 w-8" aria-hidden />
29
- <h2 className="text-foreground mb-1 text-lg font-medium">Widgets are coming soon</h2>
30
- <p className="text-muted-foreground mx-auto mb-4 max-w-md text-sm">
31
- The widget library lets you build embeddable components once and reuse them across pages.
32
- In the meantime, use Saved Sections for reusable content blocks.
33
- </p>
34
- <button
35
- type="button"
36
- onClick={() => onNavigate?.('/saved-sections')}
37
- className="bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium hover:opacity-90"
38
- >
39
- View Saved Sections
40
- </button>
41
- </div>
42
- </div>
43
- )
44
- }
@@ -1,79 +0,0 @@
1
- 'use client'
2
-
3
- import type { BlockPreviewProps } from './index.js'
4
-
5
- export function CTAPreview({ data, variant = 'banner' }: BlockPreviewProps) {
6
- const heading = (data.heading as string) || ''
7
- const body = (data.body as string) || ''
8
- const buttonText = (data.buttonText as string) || ''
9
-
10
- const button = (
11
- <span className="bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm">
12
- {buttonText || 'Click Here'}
13
- </span>
14
- )
15
-
16
- if (variant === 'inline') {
17
- return (
18
- <div className="border-border flex items-center justify-between gap-4 rounded-md border p-4">
19
- <div className="flex-1">
20
- <p className="text-foreground text-sm font-medium">
21
- {heading || <span className="text-muted-foreground">CTA Heading</span>}
22
- </p>
23
- {body && <p className="text-muted-foreground mt-1 text-xs">{body}</p>}
24
- </div>
25
- {button}
26
- </div>
27
- )
28
- }
29
-
30
- if (variant === 'floating') {
31
- return (
32
- <div className="border-border bg-card mx-auto max-w-md rounded-lg border p-6 shadow-md">
33
- <div className="text-center">
34
- <h3 className="text-foreground text-lg font-medium">
35
- {heading || <span className="text-muted-foreground">CTA Heading</span>}
36
- </h3>
37
- {(body || !heading) && (
38
- <p className="text-muted-foreground mt-2 text-sm">
39
- {body || 'Supporting text for the call to action'}
40
- </p>
41
- )}
42
- <div className="mt-4">{button}</div>
43
- </div>
44
- </div>
45
- )
46
- }
47
-
48
- if (variant === 'split') {
49
- return (
50
- <div className="border-border flex items-center gap-6 rounded-md border p-6">
51
- <div className="flex-1">
52
- <h3 className="text-foreground text-lg font-medium">
53
- {heading || <span className="text-muted-foreground">CTA Heading</span>}
54
- </h3>
55
- {(body || !heading) && (
56
- <p className="text-muted-foreground mt-2 text-sm">
57
- {body || 'Supporting text for the call to action'}
58
- </p>
59
- )}
60
- </div>
61
- <div className="shrink-0">{button}</div>
62
- </div>
63
- )
64
- }
65
-
66
- return (
67
- <div className="border-border bg-accent rounded-md border p-6 text-center">
68
- <h3 className="text-foreground text-lg font-medium">
69
- {heading || <span className="text-muted-foreground">CTA Heading</span>}
70
- </h3>
71
- {(body || !heading) && (
72
- <p className="text-muted-foreground mt-2 text-sm">
73
- {body || 'Supporting text for the call to action'}
74
- </p>
75
- )}
76
- <div className="mt-4">{button}</div>
77
- </div>
78
- )
79
- }
@@ -1,69 +0,0 @@
1
- 'use client'
2
-
3
- import { Image } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- interface CardItem {
7
- title?: string
8
- description?: string
9
- image?: string
10
- link?: string
11
- icon?: string
12
- }
13
-
14
- export function CardsPreview({ data, variant = 'grid-3' }: BlockPreviewProps) {
15
- const items = (data.items as CardItem[]) || []
16
-
17
- const placeholderItems: CardItem[] =
18
- items.length > 0
19
- ? items
20
- : [
21
- { title: 'Card Title', description: 'Card description text' },
22
- { title: 'Card Title', description: 'Card description text' },
23
- { title: 'Card Title', description: 'Card description text' },
24
- ]
25
-
26
- const gridClass =
27
- variant === 'grid-2'
28
- ? 'grid grid-cols-2 gap-3'
29
- : variant === 'grid-4'
30
- ? 'grid grid-cols-4 gap-3'
31
- : variant === 'horizontal'
32
- ? 'flex gap-3 overflow-hidden'
33
- : 'grid grid-cols-3 gap-3'
34
-
35
- return (
36
- <div className="border-border rounded-md border p-4">
37
- <div className={gridClass}>
38
- {placeholderItems.map((item, i) => (
39
- <div
40
- key={i}
41
- className={`border-border bg-card flex flex-col overflow-hidden rounded-md border ${variant === 'horizontal' ? 'min-w-40' : ''}`}
42
- >
43
- <div className="bg-muted flex h-20 items-center justify-center">
44
- {item.image ? (
45
- <img
46
- src={item.image}
47
- alt={item.title || ''}
48
- className="h-full w-full object-cover"
49
- />
50
- ) : (
51
- <Image size={20} className="text-muted-foreground" />
52
- )}
53
- </div>
54
- <div className="p-3">
55
- <p className="text-foreground text-sm font-medium">
56
- {item.title || <span className="text-muted-foreground">Card Title</span>}
57
- </p>
58
- {item.description && (
59
- <p className="text-muted-foreground mt-1 line-clamp-2 text-xs">
60
- {item.description}
61
- </p>
62
- )}
63
- </div>
64
- </div>
65
- ))}
66
- </div>
67
- </div>
68
- )
69
- }
@@ -1,46 +0,0 @@
1
- 'use client'
2
-
3
- import { Code, Globe, Terminal } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- export function CodePreview({ data, variant = 'embed' }: BlockPreviewProps) {
7
- const content = (data.content as string) || ''
8
- const language = (data.language as string) || ''
9
- const sandboxed = data.sandboxed as boolean | undefined
10
-
11
- const truncated = content.length > 200 ? content.slice(0, 200) + '…' : content
12
-
13
- const icon =
14
- variant === 'html' ? (
15
- <Globe size={14} className="text-muted-foreground" />
16
- ) : variant === 'script' ? (
17
- <Terminal size={14} className="text-muted-foreground" />
18
- ) : (
19
- <Code size={14} className="text-muted-foreground" />
20
- )
21
-
22
- return (
23
- <div className="border-border overflow-hidden rounded-md border">
24
- <div className="border-border bg-card flex items-center gap-2 border-b px-3 py-2">
25
- {icon}
26
- <span className="text-muted-foreground text-xs">{language || variant}</span>
27
- {sandboxed && (
28
- <span className="bg-muted text-muted-foreground ml-auto rounded px-1.5 py-0.5 text-xs">
29
- sandboxed
30
- </span>
31
- )}
32
- </div>
33
- <div className="bg-card p-4">
34
- {truncated ? (
35
- <pre className="text-foreground overflow-hidden font-mono text-xs whitespace-pre-wrap">
36
- {truncated}
37
- </pre>
38
- ) : (
39
- <p className="text-muted-foreground font-mono text-xs italic">
40
- // Code content goes here…
41
- </p>
42
- )}
43
- </div>
44
- </div>
45
- )
46
- }
@@ -1,87 +0,0 @@
1
- 'use client'
2
-
3
- import { ChevronDown } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- interface FAQItem {
7
- question?: string
8
- answer?: string
9
- }
10
-
11
- export function FAQPreview({ data, variant = 'accordion' }: BlockPreviewProps) {
12
- const items = (data.items as FAQItem[]) || []
13
-
14
- const placeholderItems: FAQItem[] =
15
- items.length > 0
16
- ? items
17
- : [
18
- { question: 'What is this?', answer: 'Answer to the first question goes here.' },
19
- { question: 'How does it work?', answer: 'Answer to the second question goes here.' },
20
- {
21
- question: 'Where can I learn more?',
22
- answer: 'Answer to the third question goes here.',
23
- },
24
- ]
25
-
26
- if (variant === 'two-column') {
27
- const mid = Math.ceil(placeholderItems.length / 2)
28
- const col1 = placeholderItems.slice(0, mid)
29
- const col2 = placeholderItems.slice(mid)
30
-
31
- return (
32
- <div className="border-border rounded-md border p-4">
33
- <div className="grid grid-cols-2 gap-4">
34
- {[col1, col2].map((column, colIdx) => (
35
- <div key={colIdx} className="flex flex-col gap-3">
36
- {column.map((item, i) => (
37
- <div key={i} className="border-border rounded-md border p-3">
38
- <p className="text-foreground text-sm font-medium">
39
- {item.question || 'Question?'}
40
- </p>
41
- <p className="text-muted-foreground mt-1 line-clamp-2 text-xs">
42
- {item.answer || 'Answer text…'}
43
- </p>
44
- </div>
45
- ))}
46
- </div>
47
- ))}
48
- </div>
49
- </div>
50
- )
51
- }
52
-
53
- if (variant === 'list') {
54
- return (
55
- <div className="border-border rounded-md border p-4">
56
- <div className="flex flex-col gap-3">
57
- {placeholderItems.map((item, i) => (
58
- <div key={i} className="border-border border-b pb-3 last:border-b-0 last:pb-0">
59
- <p className="text-foreground text-sm font-medium">{item.question || 'Question?'}</p>
60
- <p className="text-muted-foreground mt-1 line-clamp-2 text-xs">
61
- {item.answer || 'Answer text…'}
62
- </p>
63
- </div>
64
- ))}
65
- </div>
66
- </div>
67
- )
68
- }
69
-
70
- return (
71
- <div className="border-border rounded-md border p-4">
72
- <div className="flex flex-col gap-2">
73
- {placeholderItems.map((item, i) => (
74
- <div key={i} className="border-border rounded-md border p-3">
75
- <div className="flex items-center justify-between">
76
- <p className="text-foreground text-sm font-medium">{item.question || 'Question?'}</p>
77
- <ChevronDown size={14} className="text-muted-foreground shrink-0" />
78
- </div>
79
- {i === 0 && (
80
- <p className="text-muted-foreground mt-2 text-xs">{item.answer || 'Answer text…'}</p>
81
- )}
82
- </div>
83
- ))}
84
- </div>
85
- </div>
86
- )
87
- }
@@ -1,18 +0,0 @@
1
- 'use client'
2
-
3
- import { Box } from 'lucide-react'
4
-
5
- export interface FallbackPreviewProps {
6
- blockType: string
7
- data: Record<string, unknown>
8
- }
9
-
10
- export function FallbackPreview({ blockType }: FallbackPreviewProps) {
11
- return (
12
- <div className="border-border bg-muted/50 flex flex-col items-center justify-center gap-2 rounded-md border border-dashed p-8">
13
- <Box size={24} className="text-muted-foreground" />
14
- <p className="text-muted-foreground text-sm font-medium">{blockType}</p>
15
- <p className="text-muted-foreground text-xs">No preview available</p>
16
- </div>
17
- )
18
- }
@@ -1,117 +0,0 @@
1
- 'use client'
2
-
3
- import { useEffect, useState } from 'react'
4
- import { FileText, Mail, Send } from 'lucide-react'
5
- import { cmsApi } from '../../../lib/api.js'
6
- import type { BlockPreviewProps } from './index.js'
7
-
8
- interface PreviewField {
9
- key: string
10
- label: string
11
- type: string
12
- }
13
-
14
- interface PreviewForm {
15
- name: string
16
- fields: PreviewField[]
17
- }
18
-
19
- /**
20
- * Canvas preview for the form block. When a form is linked we fetch its real
21
- * name + fields so the editor sees what will render; otherwise we fall back to
22
- * a generic skeleton. Network failures degrade to the skeleton rather than
23
- * breaking the canvas.
24
- */
25
- export function FormPreview({ data, variant = 'contact' }: BlockPreviewProps) {
26
- const formId = (data.formId as string) || ''
27
- const [form, setForm] = useState<PreviewForm | null>(null)
28
- const [loading, setLoading] = useState(false)
29
-
30
- useEffect(() => {
31
- if (!formId) {
32
- setForm(null)
33
- return
34
- }
35
- let cancelled = false
36
- setLoading(true)
37
- cmsApi<{ name?: string; fields?: PreviewField[] }>(`/forms/${encodeURIComponent(formId)}`)
38
- .then((res) => {
39
- if (cancelled) return
40
- if (res.data?.name) {
41
- setForm({ name: res.data.name, fields: res.data.fields ?? [] })
42
- } else {
43
- setForm(null)
44
- }
45
- })
46
- .finally(() => {
47
- if (!cancelled) setLoading(false)
48
- })
49
- return () => {
50
- cancelled = true
51
- }
52
- }, [formId])
53
-
54
- if (!formId) {
55
- return (
56
- <div className="border-border bg-muted/30 rounded-md border border-dashed p-6 text-center">
57
- <FileText size={20} className="text-muted-foreground mx-auto" />
58
- <p className="text-muted-foreground mt-2 text-sm">No form selected</p>
59
- <p className="text-muted-foreground/70 text-xs">Pick a form in the block settings</p>
60
- </div>
61
- )
62
- }
63
-
64
- const heading = form?.name ?? (loading ? 'Loading form…' : 'Contact Form')
65
- const fields = form?.fields ?? []
66
-
67
- if (variant === 'newsletter') {
68
- return (
69
- <div className="border-border rounded-md border p-6 text-center">
70
- <Mail size={24} className="text-muted-foreground mx-auto" />
71
- <p className="text-foreground mt-3 text-sm font-medium">
72
- {form?.name ?? 'Newsletter Signup'}
73
- </p>
74
- <div className="mx-auto mt-4 flex max-w-xs gap-2">
75
- <div className="border-border bg-input-background h-9 flex-1 rounded-md border" />
76
- <div className="bg-primary flex h-9 items-center rounded-md px-3">
77
- <Send size={14} className="text-primary-foreground" />
78
- </div>
79
- </div>
80
- </div>
81
- )
82
- }
83
-
84
- return (
85
- <div className="border-border rounded-md border p-5">
86
- <div className="flex items-center gap-2">
87
- <FileText size={16} className="text-muted-foreground" />
88
- <p className="text-foreground text-sm font-medium">{heading}</p>
89
- </div>
90
- <div className="mt-3 flex flex-col gap-2">
91
- {fields.length > 0 ? (
92
- fields.slice(0, 5).map((field) => (
93
- <div key={field.key}>
94
- <p className="text-muted-foreground mb-1 text-xs">{field.label || field.key}</p>
95
- <div
96
- className={`border-border bg-input-background rounded-md border ${
97
- field.type === 'textarea' ? 'h-16' : 'h-8'
98
- }`}
99
- />
100
- </div>
101
- ))
102
- ) : (
103
- <>
104
- <div className="border-border bg-input-background h-8 rounded-md border" />
105
- <div className="border-border bg-input-background h-8 rounded-md border" />
106
- <div className="border-border bg-input-background h-20 rounded-md border" />
107
- </>
108
- )}
109
- </div>
110
- <div className="mt-3">
111
- <span className="bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm">
112
- {variant === 'custom' ? 'Submit' : 'Send Message'}
113
- </span>
114
- </div>
115
- </div>
116
- )
117
- }
@@ -1,87 +0,0 @@
1
- 'use client'
2
-
3
- import { Image } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- interface GalleryImage {
7
- src?: string
8
- alt?: string
9
- caption?: string
10
- }
11
-
12
- export function GalleryPreview({ data, variant = 'grid' }: BlockPreviewProps) {
13
- const images = (data.images as GalleryImage[]) || []
14
-
15
- const placeholders: GalleryImage[] =
16
- images.length > 0 ? images : Array.from({ length: 6 }, (_, i) => ({ alt: `Image ${i + 1}` }))
17
-
18
- const Thumbnail = ({ item, className = '' }: { item: GalleryImage; className?: string }) => (
19
- <div
20
- className={`bg-muted flex items-center justify-center overflow-hidden rounded-md ${className}`}
21
- >
22
- {item.src ? (
23
- <img src={item.src} alt={item.alt || ''} className="h-full w-full object-cover" />
24
- ) : (
25
- <Image size={20} className="text-muted-foreground" />
26
- )}
27
- </div>
28
- )
29
-
30
- if (variant === 'masonry') {
31
- return (
32
- <div className="border-border rounded-md border p-4">
33
- <div className="columns-3 gap-3 space-y-3">
34
- {placeholders.map((item, i) => (
35
- <Thumbnail
36
- key={i}
37
- item={item}
38
- className={
39
- i % 3 === 0 ? 'aspect-square' : i % 3 === 1 ? 'aspect-[3/4]' : 'aspect-[4/3]'
40
- }
41
- />
42
- ))}
43
- </div>
44
- </div>
45
- )
46
- }
47
-
48
- if (variant === 'carousel') {
49
- return (
50
- <div className="border-border overflow-hidden rounded-md border p-4">
51
- <div className="flex gap-3 overflow-hidden">
52
- {placeholders.slice(0, 4).map((item, i) => (
53
- <Thumbnail key={i} item={item} className="aspect-square min-w-[120px] flex-1" />
54
- ))}
55
- {placeholders.length > 4 && (
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
- </div>
59
- )}
60
- </div>
61
- </div>
62
- )
63
- }
64
-
65
- if (variant === 'lightbox') {
66
- return (
67
- <div className="border-border rounded-md border p-4">
68
- <div className="grid grid-cols-3 gap-3">
69
- {placeholders.map((item, i) => (
70
- <Thumbnail key={i} item={item} className="aspect-square" />
71
- ))}
72
- </div>
73
- <p className="text-muted-foreground mt-2 text-center text-xs">Click to open lightbox</p>
74
- </div>
75
- )
76
- }
77
-
78
- return (
79
- <div className="border-border rounded-md border p-4">
80
- <div className="grid grid-cols-3 gap-3">
81
- {placeholders.map((item, i) => (
82
- <Thumbnail key={i} item={item} className="aspect-square" />
83
- ))}
84
- </div>
85
- </div>
86
- )
87
- }
@@ -1,90 +0,0 @@
1
- 'use client'
2
-
3
- import { Image, Play } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- export function HeroPreview({ data, variant = 'centered' }: BlockPreviewProps) {
7
- const title = (data.title as string) || ''
8
- const subtitle = (data.subtitle as string) || ''
9
- const image = data.image as string | undefined
10
- const ctaText = (data.ctaText as string) || ''
11
- const overlayOpacity = (data.overlayOpacity as number) ?? 0.4
12
-
13
- if (variant === 'split-image') {
14
- return (
15
- <div className="border-border flex min-h-[200px] overflow-hidden rounded-md border">
16
- <div className="flex flex-1 flex-col justify-center gap-3 p-6">
17
- <h2 className="text-foreground text-2xl font-medium">
18
- {title || <span className="text-muted-foreground">Hero Title</span>}
19
- </h2>
20
- {(subtitle || !title) && (
21
- <p className="text-muted-foreground text-sm">{subtitle || 'Subtitle text goes here'}</p>
22
- )}
23
- {ctaText && (
24
- <div className="mt-2">
25
- <span className="bg-primary text-primary-foreground inline-block rounded-md px-4 py-2 text-sm">
26
- {ctaText}
27
- </span>
28
- </div>
29
- )}
30
- </div>
31
- <div className="bg-muted flex flex-1 items-center justify-center">
32
- {image ? (
33
- <img src={image} alt="" className="h-full w-full object-cover" />
34
- ) : (
35
- <Image size={32} className="text-muted-foreground" />
36
- )}
37
- </div>
38
- </div>
39
- )
40
- }
41
-
42
- if (variant === 'minimal') {
43
- return (
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
- {title || <span className="text-muted-foreground">Hero Title</span>}
47
- </h2>
48
- {(subtitle || !title) && (
49
- <p className="text-muted-foreground text-sm">{subtitle || 'Subtitle text goes here'}</p>
50
- )}
51
- {ctaText && (
52
- <span className="bg-primary text-primary-foreground mt-2 inline-block rounded-md px-4 py-2 text-sm">
53
- {ctaText}
54
- </span>
55
- )}
56
- </div>
57
- )
58
- }
59
-
60
- const isVideo = variant === 'video-bg'
61
-
62
- return (
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
- {image ? (
65
- <img src={image} alt="" className="absolute inset-0 h-full w-full object-cover" />
66
- ) : (
67
- <div className="bg-muted absolute inset-0" />
68
- )}
69
- <div className="bg-background absolute inset-0" style={{ opacity: overlayOpacity }} />
70
- <div className="relative z-10 flex flex-col items-center gap-3 text-center">
71
- {isVideo && (
72
- <div className="bg-primary/90 mb-2 flex h-12 w-12 items-center justify-center rounded-full">
73
- <Play size={20} className="text-primary-foreground" />
74
- </div>
75
- )}
76
- <h2 className="text-foreground text-2xl font-medium">
77
- {title || <span className="text-muted-foreground">Hero Title</span>}
78
- </h2>
79
- {(subtitle || !title) && (
80
- <p className="text-muted-foreground text-sm">{subtitle || 'Subtitle text goes here'}</p>
81
- )}
82
- {ctaText && (
83
- <span className="bg-primary text-primary-foreground mt-2 inline-block rounded-md px-4 py-2 text-sm">
84
- {ctaText}
85
- </span>
86
- )}
87
- </div>
88
- </div>
89
- )
90
- }