@prenta/admin 0.98.1 → 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 (267) hide show
  1. package/CHANGELOG.md +6 -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 -3
  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-editor-service-api.test.js +26 -23
  12. package/dist/__tests__/lib/page-editor-service-api.test.js.map +1 -1
  13. package/dist/__tests__/views/page-section-editor.test.js +0 -1
  14. package/dist/__tests__/views/page-section-editor.test.js.map +1 -1
  15. package/dist/__tests__/views/page-tab.render.test.js +0 -1
  16. package/dist/__tests__/views/page-tab.render.test.js.map +1 -1
  17. package/dist/index.d.ts +1 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/layout/Sidebar.d.ts +3 -4
  22. package/dist/layout/Sidebar.d.ts.map +1 -1
  23. package/dist/layout/Sidebar.js +7 -38
  24. package/dist/layout/Sidebar.js.map +1 -1
  25. package/dist/lib/page-editor-service.d.ts +0 -7
  26. package/dist/lib/page-editor-service.d.ts.map +1 -1
  27. package/dist/lib/page-editor-service.js +9 -9
  28. package/dist/lib/page-editor-service.js.map +1 -1
  29. package/dist/prenta-admin.css +1 -1
  30. package/dist/views/PageEditor.d.ts +2 -2
  31. package/dist/views/PageEditor.js +2 -2
  32. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  33. package/dist/views/page-editor/PageSectionEditor.js +9 -15
  34. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  35. package/package.json +4 -4
  36. package/src/AdminRoot.tsx +18 -68
  37. package/src/__tests__/components/seo-score-bands.test.ts +0 -3
  38. package/src/__tests__/layout/sidebar-posts.test.ts +6 -11
  39. package/src/__tests__/layout/sidebar-submenu.render.test.tsx +3 -2
  40. package/src/__tests__/lib/page-editor-service-api.test.ts +27 -25
  41. package/src/__tests__/views/page-section-editor.test.tsx +0 -1
  42. package/src/__tests__/views/page-tab.render.test.tsx +0 -1
  43. package/src/index.ts +1 -11
  44. package/src/layout/Sidebar.tsx +6 -41
  45. package/src/lib/page-editor-service.ts +9 -16
  46. package/src/views/PageEditor.tsx +2 -2
  47. package/src/views/page-editor/PageSectionEditor.tsx +8 -37
  48. package/dist/__tests__/views/page-builder-block-renderer.render.test.d.ts +0 -2
  49. package/dist/__tests__/views/page-builder-block-renderer.render.test.d.ts.map +0 -1
  50. package/dist/__tests__/views/page-builder-block-renderer.render.test.js +0 -48
  51. package/dist/__tests__/views/page-builder-block-renderer.render.test.js.map +0 -1
  52. package/dist/__tests__/views/page-builder-form-picker.render.test.d.ts +0 -2
  53. package/dist/__tests__/views/page-builder-form-picker.render.test.d.ts.map +0 -1
  54. package/dist/__tests__/views/page-builder-form-picker.render.test.js +0 -44
  55. package/dist/__tests__/views/page-builder-form-picker.render.test.js.map +0 -1
  56. package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts +0 -2
  57. package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts.map +0 -1
  58. package/dist/__tests__/views/page-builder-sections-panel.render.test.js +0 -121
  59. package/dist/__tests__/views/page-builder-sections-panel.render.test.js.map +0 -1
  60. package/dist/__tests__/views/page-builder-seo-panel.render.test.d.ts +0 -2
  61. package/dist/__tests__/views/page-builder-seo-panel.render.test.d.ts.map +0 -1
  62. package/dist/__tests__/views/page-builder-seo-panel.render.test.js +0 -65
  63. package/dist/__tests__/views/page-builder-seo-panel.render.test.js.map +0 -1
  64. package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts +0 -2
  65. package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts.map +0 -1
  66. package/dist/__tests__/views/page-builder-template-seed.render.test.js +0 -48
  67. package/dist/__tests__/views/page-builder-template-seed.render.test.js.map +0 -1
  68. package/dist/__tests__/views/page-templates.render.test.d.ts +0 -2
  69. package/dist/__tests__/views/page-templates.render.test.d.ts.map +0 -1
  70. package/dist/__tests__/views/page-templates.render.test.js +0 -126
  71. package/dist/__tests__/views/page-templates.render.test.js.map +0 -1
  72. package/dist/hooks/useBuilderState.d.ts +0 -49
  73. package/dist/hooks/useBuilderState.d.ts.map +0 -1
  74. package/dist/hooks/useBuilderState.js +0 -238
  75. package/dist/hooks/useBuilderState.js.map +0 -1
  76. package/dist/views/page-builder/AIBlockAssist.d.ts +0 -9
  77. package/dist/views/page-builder/AIBlockAssist.d.ts.map +0 -1
  78. package/dist/views/page-builder/AIBlockAssist.js +0 -40
  79. package/dist/views/page-builder/AIBlockAssist.js.map +0 -1
  80. package/dist/views/page-builder/AIGenerateDialog.d.ts +0 -8
  81. package/dist/views/page-builder/AIGenerateDialog.d.ts.map +0 -1
  82. package/dist/views/page-builder/AIGenerateDialog.js +0 -173
  83. package/dist/views/page-builder/AIGenerateDialog.js.map +0 -1
  84. package/dist/views/page-builder/BlockEditor.d.ts +0 -11
  85. package/dist/views/page-builder/BlockEditor.d.ts.map +0 -1
  86. package/dist/views/page-builder/BlockEditor.js +0 -159
  87. package/dist/views/page-builder/BlockEditor.js.map +0 -1
  88. package/dist/views/page-builder/BlockPicker.d.ts +0 -7
  89. package/dist/views/page-builder/BlockPicker.d.ts.map +0 -1
  90. package/dist/views/page-builder/BlockPicker.js +0 -103
  91. package/dist/views/page-builder/BlockPicker.js.map +0 -1
  92. package/dist/views/page-builder/BottomBar.d.ts +0 -9
  93. package/dist/views/page-builder/BottomBar.d.ts.map +0 -1
  94. package/dist/views/page-builder/BottomBar.js +0 -13
  95. package/dist/views/page-builder/BottomBar.js.map +0 -1
  96. package/dist/views/page-builder/BuilderSectionsPanel.d.ts +0 -20
  97. package/dist/views/page-builder/BuilderSectionsPanel.d.ts.map +0 -1
  98. package/dist/views/page-builder/BuilderSectionsPanel.js +0 -105
  99. package/dist/views/page-builder/BuilderSectionsPanel.js.map +0 -1
  100. package/dist/views/page-builder/BuilderToolbar.d.ts +0 -21
  101. package/dist/views/page-builder/BuilderToolbar.d.ts.map +0 -1
  102. package/dist/views/page-builder/BuilderToolbar.js +0 -18
  103. package/dist/views/page-builder/BuilderToolbar.js.map +0 -1
  104. package/dist/views/page-builder/ContextPanel.d.ts +0 -20
  105. package/dist/views/page-builder/ContextPanel.d.ts.map +0 -1
  106. package/dist/views/page-builder/ContextPanel.js +0 -43
  107. package/dist/views/page-builder/ContextPanel.js.map +0 -1
  108. package/dist/views/page-builder/DesignScore.d.ts +0 -6
  109. package/dist/views/page-builder/DesignScore.d.ts.map +0 -1
  110. package/dist/views/page-builder/DesignScore.js +0 -93
  111. package/dist/views/page-builder/DesignScore.js.map +0 -1
  112. package/dist/views/page-builder/NodeSettings.d.ts +0 -12
  113. package/dist/views/page-builder/NodeSettings.d.ts.map +0 -1
  114. package/dist/views/page-builder/NodeSettings.js +0 -80
  115. package/dist/views/page-builder/NodeSettings.js.map +0 -1
  116. package/dist/views/page-builder/PageBuilder.d.ts +0 -10
  117. package/dist/views/page-builder/PageBuilder.d.ts.map +0 -1
  118. package/dist/views/page-builder/PageBuilder.js +0 -222
  119. package/dist/views/page-builder/PageBuilder.js.map +0 -1
  120. package/dist/views/page-builder/PageSettings.d.ts +0 -7
  121. package/dist/views/page-builder/PageSettings.d.ts.map +0 -1
  122. package/dist/views/page-builder/PageSettings.js +0 -27
  123. package/dist/views/page-builder/PageSettings.js.map +0 -1
  124. package/dist/views/page-builder/PageTemplates.d.ts +0 -5
  125. package/dist/views/page-builder/PageTemplates.d.ts.map +0 -1
  126. package/dist/views/page-builder/PageTemplates.js +0 -146
  127. package/dist/views/page-builder/PageTemplates.js.map +0 -1
  128. package/dist/views/page-builder/RelationshipField.d.ts +0 -15
  129. package/dist/views/page-builder/RelationshipField.d.ts.map +0 -1
  130. package/dist/views/page-builder/RelationshipField.js +0 -65
  131. package/dist/views/page-builder/RelationshipField.js.map +0 -1
  132. package/dist/views/page-builder/SEOPanel.d.ts +0 -9
  133. package/dist/views/page-builder/SEOPanel.d.ts.map +0 -1
  134. package/dist/views/page-builder/SEOPanel.js +0 -38
  135. package/dist/views/page-builder/SEOPanel.js.map +0 -1
  136. package/dist/views/page-builder/SavedSections.d.ts +0 -6
  137. package/dist/views/page-builder/SavedSections.d.ts.map +0 -1
  138. package/dist/views/page-builder/SavedSections.js +0 -141
  139. package/dist/views/page-builder/SavedSections.js.map +0 -1
  140. package/dist/views/page-builder/TemplatePicker.d.ts +0 -7
  141. package/dist/views/page-builder/TemplatePicker.d.ts.map +0 -1
  142. package/dist/views/page-builder/TemplatePicker.js +0 -68
  143. package/dist/views/page-builder/TemplatePicker.js.map +0 -1
  144. package/dist/views/page-builder/Widgets.d.ts +0 -13
  145. package/dist/views/page-builder/Widgets.d.ts.map +0 -1
  146. package/dist/views/page-builder/Widgets.js +0 -15
  147. package/dist/views/page-builder/Widgets.js.map +0 -1
  148. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts +0 -3
  149. package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +0 -1
  150. package/dist/views/page-builder/block-renderers/CTAPreview.js +0 -19
  151. package/dist/views/page-builder/block-renderers/CTAPreview.js.map +0 -1
  152. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts +0 -3
  153. package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +0 -1
  154. package/dist/views/page-builder/block-renderers/CardsPreview.js +0 -22
  155. package/dist/views/page-builder/block-renderers/CardsPreview.js.map +0 -1
  156. package/dist/views/page-builder/block-renderers/CodePreview.d.ts +0 -3
  157. package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +0 -1
  158. package/dist/views/page-builder/block-renderers/CodePreview.js +0 -12
  159. package/dist/views/page-builder/block-renderers/CodePreview.js.map +0 -1
  160. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts +0 -3
  161. package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +0 -1
  162. package/dist/views/page-builder/block-renderers/FAQPreview.js +0 -27
  163. package/dist/views/page-builder/block-renderers/FAQPreview.js.map +0 -1
  164. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts +0 -6
  165. package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +0 -1
  166. package/dist/views/page-builder/block-renderers/FallbackPreview.js +0 -7
  167. package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +0 -1
  168. package/dist/views/page-builder/block-renderers/FormPreview.d.ts +0 -9
  169. package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +0 -1
  170. package/dist/views/page-builder/block-renderers/FormPreview.js +0 -52
  171. package/dist/views/page-builder/block-renderers/FormPreview.js.map +0 -1
  172. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts +0 -3
  173. package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +0 -1
  174. package/dist/views/page-builder/block-renderers/GalleryPreview.js +0 -19
  175. package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +0 -1
  176. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts +0 -3
  177. package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +0 -1
  178. package/dist/views/page-builder/block-renderers/HeroPreview.js +0 -19
  179. package/dist/views/page-builder/block-renderers/HeroPreview.js.map +0 -1
  180. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts +0 -3
  181. package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +0 -1
  182. package/dist/views/page-builder/block-renderers/ImagePreview.js +0 -17
  183. package/dist/views/page-builder/block-renderers/ImagePreview.js.map +0 -1
  184. package/dist/views/page-builder/block-renderers/TextPreview.d.ts +0 -3
  185. package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +0 -1
  186. package/dist/views/page-builder/block-renderers/TextPreview.js +0 -22
  187. package/dist/views/page-builder/block-renderers/TextPreview.js.map +0 -1
  188. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts +0 -3
  189. package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +0 -1
  190. package/dist/views/page-builder/block-renderers/VideoPreview.js +0 -18
  191. package/dist/views/page-builder/block-renderers/VideoPreview.js.map +0 -1
  192. package/dist/views/page-builder/block-renderers/index.d.ts +0 -9
  193. package/dist/views/page-builder/block-renderers/index.d.ts.map +0 -1
  194. package/dist/views/page-builder/block-renderers/index.js +0 -25
  195. package/dist/views/page-builder/block-renderers/index.js.map +0 -1
  196. package/dist/views/page-builder/canvas/BlockRenderer.d.ts +0 -8
  197. package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +0 -1
  198. package/dist/views/page-builder/canvas/BlockRenderer.js +0 -20
  199. package/dist/views/page-builder/canvas/BlockRenderer.js.map +0 -1
  200. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts +0 -10
  201. package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +0 -1
  202. package/dist/views/page-builder/canvas/BuilderCanvas.js +0 -26
  203. package/dist/views/page-builder/canvas/BuilderCanvas.js.map +0 -1
  204. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts +0 -8
  205. package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +0 -1
  206. package/dist/views/page-builder/canvas/ColumnRenderer.js +0 -32
  207. package/dist/views/page-builder/canvas/ColumnRenderer.js.map +0 -1
  208. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts +0 -8
  209. package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +0 -1
  210. package/dist/views/page-builder/canvas/ContainerRenderer.js +0 -29
  211. package/dist/views/page-builder/canvas/ContainerRenderer.js.map +0 -1
  212. package/dist/views/page-builder/canvas/RowRenderer.d.ts +0 -8
  213. package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +0 -1
  214. package/dist/views/page-builder/canvas/RowRenderer.js +0 -28
  215. package/dist/views/page-builder/canvas/RowRenderer.js.map +0 -1
  216. package/dist/views/page-builder/canvas/SectionRenderer.d.ts +0 -8
  217. package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +0 -1
  218. package/dist/views/page-builder/canvas/SectionRenderer.js +0 -50
  219. package/dist/views/page-builder/canvas/SectionRenderer.js.map +0 -1
  220. package/dist/views/page-builder/canvas/index.d.ts +0 -3
  221. package/dist/views/page-builder/canvas/index.d.ts.map +0 -1
  222. package/dist/views/page-builder/canvas/index.js +0 -2
  223. package/dist/views/page-builder/canvas/index.js.map +0 -1
  224. package/src/__tests__/views/page-builder-block-renderer.render.test.tsx +0 -66
  225. package/src/__tests__/views/page-builder-form-picker.render.test.tsx +0 -54
  226. package/src/__tests__/views/page-builder-sections-panel.render.test.tsx +0 -138
  227. package/src/__tests__/views/page-builder-seo-panel.render.test.tsx +0 -77
  228. package/src/__tests__/views/page-builder-template-seed.render.test.tsx +0 -59
  229. package/src/__tests__/views/page-templates.render.test.tsx +0 -182
  230. package/src/hooks/useBuilderState.ts +0 -361
  231. package/src/views/page-builder/AIBlockAssist.tsx +0 -64
  232. package/src/views/page-builder/AIGenerateDialog.tsx +0 -593
  233. package/src/views/page-builder/BlockEditor.tsx +0 -523
  234. package/src/views/page-builder/BlockPicker.tsx +0 -324
  235. package/src/views/page-builder/BottomBar.tsx +0 -65
  236. package/src/views/page-builder/BuilderSectionsPanel.tsx +0 -304
  237. package/src/views/page-builder/BuilderToolbar.tsx +0 -221
  238. package/src/views/page-builder/ContextPanel.tsx +0 -144
  239. package/src/views/page-builder/DesignScore.tsx +0 -251
  240. package/src/views/page-builder/NodeSettings.tsx +0 -500
  241. package/src/views/page-builder/PageBuilder.tsx +0 -405
  242. package/src/views/page-builder/PageSettings.tsx +0 -162
  243. package/src/views/page-builder/PageTemplates.tsx +0 -435
  244. package/src/views/page-builder/RelationshipField.tsx +0 -113
  245. package/src/views/page-builder/SEOPanel.tsx +0 -222
  246. package/src/views/page-builder/SavedSections.tsx +0 -480
  247. package/src/views/page-builder/TemplatePicker.tsx +0 -197
  248. package/src/views/page-builder/Widgets.tsx +0 -44
  249. package/src/views/page-builder/block-renderers/CTAPreview.tsx +0 -79
  250. package/src/views/page-builder/block-renderers/CardsPreview.tsx +0 -69
  251. package/src/views/page-builder/block-renderers/CodePreview.tsx +0 -46
  252. package/src/views/page-builder/block-renderers/FAQPreview.tsx +0 -87
  253. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +0 -18
  254. package/src/views/page-builder/block-renderers/FormPreview.tsx +0 -117
  255. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +0 -87
  256. package/src/views/page-builder/block-renderers/HeroPreview.tsx +0 -90
  257. package/src/views/page-builder/block-renderers/ImagePreview.tsx +0 -54
  258. package/src/views/page-builder/block-renderers/TextPreview.tsx +0 -81
  259. package/src/views/page-builder/block-renderers/VideoPreview.tsx +0 -73
  260. package/src/views/page-builder/block-renderers/index.ts +0 -34
  261. package/src/views/page-builder/canvas/BlockRenderer.tsx +0 -56
  262. package/src/views/page-builder/canvas/BuilderCanvas.tsx +0 -87
  263. package/src/views/page-builder/canvas/ColumnRenderer.tsx +0 -82
  264. package/src/views/page-builder/canvas/ContainerRenderer.tsx +0 -67
  265. package/src/views/page-builder/canvas/RowRenderer.tsx +0 -68
  266. package/src/views/page-builder/canvas/SectionRenderer.tsx +0 -93
  267. package/src/views/page-builder/canvas/index.ts +0 -2
