@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,54 +0,0 @@
1
- 'use client'
2
-
3
- import { Image } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- export function ImagePreview({ data, variant = 'full-width' }: BlockPreviewProps) {
7
- const src = data.src as string | undefined
8
- const alt = (data.alt as string) || ''
9
- const caption = (data.caption as string) || ''
10
- const aspectRatio = (data.aspectRatio as string) || '16/9'
11
-
12
- const roundedClass = variant === 'rounded' ? 'rounded-xl' : 'rounded-md'
13
-
14
- const ImagePlaceholder = ({ className = '' }: { className?: string }) => (
15
- <div
16
- className={`bg-muted flex items-center justify-center ${roundedClass} ${className}`}
17
- style={{ aspectRatio }}
18
- >
19
- <Image size={32} className="text-muted-foreground" />
20
- </div>
21
- )
22
-
23
- const ImageElement = ({ className = '' }: { className?: string }) =>
24
- src ? (
25
- <img
26
- src={src}
27
- alt={alt}
28
- className={`h-auto w-full object-cover ${roundedClass} ${className}`}
29
- style={{ aspectRatio }}
30
- />
31
- ) : (
32
- <ImagePlaceholder className={className} />
33
- )
34
-
35
- if (variant === 'side-by-side') {
36
- return (
37
- <div className="border-border grid grid-cols-2 gap-3 rounded-md border p-4">
38
- <ImageElement />
39
- <ImagePlaceholder />
40
- </div>
41
- )
42
- }
43
-
44
- return (
45
- <figure className="border-border overflow-hidden rounded-md border p-4">
46
- <ImageElement />
47
- {(variant === 'captioned' || caption) && (
48
- <figcaption className="text-muted-foreground mt-2 text-center text-sm">
49
- {caption || 'Image caption'}
50
- </figcaption>
51
- )}
52
- </figure>
53
- )
54
- }
@@ -1,81 +0,0 @@
1
- 'use client'
2
-
3
- import type { BlockPreviewProps } from './index.js'
4
-
5
- export function TextPreview({ data, variant = 'prose' }: BlockPreviewProps) {
6
- const body = (data.body as string) || ''
7
- const heading = (data.heading as string) || ''
8
- const headingLevel = (data.headingLevel as string) || 'h2'
9
-
10
- const truncatedBody = body.length > 300 ? body.slice(0, 300) + '…' : body
11
-
12
- const validLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const
13
- const HeadingTag = (validLevels.includes(headingLevel as any) ? headingLevel : 'h2') as
14
- | 'h1'
15
- | 'h2'
16
- | 'h3'
17
- | 'h4'
18
- | 'h5'
19
- | 'h6'
20
- const headingSizeClass =
21
- HeadingTag === 'h1' ? 'text-2xl' : HeadingTag === 'h2' ? 'text-xl' : 'text-lg'
22
-
23
- if (variant === 'two-column') {
24
- const midpoint = Math.ceil(truncatedBody.length / 2)
25
- const col1 = truncatedBody.slice(0, midpoint)
26
- const col2 = truncatedBody.slice(midpoint)
27
-
28
- return (
29
- <div className="border-border rounded-md border p-5">
30
- {heading && (
31
- <HeadingTag className={`${headingSizeClass} text-foreground mb-3 font-medium`}>
32
- {heading}
33
- </HeadingTag>
34
- )}
35
- <div className="grid grid-cols-2 gap-4">
36
- <p className="text-muted-foreground text-sm leading-relaxed">
37
- {col1 || 'Column one text content…'}
38
- </p>
39
- <p className="text-muted-foreground text-sm leading-relaxed">
40
- {col2 || 'Column two text content…'}
41
- </p>
42
- </div>
43
- </div>
44
- )
45
- }
46
-
47
- if (variant === 'with-sidebar') {
48
- return (
49
- <div className="border-border grid grid-cols-[1fr_200px] gap-4 rounded-md border p-5">
50
- <div>
51
- {heading && (
52
- <HeadingTag className={`${headingSizeClass} text-foreground mb-3 font-medium`}>
53
- {heading}
54
- </HeadingTag>
55
- )}
56
- <p className="text-muted-foreground text-sm leading-relaxed">
57
- {truncatedBody || 'Body text content goes here…'}
58
- </p>
59
- </div>
60
- <aside className="bg-muted rounded-md p-3">
61
- <div className="bg-border h-3 w-3/4 rounded" />
62
- <div className="bg-border mt-2 h-2 w-full rounded" />
63
- <div className="bg-border mt-1 h-2 w-2/3 rounded" />
64
- </aside>
65
- </div>
66
- )
67
- }
68
-
69
- return (
70
- <div className="border-border rounded-md border p-5">
71
- {heading && (
72
- <HeadingTag className={`${headingSizeClass} text-foreground mb-3 font-medium`}>
73
- {heading}
74
- </HeadingTag>
75
- )}
76
- <p className="text-muted-foreground text-sm leading-relaxed">
77
- {truncatedBody || <span className="italic">Body text content goes here…</span>}
78
- </p>
79
- </div>
80
- )
81
- }
@@ -1,73 +0,0 @@
1
- 'use client'
2
-
3
- import { Play } from 'lucide-react'
4
- import type { BlockPreviewProps } from './index.js'
5
-
6
- export function VideoPreview({ data, variant = 'inline' }: BlockPreviewProps) {
7
- const poster = data.poster as string | undefined
8
- const autoplay = data.autoplay as boolean | undefined
9
- const loop = data.loop as boolean | undefined
10
-
11
- const badges: string[] = [autoplay ? 'Autoplay' : '', loop ? 'Loop' : ''].filter(
12
- (b): b is string => b !== '',
13
- )
14
-
15
- const content = (
16
- <div className="bg-muted relative flex aspect-video items-center justify-center overflow-hidden rounded-md">
17
- {poster ? (
18
- <img src={poster} alt="" className="absolute inset-0 h-full w-full object-cover" />
19
- ) : (
20
- <div className="bg-card absolute inset-0" />
21
- )}
22
- <div className="bg-primary/90 relative z-10 flex h-12 w-12 items-center justify-center rounded-full shadow-sm">
23
- <Play size={20} className="text-primary-foreground" />
24
- </div>
25
- {badges.length > 0 && (
26
- <div className="absolute right-2 bottom-2 z-10 flex gap-1">
27
- {badges.map((badge) => (
28
- <span
29
- key={badge}
30
- className="bg-background/80 text-muted-foreground rounded px-1.5 py-0.5 text-xs"
31
- >
32
- {badge}
33
- </span>
34
- ))}
35
- </div>
36
- )}
37
- </div>
38
- )
39
-
40
- if (variant === 'background') {
41
- return (
42
- <div className="border-border overflow-hidden rounded-md border">
43
- <div className="relative aspect-[21/9]">
44
- {poster ? (
45
- <img src={poster} alt="" className="absolute inset-0 h-full w-full object-cover" />
46
- ) : (
47
- <div className="bg-card absolute inset-0" />
48
- )}
49
- <div className="bg-background/30 absolute inset-0 flex items-center justify-center">
50
- <div className="bg-primary/90 flex h-14 w-14 items-center justify-center rounded-full shadow-sm">
51
- <Play size={24} className="text-primary-foreground" />
52
- </div>
53
- </div>
54
- </div>
55
- </div>
56
- )
57
- }
58
-
59
- if (variant === 'lightbox') {
60
- return (
61
- <div className="border-border rounded-md border p-4">
62
- <div className="mx-auto max-w-sm">
63
- {content}
64
- <p className="text-muted-foreground mt-2 text-center text-xs">
65
- Click to play in lightbox
66
- </p>
67
- </div>
68
- </div>
69
- )
70
- }
71
-
72
- return <div className="border-border rounded-md border p-4">{content}</div>
73
- }
@@ -1,34 +0,0 @@
1
- 'use client'
2
-
3
- import type { ComponentType } from 'react'
4
- import { HeroPreview } from './HeroPreview.js'
5
- import { TextPreview } from './TextPreview.js'
6
- import { ImagePreview } from './ImagePreview.js'
7
- import { CardsPreview } from './CardsPreview.js'
8
- import { CTAPreview } from './CTAPreview.js'
9
- import { VideoPreview } from './VideoPreview.js'
10
- import { GalleryPreview } from './GalleryPreview.js'
11
- import { FAQPreview } from './FAQPreview.js'
12
- import { FormPreview } from './FormPreview.js'
13
- import { CodePreview } from './CodePreview.js'
14
-
15
- export interface BlockPreviewProps {
16
- data: Record<string, unknown>
17
- variant?: string
18
- }
19
-
20
- export const blockRenderers: Record<string, ComponentType<BlockPreviewProps>> = {
21
- hero: HeroPreview,
22
- text: TextPreview,
23
- image: ImagePreview,
24
- cards: CardsPreview,
25
- cta: CTAPreview,
26
- video: VideoPreview,
27
- gallery: GalleryPreview,
28
- faq: FAQPreview,
29
- form: FormPreview,
30
- code: CodePreview,
31
- }
32
-
33
- export { FallbackPreview } from './FallbackPreview.js'
34
- export type { FallbackPreviewProps } from './FallbackPreview.js'
@@ -1,56 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import type { BlockNode } from '@prenta/core'
5
- import { blockRenderers, FallbackPreview } from '../block-renderers/index.js'
6
-
7
- export interface BlockRendererProps {
8
- node: BlockNode
9
- selectedNodeId: string | null
10
- onSelectNode: (id: string | null) => void
11
- }
12
-
13
- function getBlockLabel(blockType: string): string {
14
- return blockType.charAt(0).toUpperCase() + blockType.slice(1)
15
- }
16
-
17
- export function BlockRenderer({ node, selectedNodeId, onSelectNode }: BlockRendererProps) {
18
- const [hovered, setHovered] = useState(false)
19
- const isSelected = selectedNodeId === node.id
20
- const blockType = node.settings.blockType
21
- const label = getBlockLabel(blockType)
22
- const Preview = blockRenderers[blockType]
23
-
24
- const handleClick = (e: React.MouseEvent) => {
25
- e.stopPropagation()
26
- onSelectNode(node.id)
27
- }
28
-
29
- return (
30
- <div
31
- data-node-id={node.id}
32
- data-block-type={blockType}
33
- className={`relative min-h-[48px] transition-shadow ${
34
- isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
35
- }`}
36
- onClick={handleClick}
37
- onMouseEnter={() => setHovered(true)}
38
- onMouseLeave={() => setHovered(false)}
39
- >
40
- {(hovered || isSelected) && (
41
- <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">
42
- {label}
43
- </span>
44
- )}
45
-
46
- {/* Previews are display-only on the canvas; the wrapper owns selection. */}
47
- <div className="pointer-events-none">
48
- {Preview ? (
49
- <Preview data={node.data} variant={node.settings.variant} />
50
- ) : (
51
- <FallbackPreview blockType={blockType} data={node.data} />
52
- )}
53
- </div>
54
- </div>
55
- )
56
- }
@@ -1,87 +0,0 @@
1
- 'use client'
2
-
3
- import { LayoutGrid } from 'lucide-react'
4
- import type { PageNode } from '@prenta/core'
5
- import { SectionRenderer } from './SectionRenderer.js'
6
-
7
- export interface BuilderCanvasProps {
8
- tree: PageNode
9
- selectedNodeId: string | null
10
- showGridOverlay: boolean
11
- deviceMode: 'desktop' | 'tablet' | 'mobile'
12
- onSelectNode: (id: string | null) => void
13
- }
14
-
15
- const DEVICE_CLASSES: Record<BuilderCanvasProps['deviceMode'], string> = {
16
- desktop: 'w-full',
17
- tablet: 'max-w-[768px] mx-auto',
18
- mobile: 'max-w-[375px] mx-auto',
19
- }
20
-
21
- export function BuilderCanvas({
22
- tree,
23
- selectedNodeId,
24
- showGridOverlay,
25
- deviceMode,
26
- onSelectNode,
27
- }: BuilderCanvasProps) {
28
- const handleCanvasClick = (e: React.MouseEvent) => {
29
- if (e.target === e.currentTarget) {
30
- onSelectNode(null)
31
- }
32
- }
33
-
34
- return (
35
- <div className="bg-muted relative flex-1 overflow-auto p-6" onClick={handleCanvasClick}>
36
- {showGridOverlay && <GridOverlay deviceMode={deviceMode} />}
37
-
38
- <div
39
- className={`bg-background relative min-h-full shadow-sm ${DEVICE_CLASSES[deviceMode]}`}
40
- onClick={handleCanvasClick}
41
- >
42
- {tree.children.map((child) => {
43
- if (child.type === 'section') {
44
- return (
45
- <SectionRenderer
46
- key={child.id}
47
- node={child}
48
- selectedNodeId={selectedNodeId}
49
- onSelectNode={onSelectNode}
50
- />
51
- )
52
- }
53
- return null
54
- })}
55
-
56
- {tree.children.length === 0 && (
57
- <div className="flex min-h-[400px] flex-col items-center justify-center text-center">
58
- <LayoutGrid size={32} className="text-muted-foreground mb-3" />
59
- <p className="text-foreground mb-1 text-sm font-medium">No sections yet</p>
60
- <p className="text-muted-foreground text-xs">
61
- Click "Add Section" below to start building your page
62
- </p>
63
- </div>
64
- )}
65
- </div>
66
- </div>
67
- )
68
- }
69
-
70
- function GridOverlay({ deviceMode }: { deviceMode: BuilderCanvasProps['deviceMode'] }) {
71
- return (
72
- <div
73
- className={`pointer-events-none absolute inset-0 z-50 p-6 ${
74
- deviceMode !== 'desktop' ? 'flex justify-center' : ''
75
- }`}
76
- aria-hidden="true"
77
- >
78
- <div
79
- className={`grid h-full grid-cols-12 gap-4 opacity-[0.08] ${DEVICE_CLASSES[deviceMode]}`}
80
- >
81
- {Array.from({ length: 12 }).map((_, i) => (
82
- <div key={i} className="bg-primary h-full rounded-sm" />
83
- ))}
84
- </div>
85
- </div>
86
- )
87
- }
@@ -1,82 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import type { ColumnNode } from '@prenta/core'
5
- import { BlockRenderer } from './BlockRenderer.js'
6
- import { ContainerRenderer } from './ContainerRenderer.js'
7
-
8
- export interface ColumnRendererProps {
9
- node: ColumnNode
10
- selectedNodeId: string | null
11
- onSelectNode: (id: string | null) => void
12
- }
13
-
14
- export function ColumnRenderer({ node, selectedNodeId, onSelectNode }: ColumnRendererProps) {
15
- const [hovered, setHovered] = useState(false)
16
- const isSelected = selectedNodeId === node.id
17
- const width = node.settings.width
18
- const isEmpty = node.children.length === 0
19
-
20
- const handleClick = (e: React.MouseEvent) => {
21
- e.stopPropagation()
22
- onSelectNode(node.id)
23
- }
24
-
25
- return (
26
- <div
27
- data-node-id={node.id}
28
- className={`relative transition-shadow ${
29
- isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
30
- }`}
31
- style={{
32
- gridColumn: `span ${width}`,
33
- padding: node.settings.padding,
34
- background: node.settings.background,
35
- }}
36
- onClick={handleClick}
37
- onMouseEnter={(e) => {
38
- e.stopPropagation()
39
- setHovered(true)
40
- }}
41
- onMouseLeave={() => setHovered(false)}
42
- >
43
- {(hovered || isSelected) && (
44
- <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
45
- Col {width}
46
- </span>
47
- )}
48
-
49
- {isEmpty ? (
50
- <div className="border-border text-muted-foreground flex min-h-[64px] items-center justify-center rounded-md border-2 border-dashed text-sm">
51
- Empty column
52
- </div>
53
- ) : (
54
- <div className="flex flex-col gap-2">
55
- {node.children.map((child) => {
56
- if (child.type === 'block') {
57
- return (
58
- <BlockRenderer
59
- key={child.id}
60
- node={child}
61
- selectedNodeId={selectedNodeId}
62
- onSelectNode={onSelectNode}
63
- />
64
- )
65
- }
66
- if (child.type === 'container') {
67
- return (
68
- <ContainerRenderer
69
- key={child.id}
70
- node={child}
71
- selectedNodeId={selectedNodeId}
72
- onSelectNode={onSelectNode}
73
- />
74
- )
75
- }
76
- return null
77
- })}
78
- </div>
79
- )}
80
- </div>
81
- )
82
- }
@@ -1,67 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import type { ContainerNode } from '@prenta/core'
5
- import { RowRenderer } from './RowRenderer.js'
6
-
7
- export interface ContainerRendererProps {
8
- node: ContainerNode
9
- selectedNodeId: string | null
10
- onSelectNode: (id: string | null) => void
11
- }
12
-
13
- export function ContainerRenderer({ node, selectedNodeId, onSelectNode }: ContainerRendererProps) {
14
- const [hovered, setHovered] = useState(false)
15
- const isSelected = selectedNodeId === node.id
16
- const maxWidth = node.settings.maxWidth ?? '1200px'
17
- const alignment = node.settings.alignment ?? 'center'
18
- const padding = node.settings.padding
19
-
20
- const marginMap: Record<string, string> = {
21
- left: '0 auto 0 0',
22
- center: '0 auto',
23
- right: '0 0 0 auto',
24
- }
25
-
26
- const handleClick = (e: React.MouseEvent) => {
27
- e.stopPropagation()
28
- onSelectNode(node.id)
29
- }
30
-
31
- return (
32
- <div
33
- data-node-id={node.id}
34
- className={`relative transition-shadow ${
35
- isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
36
- }`}
37
- style={{
38
- maxWidth,
39
- margin: marginMap[alignment] ?? '0 auto',
40
- padding,
41
- }}
42
- onClick={handleClick}
43
- onMouseEnter={(e) => {
44
- e.stopPropagation()
45
- setHovered(true)
46
- }}
47
- onMouseLeave={() => setHovered(false)}
48
- >
49
- {(hovered || isSelected) && (
50
- <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
51
- Container
52
- </span>
53
- )}
54
-
55
- <div className="flex flex-col gap-4">
56
- {node.children.map((row) => (
57
- <RowRenderer
58
- key={row.id}
59
- node={row}
60
- selectedNodeId={selectedNodeId}
61
- onSelectNode={onSelectNode}
62
- />
63
- ))}
64
- </div>
65
- </div>
66
- )
67
- }
@@ -1,68 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import type { RowNode } from '@prenta/core'
5
- import { ColumnRenderer } from './ColumnRenderer.js'
6
-
7
- export interface RowRendererProps {
8
- node: RowNode
9
- selectedNodeId: string | null
10
- onSelectNode: (id: string | null) => void
11
- }
12
-
13
- export function RowRenderer({ node, selectedNodeId, onSelectNode }: RowRendererProps) {
14
- const [hovered, setHovered] = useState(false)
15
- const isSelected = selectedNodeId === node.id
16
- const gap = node.settings.gap ?? '16px'
17
- const verticalAlign = node.settings.verticalAlign ?? 'stretch'
18
-
19
- const alignMap: Record<string, string> = {
20
- top: 'start',
21
- center: 'center',
22
- bottom: 'end',
23
- stretch: 'stretch',
24
- }
25
-
26
- const handleClick = (e: React.MouseEvent) => {
27
- e.stopPropagation()
28
- onSelectNode(node.id)
29
- }
30
-
31
- return (
32
- <div
33
- data-node-id={node.id}
34
- className={`relative transition-shadow ${
35
- isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
36
- }`}
37
- onClick={handleClick}
38
- onMouseEnter={(e) => {
39
- e.stopPropagation()
40
- setHovered(true)
41
- }}
42
- onMouseLeave={() => setHovered(false)}
43
- >
44
- {(hovered || isSelected) && (
45
- <span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
46
- Row
47
- </span>
48
- )}
49
-
50
- <div
51
- className="grid grid-cols-12"
52
- style={{
53
- gap,
54
- alignItems: alignMap[verticalAlign] ?? 'stretch',
55
- }}
56
- >
57
- {node.children.map((col) => (
58
- <ColumnRenderer
59
- key={col.id}
60
- node={col}
61
- selectedNodeId={selectedNodeId}
62
- onSelectNode={onSelectNode}
63
- />
64
- ))}
65
- </div>
66
- </div>
67
- )
68
- }