@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 +0,0 @@
1
- {"version":3,"file":"ContainerRenderer.js","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/ContainerRenderer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAQ9C,MAAM,UAAU,iBAAiB,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAA0B;IAC9F,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,UAAU,GAAG,cAAc,KAAK,IAAI,CAAC,EAAE,CAAA;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAA;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAA;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAA;IAErC,MAAM,SAAS,GAA2B;QACxC,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,YAAY;KACpB,CAAA;IAED,MAAM,WAAW,GAAG,CAAC,CAAmB,EAAE,EAAE;QAC1C,CAAC,CAAC,eAAe,EAAE,CAAA;QACnB,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvB,CAAC,CAAA;IAED,OAAO,CACL,+BACgB,IAAI,CAAC,EAAE,EACrB,SAAS,EAAE,8BACT,UAAU,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAC1F,EAAE,EACF,KAAK,EAAE;YACL,QAAQ;YACR,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,IAAI,QAAQ;YACxC,OAAO;SACR,EACD,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;YAClB,CAAC,CAAC,eAAe,EAAE,CAAA;YACnB,UAAU,CAAC,IAAI,CAAC,CAAA;QAClB,CAAC,EACD,YAAY,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,aAEpC,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,CAC1B,eAAM,SAAS,EAAC,2GAA2G,0BAEpH,CACR,EAED,cAAK,SAAS,EAAC,qBAAqB,YACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC1B,KAAC,WAAW,IAEV,IAAI,EAAE,GAAG,EACT,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,YAAY,IAHrB,GAAG,CAAC,EAAE,CAIX,CACH,CAAC,GACE,IACF,CACP,CAAA;AACH,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { RowNode } from '@prenta/core';
2
- export interface RowRendererProps {
3
- node: RowNode;
4
- selectedNodeId: string | null;
5
- onSelectNode: (id: string | null) => void;
6
- }
7
- export declare function RowRenderer({ node, selectedNodeId, onSelectNode }: RowRendererProps): import("react/jsx-runtime").JSX.Element;
8
- //# sourceMappingURL=RowRenderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RowRenderer.d.ts","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/RowRenderer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAA;IACb,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CAC1C;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,gBAAgB,2CAuDnF"}
@@ -1,28 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
- import { ColumnRenderer } from './ColumnRenderer.js';
5
- export function RowRenderer({ node, selectedNodeId, onSelectNode }) {
6
- const [hovered, setHovered] = useState(false);
7
- const isSelected = selectedNodeId === node.id;
8
- const gap = node.settings.gap ?? '16px';
9
- const verticalAlign = node.settings.verticalAlign ?? 'stretch';
10
- const alignMap = {
11
- top: 'start',
12
- center: 'center',
13
- bottom: 'end',
14
- stretch: 'stretch',
15
- };
16
- const handleClick = (e) => {
17
- e.stopPropagation();
18
- onSelectNode(node.id);
19
- };
20
- return (_jsxs("div", { "data-node-id": node.id, className: `relative transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, onClick: handleClick, onMouseEnter: (e) => {
21
- e.stopPropagation();
22
- setHovered(true);
23
- }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("span", { className: "bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium", children: "Row" })), _jsx("div", { className: "grid grid-cols-12", style: {
24
- gap,
25
- alignItems: alignMap[verticalAlign] ?? 'stretch',
26
- }, children: node.children.map((col) => (_jsx(ColumnRenderer, { node: col, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, col.id))) })] }));
27
- }
28
- //# sourceMappingURL=RowRenderer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RowRenderer.js","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/RowRenderer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAQpD,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAoB;IAClF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,UAAU,GAAG,cAAc,KAAK,IAAI,CAAC,EAAE,CAAA;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,MAAM,CAAA;IACvC,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,IAAI,SAAS,CAAA;IAE9D,MAAM,QAAQ,GAA2B;QACvC,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,SAAS;KACnB,CAAA;IAED,MAAM,WAAW,GAAG,CAAC,CAAmB,EAAE,EAAE;QAC1C,CAAC,CAAC,eAAe,EAAE,CAAA;QACnB,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvB,CAAC,CAAA;IAED,OAAO,CACL,+BACgB,IAAI,CAAC,EAAE,EACrB,SAAS,EAAE,8BACT,UAAU,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAC1F,EAAE,EACF,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;YAClB,CAAC,CAAC,eAAe,EAAE,CAAA;YACnB,UAAU,CAAC,IAAI,CAAC,CAAA;QAClB,CAAC,EACD,YAAY,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,aAEpC,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,CAC1B,eAAM,SAAS,EAAC,2GAA2G,oBAEpH,CACR,EAED,cACE,SAAS,EAAC,mBAAmB,EAC7B,KAAK,EAAE;oBACL,GAAG;oBACH,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,SAAS;iBACjD,YAEA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC1B,KAAC,cAAc,IAEb,IAAI,EAAE,GAAG,EACT,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,YAAY,IAHrB,GAAG,CAAC,EAAE,CAIX,CACH,CAAC,GACE,IACF,CACP,CAAA;AACH,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { SectionNode } from '@prenta/core';
2
- export interface SectionRendererProps {
3
- node: SectionNode;
4
- selectedNodeId: string | null;
5
- onSelectNode: (id: string | null) => void;
6
- }
7
- export declare function SectionRenderer({ node, selectedNodeId, onSelectNode }: SectionRendererProps): import("react/jsx-runtime").JSX.Element;
8
- //# sourceMappingURL=SectionRenderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SectionRenderer.d.ts","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/SectionRenderer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAI/C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,CAAA;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CAC1C;AAED,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CA+E3F"}
@@ -1,50 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
- import { ContainerRenderer } from './ContainerRenderer.js';
5
- import { RowRenderer } from './RowRenderer.js';
6
- export function SectionRenderer({ node, selectedNodeId, onSelectNode }) {
7
- const [hovered, setHovered] = useState(false);
8
- const isSelected = selectedNodeId === node.id;
9
- const handleClick = (e) => {
10
- e.stopPropagation();
11
- onSelectNode(node.id);
12
- };
13
- const backgroundStyle = {};
14
- if (node.settings.background) {
15
- backgroundStyle.backgroundColor = node.settings.background;
16
- }
17
- if (node.settings.backgroundImage) {
18
- backgroundStyle.backgroundImage = `url(${node.settings.backgroundImage})`;
19
- backgroundStyle.backgroundSize = 'cover';
20
- backgroundStyle.backgroundPosition = 'center';
21
- }
22
- if (node.settings.backgroundGradient) {
23
- backgroundStyle.backgroundImage = node.settings.backgroundGradient;
24
- }
25
- if (node.settings.paddingTop) {
26
- backgroundStyle.paddingTop = node.settings.paddingTop;
27
- }
28
- if (node.settings.paddingBottom) {
29
- backgroundStyle.paddingBottom = node.settings.paddingBottom;
30
- }
31
- if (node.settings.marginTop) {
32
- backgroundStyle.marginTop = node.settings.marginTop;
33
- }
34
- if (node.settings.marginBottom) {
35
- backgroundStyle.marginBottom = node.settings.marginBottom;
36
- }
37
- return (_jsxs("div", { "data-node-id": node.id, className: `relative w-full transition-shadow ${isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''}`, style: backgroundStyle, onClick: handleClick, onMouseEnter: (e) => {
38
- e.stopPropagation();
39
- setHovered(true);
40
- }, onMouseLeave: () => setHovered(false), children: [(hovered || isSelected) && (_jsx("span", { className: "bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium", children: "Section" })), node.children.map((child) => {
41
- if (child.type === 'container') {
42
- return (_jsx(ContainerRenderer, { node: child, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, child.id));
43
- }
44
- if (child.type === 'row') {
45
- return (_jsx(RowRenderer, { node: child, selectedNodeId: selectedNodeId, onSelectNode: onSelectNode }, child.id));
46
- }
47
- return null;
48
- })] }));
49
- }
50
- //# sourceMappingURL=SectionRenderer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SectionRenderer.js","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/SectionRenderer.tsx"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- export { BuilderCanvas } from './BuilderCanvas.js';
2
- export type { BuilderCanvasProps } from './BuilderCanvas.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,2 +0,0 @@
1
- export { BuilderCanvas } from './BuilderCanvas.js';
2
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/views/page-builder/canvas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,66 +0,0 @@
1
- // @vitest-environment happy-dom
2
- import { beforeEach, describe, expect, it, vi } from 'vitest'
3
- import { fireEvent, render, screen, waitFor } from '@testing-library/react'
4
- import type { BlockNode } from '@prenta/core'
5
-
6
- const cmsApi = vi.fn()
7
- vi.mock('../../lib/api.js', () => ({ cmsApi: (...args: unknown[]) => cmsApi(...args) }))
8
-
9
- const { BlockRenderer } = await import('../../views/page-builder/canvas/BlockRenderer.js')
10
-
11
- function formNode(over: Partial<BlockNode> = {}): BlockNode {
12
- return {
13
- id: 'node-1',
14
- type: 'block',
15
- settings: { blockType: 'form', variant: 'contact' },
16
- data: { formId: 'f1' },
17
- ...over,
18
- } as BlockNode
19
- }
20
-
21
- beforeEach(() => {
22
- cmsApi.mockReset()
23
- cmsApi.mockResolvedValue({
24
- data: {
25
- name: 'Contact Us',
26
- fields: [
27
- { key: 'name', label: 'Full Name', type: 'text' },
28
- { key: 'message', label: 'Message', type: 'textarea' },
29
- ],
30
- },
31
- status: 200,
32
- })
33
- })
34
-
35
- describe('canvas BlockRenderer', () => {
36
- it('renders the live form preview with the linked form name and fields', async () => {
37
- render(<BlockRenderer node={formNode()} selectedNodeId={null} onSelectNode={vi.fn()} />)
38
- await waitFor(() => expect(screen.getByText('Contact Us')).toBeTruthy())
39
- expect(cmsApi).toHaveBeenCalledWith('/forms/f1')
40
- expect(screen.getByText('Full Name')).toBeTruthy()
41
- })
42
-
43
- it('selects the node on click', () => {
44
- const onSelectNode = vi.fn()
45
- const { container } = render(
46
- <BlockRenderer
47
- node={formNode({ data: {} })}
48
- selectedNodeId={null}
49
- onSelectNode={onSelectNode}
50
- />,
51
- )
52
- fireEvent.click(container.querySelector('[data-node-id="node-1"]')!)
53
- expect(onSelectNode).toHaveBeenCalledWith('node-1')
54
- })
55
-
56
- it('falls back to a placeholder for unknown block types', () => {
57
- render(
58
- <BlockRenderer
59
- node={formNode({ settings: { blockType: 'widget' }, data: {} })}
60
- selectedNodeId={null}
61
- onSelectNode={vi.fn()}
62
- />,
63
- )
64
- expect(screen.getByText('No preview available')).toBeTruthy()
65
- })
66
- })
@@ -1,54 +0,0 @@
1
- // @vitest-environment happy-dom
2
- import { beforeEach, describe, expect, it, vi } from 'vitest'
3
- import { fireEvent, render, screen, waitFor } from '@testing-library/react'
4
- import type { FieldDefinition } from '@prenta/core'
5
-
6
- const cmsApi = vi.fn()
7
- vi.mock('../../lib/api.js', () => ({ cmsApi: (...args: unknown[]) => cmsApi(...args) }))
8
-
9
- const { RelationshipField } = await import('../../views/page-builder/RelationshipField.js')
10
-
11
- const formField: FieldDefinition = {
12
- type: 'relationship',
13
- label: 'Form',
14
- relationTo: 'forms',
15
- } as FieldDefinition
16
-
17
- beforeEach(() => {
18
- cmsApi.mockReset()
19
- })
20
-
21
- describe('RelationshipField (form block picker)', () => {
22
- it('loads forms and lets the editor pick one by id', async () => {
23
- cmsApi.mockResolvedValue({
24
- data: [
25
- { id: 'f1', name: 'Contact Us', slug: 'contact-us' },
26
- { id: 'f2', name: 'Event RSVP', slug: 'event-rsvp' },
27
- ],
28
- status: 200,
29
- })
30
- const onChange = vi.fn()
31
- render(<RelationshipField definition={formField} value="" onChange={onChange} label="Form" />)
32
-
33
- await waitFor(() => expect(screen.getByText('Contact Us')).toBeTruthy())
34
- expect(cmsApi).toHaveBeenCalledWith('/forms')
35
- expect(screen.getByText('Event RSVP')).toBeTruthy()
36
-
37
- fireEvent.change(screen.getByLabelText('Form'), { target: { value: 'f2' } })
38
- expect(onChange).toHaveBeenCalledWith('f2')
39
- })
40
-
41
- it('shows an empty hint when the collection has no items', async () => {
42
- cmsApi.mockResolvedValue({ data: [], status: 200 })
43
- render(<RelationshipField definition={formField} value="" onChange={vi.fn()} label="Form" />)
44
- await waitFor(() => expect(screen.getByText('No forms found.')).toBeTruthy())
45
- })
46
-
47
- it('degrades to a plain id input when the collection cannot be loaded', async () => {
48
- cmsApi.mockResolvedValue({ error: 'boom', status: 500 })
49
- render(<RelationshipField definition={formField} value="f9" onChange={vi.fn()} label="Form" />)
50
- await waitFor(() =>
51
- expect((screen.getByPlaceholderText('Enter forms id…') as HTMLInputElement).value).toBe('f9'),
52
- )
53
- })
54
- })
@@ -1,138 +0,0 @@
1
- // @vitest-environment happy-dom
2
- import { beforeEach, describe, expect, it, vi } from 'vitest'
3
- import { fireEvent, render, screen } from '@testing-library/react'
4
- import type { PageNode } from '@prenta/core'
5
-
6
- const { BuilderSectionsPanel } = await import('../../views/page-builder/BuilderSectionsPanel.js')
7
-
8
- /** Minimal builder tree: a hero section plus an empty, hidden section. */
9
- function makeTree(): PageNode {
10
- return {
11
- id: 'page1',
12
- type: 'page',
13
- children: [
14
- {
15
- id: 'sec1',
16
- type: 'section',
17
- settings: {},
18
- children: [
19
- {
20
- id: 'cont1',
21
- type: 'container',
22
- settings: {},
23
- children: [
24
- {
25
- id: 'row1',
26
- type: 'row',
27
- settings: {},
28
- children: [
29
- {
30
- id: 'col1',
31
- type: 'column',
32
- settings: { width: 12 },
33
- children: [
34
- {
35
- id: 'blk1',
36
- type: 'block',
37
- settings: { blockType: 'hero', variant: 'centered' },
38
- data: {},
39
- },
40
- ],
41
- },
42
- ],
43
- },
44
- ],
45
- },
46
- ],
47
- },
48
- { id: 'sec2', type: 'section', settings: { visibility: 'hidden' }, children: [] },
49
- ],
50
- }
51
- }
52
-
53
- function renderPanel(over: Partial<Parameters<typeof BuilderSectionsPanel>[0]> = {}) {
54
- const props = {
55
- tree: makeTree(),
56
- selectedNodeId: null,
57
- collapsed: false,
58
- onToggleCollapsed: vi.fn(),
59
- onSelect: vi.fn(),
60
- onReorder: vi.fn(),
61
- onAddSection: vi.fn(),
62
- ...over,
63
- }
64
- render(<BuilderSectionsPanel {...props} />)
65
- return props
66
- }
67
-
68
- beforeEach(() => {
69
- vi.clearAllMocks()
70
- })
71
-
72
- describe('BuilderSectionsPanel', () => {
73
- it('lists the page sections in order with derived names and block counts', () => {
74
- renderPanel()
75
-
76
- // First section is named after its first block's catalog label.
77
- expect(screen.getByText('Hero')).toBeTruthy()
78
- expect(screen.getByText('1 block')).toBeTruthy()
79
- // Empty section falls back to a positional name.
80
- expect(screen.getByText('Section 2')).toBeTruthy()
81
- expect(screen.getByText('Empty section')).toBeTruthy()
82
- // Count chip in the header.
83
- expect(screen.getByText('2')).toBeTruthy()
84
- // Panel is an accessible nav landmark.
85
- expect(screen.getByRole('navigation', { name: 'Page sections' })).toBeTruthy()
86
- })
87
-
88
- it('fires the selection callback when a section row is clicked', () => {
89
- const props = renderPanel()
90
-
91
- // `/^Hero/` excludes the drag handle ("Drag to reorder Hero").
92
- fireEvent.click(screen.getByRole('button', { name: /^Hero/ }))
93
- expect(props.onSelect).toHaveBeenCalledWith('sec1')
94
- })
95
-
96
- it('marks the selected section with aria-current', () => {
97
- renderPanel({ selectedNodeId: 'sec1' })
98
-
99
- const row = screen.getByRole('button', { name: /^Hero/ })
100
- expect(row.getAttribute('aria-current')).toBe('true')
101
- })
102
-
103
- it('exposes keyboard-accessible drag handles per section', () => {
104
- renderPanel()
105
- expect(screen.getByRole('button', { name: 'Drag to reorder Hero' })).toBeTruthy()
106
- expect(screen.getByRole('button', { name: 'Drag to reorder Section 2' })).toBeTruthy()
107
- })
108
-
109
- it('fires the add-section callback from the bottom affordance', () => {
110
- const props = renderPanel()
111
-
112
- fireEvent.click(screen.getByRole('button', { name: 'Add Section' }))
113
- expect(props.onAddSection).toHaveBeenCalledTimes(1)
114
- })
115
-
116
- it('collapses to a rail with an expand toggle', () => {
117
- const props = renderPanel({ collapsed: true })
118
-
119
- // Section rows are gone; only the expand affordance remains.
120
- expect(screen.queryByText('Hero')).toBeNull()
121
- const toggle = screen.getByRole('button', { name: 'Expand sections panel' })
122
- expect(toggle.getAttribute('aria-expanded')).toBe('false')
123
-
124
- fireEvent.click(toggle)
125
- expect(props.onToggleCollapsed).toHaveBeenCalledTimes(1)
126
- })
127
-
128
- it('shows a collapse toggle with aria-expanded when open', () => {
129
- renderPanel()
130
- const toggle = screen.getByRole('button', { name: 'Collapse sections panel' })
131
- expect(toggle.getAttribute('aria-expanded')).toBe('true')
132
- })
133
-
134
- it('shows an empty message when the page has no sections', () => {
135
- renderPanel({ tree: { id: 'page1', type: 'page', children: [] } })
136
- expect(screen.getByText(/No sections yet/)).toBeTruthy()
137
- })
138
- })
@@ -1,59 +0,0 @@
1
- // @vitest-environment happy-dom
2
- import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest'
3
- import { cleanup, render, screen, waitFor } from '@testing-library/react'
4
-
5
- const cmsApi = vi.fn()
6
- vi.mock('../../lib/api.js', () => ({ cmsApi: (...args: unknown[]) => cmsApi(...args) }))
7
- vi.mock('sonner', () => ({
8
- toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() },
9
- Toaster: () => null,
10
- }))
11
-
12
- const { PageBuilder } = await import('../../views/page-builder/PageBuilder.js')
13
-
14
- const TEMPLATE_TREE = {
15
- id: 'tpl-page',
16
- type: 'page',
17
- children: [
18
- {
19
- id: 'sec1',
20
- type: 'section',
21
- settings: { label: 'Hero From Template' },
22
- children: [],
23
- },
24
- ],
25
- }
26
-
27
- beforeEach(() => {
28
- cmsApi.mockReset()
29
- cmsApi.mockImplementation(async (endpoint: string) => {
30
- if (endpoint === '/page-templates/tpl-1') {
31
- return { data: { id: 'tpl-1', name: 'Landing', tree: TEMPLATE_TREE }, status: 200 }
32
- }
33
- return { data: {}, status: 200 }
34
- })
35
- })
36
-
37
- afterEach(cleanup)
38
-
39
- describe('PageBuilder template seeding (/page-builder/new?template=)', () => {
40
- it('fetches the template and seeds the canvas tree for a new page', async () => {
41
- render(
42
- <PageBuilder templateId="tpl-1" collectionSlug="pages" config={{}} onNavigate={() => {}} />,
43
- )
44
-
45
- await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/page-templates/tpl-1'))
46
- // replaceTree marks the builder dirty — the unsaved-changes dot is the
47
- // observable proof the template tree was seeded into the canvas state.
48
- expect(await screen.findByTitle('Unsaved changes')).toBeTruthy()
49
- })
50
-
51
- it('starts from a blank, clean tree when no template id is given', async () => {
52
- render(<PageBuilder collectionSlug="pages" config={{}} onNavigate={() => {}} />)
53
-
54
- await waitFor(() =>
55
- expect(cmsApi).not.toHaveBeenCalledWith(expect.stringContaining('/page-templates/')),
56
- )
57
- expect(screen.queryByTitle('Unsaved changes')).toBeNull()
58
- })
59
- })
@@ -1,182 +0,0 @@
1
- // @vitest-environment happy-dom
2
- import { beforeEach, describe, expect, it, vi } from 'vitest'
3
- import { fireEvent, render, screen, waitFor } from '@testing-library/react'
4
-
5
- const cmsApi = vi.fn()
6
- vi.mock('../../lib/api.js', () => ({ cmsApi: (...args: unknown[]) => cmsApi(...args) }))
7
- vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() } }))
8
-
9
- const { PageTemplates } = await import('../../views/page-builder/PageTemplates.js')
10
-
11
- function section(id: string) {
12
- return { id, type: 'section', settings: {}, children: [] }
13
- }
14
-
15
- const TEMPLATES = [
16
- {
17
- id: 'builtin-landing',
18
- name: 'Landing Page',
19
- description: 'Hero, features cards, CTA, testimonials, and final CTA',
20
- category: 'landing',
21
- builtIn: true,
22
- updatedAt: '2026-05-29T00:00:00.000Z',
23
- thumbnail: null,
24
- tree: { id: 'p1', type: 'page', children: [section('a'), section('b'), section('c')] },
25
- },
26
- {
27
- id: 'custom-1',
28
- name: 'Team Member',
29
- description: 'Avatar hero, full bio, and contact links',
30
- category: 'content',
31
- builtIn: false,
32
- updatedAt: '2026-06-10T00:00:00.000Z',
33
- thumbnail: null,
34
- tree: { id: 'p2', type: 'page', children: [section('a')] },
35
- },
36
- ]
37
-
38
- beforeEach(() => {
39
- cmsApi.mockReset()
40
- cmsApi.mockImplementation(async (endpoint: string, options?: RequestInit) => {
41
- if (endpoint === '/page-templates' && !options?.method) {
42
- return { data: TEMPLATES, status: 200 }
43
- }
44
- return { data: {}, status: 200 }
45
- })
46
- })
47
-
48
- describe('PageTemplates card grid', () => {
49
- it('renders a card per template with name, category, and section-count meta', async () => {
50
- render(<PageTemplates onNavigate={() => {}} />)
51
-
52
- expect(await screen.findByText('Landing Page')).toBeTruthy()
53
- expect(screen.getByText('Team Member')).toBeTruthy()
54
- // Section counts derived from each template's tree.
55
- expect(screen.getByText(/3 sections/)).toBeTruthy()
56
- expect(screen.getByText(/1 section ·/)).toBeTruthy()
57
- // Category labels from the design's palette.
58
- expect(screen.getByText('Landing Page')).toBeTruthy()
59
- expect(screen.getByText('Built-in')).toBeTruthy()
60
- })
61
-
62
- it('hides edit/delete actions on built-in templates (server rejects them)', async () => {
63
- render(<PageTemplates onNavigate={() => {}} />)
64
- await screen.findByText('Landing Page')
65
-
66
- expect(screen.queryByRole('button', { name: 'Edit Landing Page' })).toBeNull()
67
- expect(screen.queryByRole('button', { name: 'Delete Landing Page' })).toBeNull()
68
- expect(screen.getByRole('button', { name: 'Edit Team Member' })).toBeTruthy()
69
- expect(screen.getByRole('button', { name: 'Delete Team Member' })).toBeTruthy()
70
- })
71
-
72
- it('deletes a custom template only after the confirm dialog is accepted', async () => {
73
- render(<PageTemplates onNavigate={() => {}} />)
74
- await screen.findByText('Team Member')
75
-
76
- fireEvent.click(screen.getByRole('button', { name: 'Delete Team Member' }))
77
-
78
- // Confirm dialog is up; nothing deleted yet.
79
- expect(await screen.findByText('Delete template?')).toBeTruthy()
80
- expect(cmsApi).not.toHaveBeenCalledWith(
81
- '/page-templates/custom-1',
82
- expect.objectContaining({ method: 'DELETE' }),
83
- )
84
-
85
- fireEvent.click(screen.getByRole('button', { name: 'Delete' }))
86
-
87
- await waitFor(() =>
88
- expect(cmsApi).toHaveBeenCalledWith(
89
- '/page-templates/custom-1',
90
- expect.objectContaining({ method: 'DELETE' }),
91
- ),
92
- )
93
- })
94
-
95
- it('opens the edit modal seeded with the template and saves via PUT', async () => {
96
- render(<PageTemplates onNavigate={() => {}} />)
97
- await screen.findByText('Team Member')
98
-
99
- fireEvent.click(screen.getByRole('button', { name: 'Edit Team Member' }))
100
-
101
- const nameInput = (await screen.findByPlaceholderText('Template name')) as HTMLInputElement
102
- expect(nameInput.value).toBe('Team Member')
103
-
104
- fireEvent.change(nameInput, { target: { value: 'Team Bio' } })
105
- fireEvent.click(screen.getByRole('button', { name: 'Save changes' }))
106
-
107
- await waitFor(() =>
108
- expect(cmsApi).toHaveBeenCalledWith(
109
- '/page-templates/custom-1',
110
- expect.objectContaining({ method: 'PUT' }),
111
- ),
112
- )
113
- const putCall = cmsApi.mock.calls.find(
114
- (c) => (c[1] as RequestInit | undefined)?.method === 'PUT',
115
- )!
116
- expect(JSON.parse((putCall[1] as RequestInit).body as string)).toMatchObject({
117
- name: 'Team Bio',
118
- category: 'content',
119
- })
120
- })
121
-
122
- it('routes "Use template" into the builder with the template id', async () => {
123
- const onNavigate = vi.fn()
124
- render(<PageTemplates onNavigate={onNavigate} />)
125
- await screen.findByText('Landing Page')
126
-
127
- fireEvent.click(screen.getByRole('button', { name: 'Create page from Landing Page' }))
128
-
129
- expect(onNavigate).toHaveBeenCalledWith('/page-builder/new?template=builtin-landing')
130
- })
131
-
132
- it('duplicates a template (built-ins included) via POST with a "(copy)" name', async () => {
133
- render(<PageTemplates onNavigate={() => {}} />)
134
- await screen.findByText('Landing Page')
135
-
136
- fireEvent.click(screen.getByRole('button', { name: 'Duplicate Landing Page' }))
137
-
138
- await waitFor(() =>
139
- expect(cmsApi).toHaveBeenCalledWith(
140
- '/page-templates',
141
- expect.objectContaining({ method: 'POST' }),
142
- ),
143
- )
144
- const postCall = cmsApi.mock.calls.find(
145
- (c) => (c[1] as RequestInit | undefined)?.method === 'POST',
146
- )!
147
- expect(JSON.parse((postCall[1] as RequestInit).body as string)).toMatchObject({
148
- name: 'Landing Page (copy)',
149
- category: 'landing',
150
- tree: TEMPLATES[0]!.tree,
151
- })
152
- // The grid refetches so the copy appears.
153
- await waitFor(() =>
154
- expect(
155
- cmsApi.mock.calls.filter(
156
- (c) => c[0] === '/page-templates' && !(c[1] as RequestInit | undefined)?.method,
157
- ).length,
158
- ).toBeGreaterThanOrEqual(2),
159
- )
160
- })
161
-
162
- it('filters cards by search text', async () => {
163
- render(<PageTemplates onNavigate={() => {}} />)
164
- await screen.findByText('Team Member')
165
-
166
- fireEvent.change(screen.getByPlaceholderText('Search templates…'), {
167
- target: { value: 'landing' },
168
- })
169
-
170
- await waitFor(() => {
171
- expect(screen.queryByText('Team Member')).toBeNull()
172
- expect(screen.getByText('Landing Page')).toBeTruthy()
173
- })
174
- })
175
-
176
- it('shows the empty state when no templates exist', async () => {
177
- cmsApi.mockResolvedValue({ data: [], status: 200 })
178
- render(<PageTemplates onNavigate={() => {}} />)
179
-
180
- expect(await screen.findByText('No page templates yet')).toBeTruthy()
181
- })
182
- })