@@ -1,361 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, useCallback, useRef, useMemo } from 'react'
4
- import type { PageNode, BuilderNode, BlockNode, SectionNode, ColumnNode } from '@prenta/core'
5
- import {
6
- addNode,
7
- removeNode,
8
- moveNode,
9
- updateNodeSettings,
10
- updateBlockData,
11
- findNode,
12
- findParent,
13
- createEmptyPage,
14
- createSection,
15
- createContainer,
16
- createRow,
17
- createColumn,
18
- createBlock,
19
- hasChildren,
20
- } from '@prenta/core/page-builder'
21
-
22
- export type DeviceMode = 'desktop' | 'tablet' | 'mobile'
23
- export type PanelTab = 'block' | 'node' | 'page' | 'seo' | 'design'
24
-
25
- export interface PageSettings {
26
- title: string
27
- slug: string
28
- template?: string
29
- metaTitle?: string
30
- metaDescription?: string
31
- ogImage?: string
32
- focusKeyphrase?: string
33
- schemaType?: string
34
- }
35
-
36
- export interface BuilderState {
37
- tree: PageNode
38
- selectedNodeId: string | null
39
- selectedNode: BuilderNode | null
40
- deviceMode: DeviceMode
41
- activeTab: PanelTab
42
- pageSettings: PageSettings
43
- dirty: boolean
44
- canUndo: boolean
45
- canRedo: boolean
46
- showGridOverlay: boolean
47
- }
48
-
49
- export interface BuilderActions {
50
- selectNode: (id: string | null) => void
51
- setDeviceMode: (mode: DeviceMode) => void
52
- setActiveTab: (tab: PanelTab) => void
53
- setPageSettings: (settings: Partial<PageSettings>) => void
54
- setShowGridOverlay: (show: boolean) => void
55
-
56
- addSection: () => void
57
- addRowToSection: (sectionId: string) => void
58
- addBlockToColumn: (columnId: string, blockType: string, variant?: string) => void
59
- addNodeAtId: (parentId: string, node: BuilderNode, index?: number) => void
60
- removeNodeById: (id: string) => void
61
- moveNodeById: (id: string, newParentId: string, index?: number) => void
62
- updateSettings: (id: string, settings: Record<string, unknown>) => void
63
- updateBlock: (id: string, data: Record<string, unknown>) => void
64
- duplicateNode: (id: string) => void
65
- moveNodeUp: (id: string) => void
66
- moveNodeDown: (id: string) => void
67
-
68
- undo: () => void
69
- redo: () => void
70
- markClean: () => void
71
- replaceTree: (tree: PageNode) => void
72
- }
73
-
74
- const MAX_HISTORY = 50
75
-
76
- function deepClone<T>(obj: T): T {
77
- return JSON.parse(JSON.stringify(obj))
78
- }
79
-
80
- function regenerateIds(node: BuilderNode): BuilderNode {
81
- const cloned = deepClone(node)
82
- let counter = 0
83
- function walk(n: any) {
84
- n.id = `node_${Date.now().toString(36)}_${(counter++).toString(36)}_${Math.random().toString(36).slice(2, 8)}`
85
- if (Array.isArray(n.children)) {
86
- for (const child of n.children) walk(child)
87
- }
88
- }
89
- walk(cloned)
90
- return cloned
91
- }
92
-
93
- export function useBuilderState(
94
- initialTree?: PageNode,
95
- initialPageSettings?: Partial<PageSettings>,
96
- ): BuilderState & BuilderActions {
97
- const [tree, setTree] = useState<PageNode>(() => initialTree ?? createEmptyPage())
98
- const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null)
99
- const [deviceMode, setDeviceMode] = useState<DeviceMode>('desktop')
100
- const [activeTab, setActiveTab] = useState<PanelTab>('page')
101
- const [showGridOverlay, setShowGridOverlay] = useState(false)
102
- const [pageSettings, setPageSettingsState] = useState<PageSettings>({
103
- title: '',
104
- slug: '',
105
- ...initialPageSettings,
106
- })
107
- const [dirty, setDirty] = useState(false)
108
-
109
- const undoStack = useRef<PageNode[]>([])
110
- const redoStack = useRef<PageNode[]>([])
111
-
112
- const pushHistory = useCallback((currentTree: PageNode) => {
113
- undoStack.current = [...undoStack.current.slice(-MAX_HISTORY + 1), currentTree]
114
- redoStack.current = []
115
- }, [])
116
-
117
- const [canUndo, setCanUndo] = useState(false)
118
- const [canRedo, setCanRedo] = useState(false)
119
-
120
- const applyTreeChange = useCallback(
121
- (fn: (prev: PageNode) => PageNode) => {
122
- setTree((prev) => {
123
- pushHistory(prev)
124
- const next = fn(prev)
125
- setDirty(true)
126
- setCanUndo(true)
127
- setCanRedo(false)
128
- return next
129
- })
130
- },
131
- [pushHistory],
132
- )
133
-
134
- const selectedNode = useMemo(() => {
135
- if (!selectedNodeId) return null
136
- return findNode(tree, selectedNodeId) ?? null
137
- }, [tree, selectedNodeId])
138
-
139
- const selectNode = useCallback(
140
- (id: string | null) => {
141
- setSelectedNodeId(id)
142
- if (id) {
143
- const node = findNode(tree, id)
144
- if (node) {
145
- if (node.type === 'block') setActiveTab('block')
146
- else if (node.type === 'page') setActiveTab('page')
147
- else setActiveTab('node')
148
- }
149
- }
150
- },
151
- [tree],
152
- )
153
-
154
- const setPageSettings = useCallback((settings: Partial<PageSettings>) => {
155
- setPageSettingsState((prev) => ({ ...prev, ...settings }))
156
- setDirty(true)
157
- }, [])
158
-
159
- const addSection = useCallback(() => {
160
- applyTreeChange((prev) => {
161
- const section = createSection({ paddingTop: '64px', paddingBottom: '64px' })
162
- const container = createContainer()
163
- const col = createColumn(12)
164
- const row = createRow([col])
165
- ;(container as any).children = [row]
166
- ;(section as any).children = [container]
167
- return addNode(prev, prev.id, section as BuilderNode)
168
- })
169
- }, [applyTreeChange])
170
-
171
- const addRowToSection = useCallback(
172
- (sectionId: string) => {
173
- applyTreeChange((prev) => {
174
- const section = findNode(prev, sectionId)
175
- if (!section || !hasChildren(section)) return prev
176
- const containers = (section as SectionNode).children.filter((c) => c.type === 'container')
177
- const targetId = containers.length > 0 ? containers[containers.length - 1]!.id : sectionId
178
- const col = createColumn(12)
179
- const row = createRow([col])
180
- return addNode(prev, targetId, row as BuilderNode)
181
- })
182
- },
183
- [applyTreeChange],
184
- )
185
-
186
- const addBlockToColumn = useCallback(
187
- (columnId: string, blockType: string, variant?: string) => {
188
- applyTreeChange((prev) => {
189
- const block = createBlock(blockType, variant)
190
- return addNode(prev, columnId, block as BuilderNode)
191
- })
192
- },
193
- [applyTreeChange],
194
- )
195
-
196
- const addNodeAtId = useCallback(
197
- (parentId: string, node: BuilderNode, index?: number) => {
198
- applyTreeChange((prev) => addNode(prev, parentId, node, index))
199
- },
200
- [applyTreeChange],
201
- )
202
-
203
- const removeNodeById = useCallback(
204
- (id: string) => {
205
- applyTreeChange((prev) => {
206
- const result = removeNode(prev, id)
207
- if (selectedNodeId === id) setSelectedNodeId(null)
208
- return result
209
- })
210
- },
211
- [applyTreeChange, selectedNodeId],
212
- )
213
-
214
- const moveNodeById = useCallback(
215
- (id: string, newParentId: string, index?: number) => {
216
- applyTreeChange((prev) => moveNode(prev, id, newParentId, index))
217
- },
218
- [applyTreeChange],
219
- )
220
-
221
- const updateSettings = useCallback(
222
- (id: string, settings: Record<string, unknown>) => {
223
- applyTreeChange((prev) => updateNodeSettings(prev, id, settings))
224
- },
225
- [applyTreeChange],
226
- )
227
-
228
- const updateBlock = useCallback(
229
- (id: string, data: Record<string, unknown>) => {
230
- applyTreeChange((prev) => updateBlockData(prev, id, data))
231
- },
232
- [applyTreeChange],
233
- )
234
-
235
- const duplicateNode = useCallback(
236
- (id: string) => {
237
- applyTreeChange((prev) => {
238
- const node = findNode(prev, id)
239
- if (!node) return prev
240
- const parent = findParent(prev, id)
241
- if (!parent) return prev
242
- const siblings = (parent as any).children as BuilderNode[]
243
- const idx = siblings.findIndex((c) => c.id === id)
244
- const cloned = regenerateIds(node)
245
- return addNode(prev, parent.id, cloned, idx + 1)
246
- })
247
- },
248
- [applyTreeChange],
249
- )
250
-
251
- const moveNodeUp = useCallback(
252
- (id: string) => {
253
- applyTreeChange((prev) => {
254
- const parent = findParent(prev, id)
255
- if (!parent) return prev
256
- const siblings = (parent as any).children as BuilderNode[]
257
- const idx = siblings.findIndex((c) => c.id === id)
258
- if (idx <= 0) return prev
259
- const withoutNode = removeNode(prev, id)
260
- const node = findNode(prev, id)
261
- if (!node) return prev
262
- return addNode(withoutNode, parent.id, deepClone(node), idx - 1)
263
- })
264
- },
265
- [applyTreeChange],
266
- )
267
-
268
- const moveNodeDown = useCallback(
269
- (id: string) => {
270
- applyTreeChange((prev) => {
271
- const parent = findParent(prev, id)
272
- if (!parent) return prev
273
- const siblings = (parent as any).children as BuilderNode[]
274
- const idx = siblings.findIndex((c) => c.id === id)
275
- if (idx >= siblings.length - 1) return prev
276
- const withoutNode = removeNode(prev, id)
277
- const node = findNode(prev, id)
278
- if (!node) return prev
279
- return addNode(withoutNode, parent.id, deepClone(node), idx + 1)
280
- })
281
- },
282
- [applyTreeChange],
283
- )
284
-
285
- const undo = useCallback(() => {
286
- if (undoStack.current.length === 0) return
287
- const prev = undoStack.current[undoStack.current.length - 1]!
288
- undoStack.current = undoStack.current.slice(0, -1)
289
- setTree((current) => {
290
- redoStack.current = [...redoStack.current, current]
291
- setCanUndo(undoStack.current.length > 0)
292
- setCanRedo(true)
293
- return prev
294
- })
295
- }, [])
296
-
297
- const redo = useCallback(() => {
298
- if (redoStack.current.length === 0) return
299
- const next = redoStack.current[redoStack.current.length - 1]!
300
- redoStack.current = redoStack.current.slice(0, -1)
301
- setTree((current) => {
302
- undoStack.current = [...undoStack.current, current]
303
- setCanRedo(redoStack.current.length > 0)
304
- setCanUndo(true)
305
- return next
306
- })
307
- }, [])
308
-
309
- const markClean = useCallback(() => {
310
- setDirty(false)
311
- }, [])
312
-
313
- const replaceTree = useCallback(
314
- (newTree: PageNode) => {
315
- setTree((prev) => {
316
- pushHistory(prev)
317
- setDirty(true)
318
- setCanUndo(true)
319
- setCanRedo(false)
320
- return newTree
321
- })
322
- },
323
- [pushHistory],
324
- )
325
-
326
- return {
327
- tree,
328
- selectedNodeId,
329
- selectedNode,
330
- deviceMode,
331
- activeTab,
332
- pageSettings,
333
- dirty,
334
- canUndo,
335
- canRedo,
336
- showGridOverlay,
337
-
338
- selectNode,
339
- setDeviceMode,
340
- setActiveTab,
341
- setPageSettings,
342
- setShowGridOverlay,
343
-
344
- addSection,
345
- addRowToSection,
346
- addBlockToColumn,
347
- addNodeAtId,
348
- removeNodeById,
349
- moveNodeById,
350
- updateSettings,
351
- updateBlock,
352
- duplicateNode,
353
- moveNodeUp,
354
- moveNodeDown,
355
-
356
- undo,
357
- redo,
358
- markClean,
359
- replaceTree,
360
- }
361
- }
@@ -1,64 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, useCallback } from 'react'
4
- import { Sparkles, Loader2 } from 'lucide-react'
5
- import { toast } from 'sonner'
6
- import { cmsApi } from '../../lib/api.js'
7
- import type { BlockNode } from '@prenta/core'
8
-
9
- export interface AIBlockAssistProps {
10
- block: BlockNode
11
- pageTitle?: string
12
- businessName?: string
13
- onUpdateData: (data: Record<string, unknown>) => void
14
- }
15
-
16
- export function AIBlockAssist({
17
- block,
18
- pageTitle,
19
- businessName,
20
- onUpdateData,
21
- }: AIBlockAssistProps) {
22
- const [generating, setGenerating] = useState(false)
23
-
24
- const handleGenerate = useCallback(async () => {
25
- setGenerating(true)
26
-
27
- try {
28
- const res = await cmsApi<Record<string, unknown>>('/page-builder/generate-block', {
29
- method: 'POST',
30
- body: JSON.stringify({
31
- blockType: block.settings.blockType,
32
- variant: block.settings.variant,
33
- pageContext: {
34
- pageTitle,
35
- businessName,
36
- },
37
- }),
38
- })
39
-
40
- if (res.error) {
41
- toast.error(res.error)
42
- } else if (res.data) {
43
- onUpdateData(res.data)
44
- toast.success('Content generated')
45
- }
46
- } catch {
47
- toast.error('Failed to generate content')
48
- } finally {
49
- setGenerating(false)
50
- }
51
- }, [block, pageTitle, businessName, onUpdateData])
52
-
53
- return (
54
- <button
55
- onClick={handleGenerate}
56
- disabled={generating}
57
- className="text-primary hover:bg-primary/10 flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors disabled:opacity-50"
58
- title="Generate content with AI"
59
- >
60
- {generating ? <Loader2 size={12} className="animate-spin" /> : <Sparkles size={12} />}
61
- {generating ? 'Generating...' : 'AI Fill'}
62
- </button>
63
- )
64
- }