@prenta/admin 0.92.0 → 0.94.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 (425) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/design-system/tokens.css +173 -71
  3. package/design-system/tokens.json +244 -63
  4. package/design-system/tokens.scss +203 -98
  5. package/design-system/tokens.tailwind.cjs +93 -38
  6. package/dist/AdminRoot.d.ts +27 -6
  7. package/dist/AdminRoot.d.ts.map +1 -1
  8. package/dist/AdminRoot.js.map +1 -1
  9. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts +2 -0
  10. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts.map +1 -0
  11. package/dist/__tests__/components/breakpoint-controls.render.test.js +51 -0
  12. package/dist/__tests__/components/breakpoint-controls.render.test.js.map +1 -0
  13. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts +2 -0
  14. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts.map +1 -0
  15. package/dist/__tests__/components/canvas-edit-tip.render.test.js +37 -0
  16. package/dist/__tests__/components/canvas-edit-tip.render.test.js.map +1 -0
  17. package/dist/__tests__/components/editor-rail.render.test.d.ts +2 -0
  18. package/dist/__tests__/components/editor-rail.render.test.d.ts.map +1 -0
  19. package/dist/__tests__/components/editor-rail.render.test.js +138 -0
  20. package/dist/__tests__/components/editor-rail.render.test.js.map +1 -0
  21. package/dist/__tests__/components/media-block.render.test.d.ts +2 -0
  22. package/dist/__tests__/components/media-block.render.test.d.ts.map +1 -0
  23. package/dist/__tests__/components/media-block.render.test.js +108 -0
  24. package/dist/__tests__/components/media-block.render.test.js.map +1 -0
  25. package/dist/__tests__/components/page-audit-panel.render.test.d.ts +2 -0
  26. package/dist/__tests__/components/page-audit-panel.render.test.d.ts.map +1 -0
  27. package/dist/__tests__/components/page-audit-panel.render.test.js +59 -0
  28. package/dist/__tests__/components/page-audit-panel.render.test.js.map +1 -0
  29. package/dist/__tests__/components/reflow-meter.render.test.d.ts +2 -0
  30. package/dist/__tests__/components/reflow-meter.render.test.d.ts.map +1 -0
  31. package/dist/__tests__/components/reflow-meter.render.test.js +94 -0
  32. package/dist/__tests__/components/reflow-meter.render.test.js.map +1 -0
  33. package/dist/__tests__/components/seo-char-count.test.js +24 -6
  34. package/dist/__tests__/components/seo-char-count.test.js.map +1 -1
  35. package/dist/__tests__/components/serp-preview.render.test.d.ts +2 -0
  36. package/dist/__tests__/components/serp-preview.render.test.d.ts.map +1 -0
  37. package/dist/__tests__/components/serp-preview.render.test.js +25 -0
  38. package/dist/__tests__/components/serp-preview.render.test.js.map +1 -0
  39. package/dist/__tests__/lib/breakpoints.test.d.ts +2 -0
  40. package/dist/__tests__/lib/breakpoints.test.d.ts.map +1 -0
  41. package/dist/__tests__/lib/breakpoints.test.js +67 -0
  42. package/dist/__tests__/lib/breakpoints.test.js.map +1 -0
  43. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts +2 -0
  44. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts.map +1 -0
  45. package/dist/__tests__/lib/canvas-edit-chrome.test.js +44 -0
  46. package/dist/__tests__/lib/canvas-edit-chrome.test.js.map +1 -0
  47. package/dist/__tests__/lib/media-format.test.d.ts +2 -0
  48. package/dist/__tests__/lib/media-format.test.d.ts.map +1 -0
  49. package/dist/__tests__/lib/media-format.test.js +70 -0
  50. package/dist/__tests__/lib/media-format.test.js.map +1 -0
  51. package/dist/__tests__/lib/page-audit-input.test.d.ts +2 -0
  52. package/dist/__tests__/lib/page-audit-input.test.d.ts.map +1 -0
  53. package/dist/__tests__/lib/page-audit-input.test.js +122 -0
  54. package/dist/__tests__/lib/page-audit-input.test.js.map +1 -0
  55. package/dist/__tests__/lib/page-editor-service.test.js +2 -0
  56. package/dist/__tests__/lib/page-editor-service.test.js.map +1 -1
  57. package/dist/__tests__/lib/page-redirect.test.d.ts +2 -0
  58. package/dist/__tests__/lib/page-redirect.test.d.ts.map +1 -0
  59. package/dist/__tests__/lib/page-redirect.test.js +26 -0
  60. package/dist/__tests__/lib/page-redirect.test.js.map +1 -0
  61. package/dist/__tests__/lib/rail-width.test.d.ts +2 -0
  62. package/dist/__tests__/lib/rail-width.test.d.ts.map +1 -0
  63. package/dist/__tests__/lib/rail-width.test.js +69 -0
  64. package/dist/__tests__/lib/rail-width.test.js.map +1 -0
  65. package/dist/__tests__/lib/reflow-baseline.test.d.ts +2 -0
  66. package/dist/__tests__/lib/reflow-baseline.test.d.ts.map +1 -0
  67. package/dist/__tests__/lib/reflow-baseline.test.js +56 -0
  68. package/dist/__tests__/lib/reflow-baseline.test.js.map +1 -0
  69. package/dist/__tests__/lib/reflow-probe.test.d.ts +2 -0
  70. package/dist/__tests__/lib/reflow-probe.test.d.ts.map +1 -0
  71. package/dist/__tests__/lib/reflow-probe.test.js +73 -0
  72. package/dist/__tests__/lib/reflow-probe.test.js.map +1 -0
  73. package/dist/__tests__/lib/version-diff.test.d.ts +2 -0
  74. package/dist/__tests__/lib/version-diff.test.d.ts.map +1 -0
  75. package/dist/__tests__/lib/version-diff.test.js +230 -0
  76. package/dist/__tests__/lib/version-diff.test.js.map +1 -0
  77. package/dist/__tests__/lib/version-history.test.d.ts +2 -0
  78. package/dist/__tests__/lib/version-history.test.d.ts.map +1 -0
  79. package/dist/__tests__/lib/version-history.test.js +125 -0
  80. package/dist/__tests__/lib/version-history.test.js.map +1 -0
  81. package/dist/__tests__/styles/canvas-container-queries.test.d.ts +2 -0
  82. package/dist/__tests__/styles/canvas-container-queries.test.d.ts.map +1 -0
  83. package/dist/__tests__/styles/canvas-container-queries.test.js +87 -0
  84. package/dist/__tests__/styles/canvas-container-queries.test.js.map +1 -0
  85. package/dist/__tests__/styles/packaging.test.d.ts +2 -0
  86. package/dist/__tests__/styles/packaging.test.d.ts.map +1 -0
  87. package/dist/__tests__/styles/packaging.test.js +31 -0
  88. package/dist/__tests__/styles/packaging.test.js.map +1 -0
  89. package/dist/__tests__/styles/responsive-layer.test.d.ts +2 -0
  90. package/dist/__tests__/styles/responsive-layer.test.d.ts.map +1 -0
  91. package/dist/__tests__/styles/responsive-layer.test.js +127 -0
  92. package/dist/__tests__/styles/responsive-layer.test.js.map +1 -0
  93. package/dist/__tests__/styles/tokens-drift.test.d.ts +2 -0
  94. package/dist/__tests__/styles/tokens-drift.test.d.ts.map +1 -0
  95. package/dist/__tests__/styles/tokens-drift.test.js +92 -0
  96. package/dist/__tests__/styles/tokens-drift.test.js.map +1 -0
  97. package/dist/__tests__/views/admin-renderer-compat.test.d.ts +2 -0
  98. package/dist/__tests__/views/admin-renderer-compat.test.d.ts.map +1 -0
  99. package/dist/__tests__/views/admin-renderer-compat.test.js +43 -0
  100. package/dist/__tests__/views/admin-renderer-compat.test.js.map +1 -0
  101. package/dist/__tests__/views/admin-section-renderers.test.js +52 -4
  102. package/dist/__tests__/views/admin-section-renderers.test.js.map +1 -1
  103. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts +2 -0
  104. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts.map +1 -0
  105. package/dist/__tests__/views/canvas-review-mode.render.test.js +70 -0
  106. package/dist/__tests__/views/canvas-review-mode.render.test.js.map +1 -0
  107. package/dist/__tests__/views/editor-top-bar.render.test.js +30 -1
  108. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  109. package/dist/__tests__/views/page-tab.render.test.d.ts +2 -0
  110. package/dist/__tests__/views/page-tab.render.test.d.ts.map +1 -0
  111. package/dist/__tests__/views/page-tab.render.test.js +151 -0
  112. package/dist/__tests__/views/page-tab.render.test.js.map +1 -0
  113. package/dist/__tests__/views/section-class-parity.test.d.ts +2 -0
  114. package/dist/__tests__/views/section-class-parity.test.d.ts.map +1 -0
  115. package/dist/__tests__/views/section-class-parity.test.js +81 -0
  116. package/dist/__tests__/views/section-class-parity.test.js.map +1 -0
  117. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts +2 -0
  118. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts.map +1 -0
  119. package/dist/__tests__/views/sections-panel-design-owned.render.test.js +86 -0
  120. package/dist/__tests__/views/sections-panel-design-owned.render.test.js.map +1 -0
  121. package/dist/__tests__/views/version-history-panel.render.test.d.ts +2 -0
  122. package/dist/__tests__/views/version-history-panel.render.test.d.ts.map +1 -0
  123. package/dist/__tests__/views/version-history-panel.render.test.js +153 -0
  124. package/dist/__tests__/views/version-history-panel.render.test.js.map +1 -0
  125. package/dist/components/BreakpointPicker.d.ts +18 -0
  126. package/dist/components/BreakpointPicker.d.ts.map +1 -0
  127. package/dist/components/BreakpointPicker.js +31 -0
  128. package/dist/components/BreakpointPicker.js.map +1 -0
  129. package/dist/components/CanvasEditTip.d.ts +6 -0
  130. package/dist/components/CanvasEditTip.d.ts.map +1 -0
  131. package/dist/components/CanvasEditTip.js +22 -0
  132. package/dist/components/CanvasEditTip.js.map +1 -0
  133. package/dist/components/EditorRail.d.ts +36 -0
  134. package/dist/components/EditorRail.d.ts.map +1 -0
  135. package/dist/components/EditorRail.js +104 -0
  136. package/dist/components/EditorRail.js.map +1 -0
  137. package/dist/components/EditorRailTabs.d.ts +32 -0
  138. package/dist/components/EditorRailTabs.d.ts.map +1 -0
  139. package/dist/components/EditorRailTabs.js +45 -0
  140. package/dist/components/EditorRailTabs.js.map +1 -0
  141. package/dist/components/MediaBlock.d.ts +49 -0
  142. package/dist/components/MediaBlock.d.ts.map +1 -0
  143. package/dist/components/MediaBlock.js +50 -0
  144. package/dist/components/MediaBlock.js.map +1 -0
  145. package/dist/components/ReflowMeter.d.ts +28 -0
  146. package/dist/components/ReflowMeter.d.ts.map +1 -0
  147. package/dist/components/ReflowMeter.js +42 -0
  148. package/dist/components/ReflowMeter.js.map +1 -0
  149. package/dist/components/ZoomChip.d.ts +17 -0
  150. package/dist/components/ZoomChip.d.ts.map +1 -0
  151. package/dist/components/ZoomChip.js +17 -0
  152. package/dist/components/ZoomChip.js.map +1 -0
  153. package/dist/components/breakpoint-icons.d.ts +3 -0
  154. package/dist/components/breakpoint-icons.d.ts.map +1 -0
  155. package/dist/components/breakpoint-icons.js +16 -0
  156. package/dist/components/breakpoint-icons.js.map +1 -0
  157. package/dist/components/page-tab/AuthorPicker.d.ts +31 -0
  158. package/dist/components/page-tab/AuthorPicker.d.ts.map +1 -0
  159. package/dist/components/page-tab/AuthorPicker.js +95 -0
  160. package/dist/components/page-tab/AuthorPicker.js.map +1 -0
  161. package/dist/components/page-tab/DirectiveSwitch.d.ts +38 -0
  162. package/dist/components/page-tab/DirectiveSwitch.d.ts.map +1 -0
  163. package/dist/components/page-tab/DirectiveSwitch.js +33 -0
  164. package/dist/components/page-tab/DirectiveSwitch.js.map +1 -0
  165. package/dist/components/seo/EditorSeoScoreBadge.d.ts +8 -1
  166. package/dist/components/seo/EditorSeoScoreBadge.d.ts.map +1 -1
  167. package/dist/components/seo/EditorSeoScoreBadge.js +2 -2
  168. package/dist/components/seo/EditorSeoScoreBadge.js.map +1 -1
  169. package/dist/components/seo/PageAuditPanel.d.ts +14 -0
  170. package/dist/components/seo/PageAuditPanel.d.ts.map +1 -0
  171. package/dist/components/seo/PageAuditPanel.js +59 -0
  172. package/dist/components/seo/PageAuditPanel.js.map +1 -0
  173. package/dist/components/seo/SeoCharCount.d.ts +19 -7
  174. package/dist/components/seo/SeoCharCount.d.ts.map +1 -1
  175. package/dist/components/seo/SeoCharCount.js +30 -16
  176. package/dist/components/seo/SeoCharCount.js.map +1 -1
  177. package/dist/components/seo/SeoEditorPane.d.ts +15 -1
  178. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
  179. package/dist/components/seo/SeoEditorPane.js +118 -21
  180. package/dist/components/seo/SeoEditorPane.js.map +1 -1
  181. package/dist/components/seo/SerpPreview.d.ts +20 -0
  182. package/dist/components/seo/SerpPreview.d.ts.map +1 -0
  183. package/dist/components/seo/SerpPreview.js +6 -0
  184. package/dist/components/seo/SerpPreview.js.map +1 -0
  185. package/dist/hooks/usePageAudit.d.ts +41 -0
  186. package/dist/hooks/usePageAudit.d.ts.map +1 -0
  187. package/dist/hooks/usePageAudit.js +68 -0
  188. package/dist/hooks/usePageAudit.js.map +1 -0
  189. package/dist/hooks/useReflowGuard.d.ts +47 -0
  190. package/dist/hooks/useReflowGuard.d.ts.map +1 -0
  191. package/dist/hooks/useReflowGuard.js +52 -0
  192. package/dist/hooks/useReflowGuard.js.map +1 -0
  193. package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
  194. package/dist/layout/primitives/AdminShell.js +2 -2
  195. package/dist/layout/primitives/AdminShell.js.map +1 -1
  196. package/dist/lib/breakpoints.d.ts +51 -0
  197. package/dist/lib/breakpoints.d.ts.map +1 -0
  198. package/dist/lib/breakpoints.js +84 -0
  199. package/dist/lib/breakpoints.js.map +1 -0
  200. package/dist/lib/canvas-edit-chrome.d.ts +22 -0
  201. package/dist/lib/canvas-edit-chrome.d.ts.map +1 -0
  202. package/dist/lib/canvas-edit-chrome.js +81 -0
  203. package/dist/lib/canvas-edit-chrome.js.map +1 -0
  204. package/dist/lib/media-format.d.ts +55 -0
  205. package/dist/lib/media-format.d.ts.map +1 -0
  206. package/dist/lib/media-format.js +93 -0
  207. package/dist/lib/media-format.js.map +1 -0
  208. package/dist/lib/page-audit-input.d.ts +45 -0
  209. package/dist/lib/page-audit-input.d.ts.map +1 -0
  210. package/dist/lib/page-audit-input.js +53 -0
  211. package/dist/lib/page-audit-input.js.map +1 -0
  212. package/dist/lib/page-editor-service.d.ts +12 -0
  213. package/dist/lib/page-editor-service.d.ts.map +1 -1
  214. package/dist/lib/page-editor-service.js +6 -0
  215. package/dist/lib/page-editor-service.js.map +1 -1
  216. package/dist/lib/page-redirect.d.ts +39 -0
  217. package/dist/lib/page-redirect.d.ts.map +1 -0
  218. package/dist/lib/page-redirect.js +38 -0
  219. package/dist/lib/page-redirect.js.map +1 -0
  220. package/dist/lib/rail-width.d.ts +23 -0
  221. package/dist/lib/rail-width.d.ts.map +1 -0
  222. package/dist/lib/rail-width.js +59 -0
  223. package/dist/lib/rail-width.js.map +1 -0
  224. package/dist/lib/reflow-baseline.d.ts +45 -0
  225. package/dist/lib/reflow-baseline.d.ts.map +1 -0
  226. package/dist/lib/reflow-baseline.js +38 -0
  227. package/dist/lib/reflow-baseline.js.map +1 -0
  228. package/dist/lib/reflow-probe.d.ts +159 -0
  229. package/dist/lib/reflow-probe.d.ts.map +1 -0
  230. package/dist/lib/reflow-probe.js +228 -0
  231. package/dist/lib/reflow-probe.js.map +1 -0
  232. package/dist/lib/seo-service.d.ts +10 -0
  233. package/dist/lib/seo-service.d.ts.map +1 -1
  234. package/dist/lib/seo-service.js.map +1 -1
  235. package/dist/lib/version-diff.d.ts +50 -0
  236. package/dist/lib/version-diff.d.ts.map +1 -0
  237. package/dist/lib/version-diff.js +294 -0
  238. package/dist/lib/version-diff.js.map +1 -0
  239. package/dist/lib/version-history.d.ts +73 -0
  240. package/dist/lib/version-history.d.ts.map +1 -0
  241. package/dist/lib/version-history.js +126 -0
  242. package/dist/lib/version-history.js.map +1 -0
  243. package/dist/prenta-admin.css +1 -1
  244. package/dist/views/page-editor/CanvasMetaLine.d.ts +19 -0
  245. package/dist/views/page-editor/CanvasMetaLine.d.ts.map +1 -0
  246. package/dist/views/page-editor/CanvasMetaLine.js +23 -0
  247. package/dist/views/page-editor/CanvasMetaLine.js.map +1 -0
  248. package/dist/views/page-editor/EditorCanvas.d.ts +47 -8
  249. package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
  250. package/dist/views/page-editor/EditorCanvas.js +68 -34
  251. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  252. package/dist/views/page-editor/EditorTopBar.d.ts +21 -2
  253. package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
  254. package/dist/views/page-editor/EditorTopBar.js +13 -20
  255. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  256. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  257. package/dist/views/page-editor/PageSectionEditor.js +383 -78
  258. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  259. package/dist/views/page-editor/PageTab.d.ts +36 -0
  260. package/dist/views/page-editor/PageTab.d.ts.map +1 -0
  261. package/dist/views/page-editor/PageTab.js +65 -0
  262. package/dist/views/page-editor/PageTab.js.map +1 -0
  263. package/dist/views/page-editor/ReviewBar.d.ts +21 -0
  264. package/dist/views/page-editor/ReviewBar.d.ts.map +1 -0
  265. package/dist/views/page-editor/ReviewBar.js +22 -0
  266. package/dist/views/page-editor/ReviewBar.js.map +1 -0
  267. package/dist/views/page-editor/SectionInspector.d.ts.map +1 -1
  268. package/dist/views/page-editor/SectionInspector.js +64 -20
  269. package/dist/views/page-editor/SectionInspector.js.map +1 -1
  270. package/dist/views/page-editor/SectionsPanel.d.ts +30 -5
  271. package/dist/views/page-editor/SectionsPanel.d.ts.map +1 -1
  272. package/dist/views/page-editor/SectionsPanel.js +38 -7
  273. package/dist/views/page-editor/SectionsPanel.js.map +1 -1
  274. package/dist/views/page-editor/SitePreviewFrame.d.ts.map +1 -1
  275. package/dist/views/page-editor/SitePreviewFrame.js +3 -0
  276. package/dist/views/page-editor/SitePreviewFrame.js.map +1 -1
  277. package/dist/views/page-editor/VersionHistoryPanel.d.ts +29 -0
  278. package/dist/views/page-editor/VersionHistoryPanel.d.ts.map +1 -0
  279. package/dist/views/page-editor/VersionHistoryPanel.js +81 -0
  280. package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -0
  281. package/dist/views/page-editor/reflow-context.d.ts +28 -0
  282. package/dist/views/page-editor/reflow-context.d.ts.map +1 -0
  283. package/dist/views/page-editor/reflow-context.js +14 -0
  284. package/dist/views/page-editor/reflow-context.js.map +1 -0
  285. package/dist/views/page-editor/sections/ByTheNumbersSection.d.ts.map +1 -1
  286. package/dist/views/page-editor/sections/ByTheNumbersSection.js +1 -1
  287. package/dist/views/page-editor/sections/ByTheNumbersSection.js.map +1 -1
  288. package/dist/views/page-editor/sections/CtaBannerSection.d.ts.map +1 -1
  289. package/dist/views/page-editor/sections/CtaBannerSection.js +1 -1
  290. package/dist/views/page-editor/sections/CtaBannerSection.js.map +1 -1
  291. package/dist/views/page-editor/sections/FeatureHighlightSection.d.ts.map +1 -1
  292. package/dist/views/page-editor/sections/FeatureHighlightSection.js +2 -2
  293. package/dist/views/page-editor/sections/FeatureHighlightSection.js.map +1 -1
  294. package/dist/views/page-editor/sections/GallerySection.d.ts.map +1 -1
  295. package/dist/views/page-editor/sections/GallerySection.js +7 -3
  296. package/dist/views/page-editor/sections/GallerySection.js.map +1 -1
  297. package/dist/views/page-editor/sections/HeroBannerSection.js +1 -1
  298. package/dist/views/page-editor/sections/HeroBannerSection.js.map +1 -1
  299. package/dist/views/page-editor/sections/MissionSection.d.ts.map +1 -1
  300. package/dist/views/page-editor/sections/MissionSection.js +1 -1
  301. package/dist/views/page-editor/sections/MissionSection.js.map +1 -1
  302. package/dist/views/page-editor/sections/PullQuoteSection.d.ts.map +1 -1
  303. package/dist/views/page-editor/sections/PullQuoteSection.js +1 -1
  304. package/dist/views/page-editor/sections/PullQuoteSection.js.map +1 -1
  305. package/dist/views/page-editor/sections/RelatedPostsSection.d.ts.map +1 -1
  306. package/dist/views/page-editor/sections/RelatedPostsSection.js +1 -1
  307. package/dist/views/page-editor/sections/RelatedPostsSection.js.map +1 -1
  308. package/dist/views/page-editor/sections/SectionRenderer.d.ts +13 -1
  309. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  310. package/dist/views/page-editor/sections/SectionRenderer.js +66 -26
  311. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  312. package/dist/views/page-editor/sections/admin-renderers.d.ts +47 -15
  313. package/dist/views/page-editor/sections/admin-renderers.d.ts.map +1 -1
  314. package/dist/views/page-editor/sections/admin-renderers.js +27 -15
  315. package/dist/views/page-editor/sections/admin-renderers.js.map +1 -1
  316. package/dist/views/page-editor/sections/parts.d.ts +0 -1
  317. package/dist/views/page-editor/sections/parts.d.ts.map +1 -1
  318. package/dist/views/page-editor/sections/parts.js +41 -16
  319. package/dist/views/page-editor/sections/parts.js.map +1 -1
  320. package/dist/views/page-editor/viewports.d.ts +7 -14
  321. package/dist/views/page-editor/viewports.d.ts.map +1 -1
  322. package/dist/views/page-editor/viewports.js +7 -12
  323. package/dist/views/page-editor/viewports.js.map +1 -1
  324. package/dist/views/post-editor/PostEditorCanvas.d.ts +2 -1
  325. package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
  326. package/dist/views/post-editor/PostEditorCanvas.js +5 -2
  327. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  328. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  329. package/dist/views/post-editor/PostSectionEditor.js +2 -20
  330. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  331. package/dist/views/post-editor/PostTemplateEditor.d.ts.map +1 -1
  332. package/dist/views/post-editor/PostTemplateEditor.js +4 -1
  333. package/dist/views/post-editor/PostTemplateEditor.js.map +1 -1
  334. package/package.json +5 -3
  335. package/src/AdminRoot.tsx +27 -6
  336. package/src/__tests__/components/breakpoint-controls.render.test.tsx +57 -0
  337. package/src/__tests__/components/canvas-edit-tip.render.test.tsx +41 -0
  338. package/src/__tests__/components/editor-rail.render.test.tsx +192 -0
  339. package/src/__tests__/components/media-block.render.test.tsx +126 -0
  340. package/src/__tests__/components/page-audit-panel.render.test.tsx +64 -0
  341. package/src/__tests__/components/reflow-meter.render.test.tsx +144 -0
  342. package/src/__tests__/components/seo-char-count.test.tsx +26 -6
  343. package/src/__tests__/components/serp-preview.render.test.tsx +32 -0
  344. package/src/__tests__/lib/breakpoints.test.ts +84 -0
  345. package/src/__tests__/lib/canvas-edit-chrome.test.ts +56 -0
  346. package/src/__tests__/lib/media-format.test.ts +89 -0
  347. package/src/__tests__/lib/page-audit-input.test.ts +144 -0
  348. package/src/__tests__/lib/page-editor-service.test.ts +2 -0
  349. package/src/__tests__/lib/page-redirect.test.ts +29 -0
  350. package/src/__tests__/lib/rail-width.test.ts +86 -0
  351. package/src/__tests__/lib/reflow-baseline.test.ts +64 -0
  352. package/src/__tests__/lib/reflow-probe.test.ts +95 -0
  353. package/src/__tests__/lib/version-diff.test.ts +278 -0
  354. package/src/__tests__/lib/version-history.test.ts +166 -0
  355. package/src/__tests__/styles/canvas-container-queries.test.ts +103 -0
  356. package/src/__tests__/styles/packaging.test.ts +38 -0
  357. package/src/__tests__/styles/responsive-layer.test.ts +152 -0
  358. package/src/__tests__/styles/tokens-drift.test.ts +110 -0
  359. package/src/__tests__/views/admin-renderer-compat.test.ts +48 -0
  360. package/src/__tests__/views/admin-section-renderers.test.tsx +70 -4
  361. package/src/__tests__/views/canvas-review-mode.render.test.tsx +94 -0
  362. package/src/__tests__/views/editor-top-bar.render.test.tsx +43 -1
  363. package/src/__tests__/views/page-tab.render.test.tsx +226 -0
  364. package/src/__tests__/views/section-class-parity.test.ts +98 -0
  365. package/src/__tests__/views/sections-panel-design-owned.render.test.tsx +104 -0
  366. package/src/__tests__/views/version-history-panel.render.test.tsx +195 -0
  367. package/src/components/BreakpointPicker.tsx +114 -0
  368. package/src/components/CanvasEditTip.tsx +46 -0
  369. package/src/components/EditorRail.tsx +219 -0
  370. package/src/components/EditorRailTabs.tsx +117 -0
  371. package/src/components/MediaBlock.tsx +223 -0
  372. package/src/components/ReflowMeter.tsx +125 -0
  373. package/src/components/ZoomChip.tsx +39 -0
  374. package/src/components/breakpoint-icons.ts +17 -0
  375. package/src/components/page-tab/AuthorPicker.tsx +240 -0
  376. package/src/components/page-tab/DirectiveSwitch.tsx +89 -0
  377. package/src/components/seo/EditorSeoScoreBadge.tsx +9 -1
  378. package/src/components/seo/PageAuditPanel.tsx +192 -0
  379. package/src/components/seo/SeoCharCount.tsx +55 -24
  380. package/src/components/seo/SeoEditorPane.tsx +213 -31
  381. package/src/components/seo/SerpPreview.tsx +41 -0
  382. package/src/hooks/usePageAudit.ts +98 -0
  383. package/src/hooks/useReflowGuard.ts +96 -0
  384. package/src/layout/primitives/AdminShell.tsx +13 -1
  385. package/src/lib/breakpoints.ts +107 -0
  386. package/src/lib/canvas-edit-chrome.ts +82 -0
  387. package/src/lib/media-format.ts +99 -0
  388. package/src/lib/page-audit-input.ts +104 -0
  389. package/src/lib/page-editor-service.ts +18 -0
  390. package/src/lib/page-redirect.ts +60 -0
  391. package/src/lib/rail-width.ts +58 -0
  392. package/src/lib/reflow-baseline.ts +70 -0
  393. package/src/lib/reflow-probe.ts +299 -0
  394. package/src/lib/seo-service.ts +10 -0
  395. package/src/lib/version-diff.ts +376 -0
  396. package/src/lib/version-history.ts +192 -0
  397. package/src/styles/prenta-tokens.css +120 -42
  398. package/src/styles/responsive.css +281 -0
  399. package/src/styles/theme.css +138 -0
  400. package/src/views/page-editor/CanvasMetaLine.tsx +50 -0
  401. package/src/views/page-editor/EditorCanvas.tsx +140 -54
  402. package/src/views/page-editor/EditorTopBar.tsx +55 -51
  403. package/src/views/page-editor/PageSectionEditor.tsx +575 -185
  404. package/src/views/page-editor/PageTab.tsx +433 -0
  405. package/src/views/page-editor/ReviewBar.tsx +76 -0
  406. package/src/views/page-editor/SectionInspector.tsx +84 -42
  407. package/src/views/page-editor/SectionsPanel.tsx +282 -141
  408. package/src/views/page-editor/SitePreviewFrame.tsx +3 -0
  409. package/src/views/page-editor/VersionHistoryPanel.tsx +302 -0
  410. package/src/views/page-editor/reflow-context.ts +43 -0
  411. package/src/views/page-editor/sections/ByTheNumbersSection.tsx +3 -2
  412. package/src/views/page-editor/sections/CtaBannerSection.tsx +3 -1
  413. package/src/views/page-editor/sections/FeatureHighlightSection.tsx +3 -2
  414. package/src/views/page-editor/sections/GallerySection.tsx +7 -3
  415. package/src/views/page-editor/sections/HeroBannerSection.tsx +2 -2
  416. package/src/views/page-editor/sections/MissionSection.tsx +4 -2
  417. package/src/views/page-editor/sections/PullQuoteSection.tsx +3 -1
  418. package/src/views/page-editor/sections/RelatedPostsSection.tsx +2 -1
  419. package/src/views/page-editor/sections/SectionRenderer.tsx +115 -34
  420. package/src/views/page-editor/sections/admin-renderers.tsx +54 -15
  421. package/src/views/page-editor/sections/parts.tsx +46 -18
  422. package/src/views/page-editor/viewports.ts +13 -26
  423. package/src/views/post-editor/PostEditorCanvas.tsx +18 -11
  424. package/src/views/post-editor/PostSectionEditor.tsx +1 -56
  425. package/src/views/post-editor/PostTemplateEditor.tsx +3 -0
@@ -1,71 +1,116 @@
1
1
  'use client'
2
2
 
3
3
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
4
- import { LayoutTemplate, Plus } from 'lucide-react'
4
+ import { LayoutTemplate } from 'lucide-react'
5
+ import { CanvasEditTip } from '../../components/CanvasEditTip.js'
6
+ import { CanvasMetaLine } from './CanvasMetaLine.js'
7
+ import { fitScale, getBreakpoint, type BreakpointId, type Zoom } from '../../lib/breakpoints.js'
5
8
  import type { PageSection } from '../../lib/page-editor-service.js'
6
9
  import { SectionRenderer } from './sections/index.js'
7
10
  import { StructureNotice } from './StructureNotice.js'
8
- import { getViewport, type ViewportId } from './viewports.js'
9
11
 
10
12
  interface EditorCanvasProps {
11
13
  sections: PageSection[]
12
14
  selectedId: string | null
13
- viewport: ViewportId
15
+ breakpoint: BreakpointId
16
+ zoom?: Zoom
14
17
  onSelect: (id: string) => void
15
- onAddSection: () => void
18
+ /**
19
+ * Reports the measured scale so the header's zoom chip can show a real
20
+ * percentage. Only the canvas knows the available width, so the number has
21
+ * to travel up rather than being recomputed by the header.
22
+ */
23
+ onScaleChange?: (scale: number) => void
24
+ /**
25
+ * Reports the canvas surface element, so the reflow guard can clone it. The
26
+ * guard needs the real element rather than a `document.querySelector`, which
27
+ * would also match the site-preview frame's canvas when that is mounted.
28
+ */
29
+ onCanvasElement?: (el: HTMLElement | null) => void
16
30
  /** Section types rendered as placeholders — shows the "Structure view" notice. */
17
31
  structuralTypes?: string[]
18
32
  sitePreviewAvailable?: boolean
33
+ /**
34
+ * Read-only render of a past version. Suppresses selection and the editing
35
+ * affordances, and turns on the changed-section outlines.
36
+ */
37
+ reviewing?: boolean
38
+ /** Sections that differ from the version before the one being reviewed. */
39
+ changedSectionIds?: ReadonlySet<string>
40
+ /**
41
+ * Rendered in place of the editing tip / structure notice while reviewing.
42
+ * Passed in rather than built here because the review bar's actions belong
43
+ * to the editor's history state, which the canvas knows nothing about.
44
+ */
45
+ reviewBar?: React.ReactNode
19
46
  }
20
47
 
21
48
  /**
22
- * The preview canvas. Renders the page at the selected viewport's logical
23
- * width and scales it down with a CSS transform so wide viewports (1440px,
24
- * 1920px) fit inside the available canvas column. Scale is recomputed from
25
- * a ResizeObserver so it stays correct as panels open/close.
49
+ * The preview canvas.
50
+ *
51
+ * The canvas renders at the breakpoint's **real CSS width** and is scaled down
52
+ * with a transform. Combined with `container-type: inline-size`, that makes the
53
+ * page reflow against its own width — the same container queries that style the
54
+ * live page decide the layout. A max-width clamp cannot do this: it yields a
55
+ * narrow desktop layout rather than the mobile one.
56
+ *
57
+ * Two measurement rules, both learned the hard way:
58
+ *
59
+ * 1. Available width comes from a **zero-height sentinel** rendered as the
60
+ * panel's first child, not from `panel.clientWidth - padding`. The two
61
+ * disagree once a scrollbar appears or the host scales the preview, and
62
+ * the padding arithmetic silently rots whenever the gutter changes.
63
+ * 2. Both measurements are re-taken on **every render**, not only from the
64
+ * ResizeObserver. Page height changes with every text edit, image swap and
65
+ * show/hide — none of which resize the observed elements. The observer
66
+ * exists for later window resizes; its first callback is not a substitute.
26
67
  */
27
68
  export function EditorCanvas({
28
69
  sections,
29
70
  selectedId,
30
- viewport,
71
+ breakpoint,
72
+ zoom = 'fit',
31
73
  onSelect,
32
- onAddSection,
74
+ onScaleChange,
75
+ onCanvasElement,
33
76
  structuralTypes = [],
34
77
  sitePreviewAvailable = false,
78
+ reviewing = false,
79
+ changedSectionIds,
80
+ reviewBar,
35
81
  }: EditorCanvasProps) {
36
- const vp = getViewport(viewport)
37
- const containerRef = useRef<HTMLDivElement>(null)
82
+ const bp = getBreakpoint(breakpoint)
83
+ const sentinelRef = useRef<HTMLDivElement>(null)
38
84
  const surfaceRef = useRef<HTMLDivElement>(null)
39
85
  const sectionRefs = useRef<Map<string, HTMLElement>>(new Map())
40
- const [scale, setScale] = useState(1)
41
- const [surfaceHeight, setSurfaceHeight] = useState<number | null>(null)
86
+
87
+ const [available, setAvailable] = useState(0)
88
+ const [pageHeight, setPageHeight] = useState(0)
42
89
 
43
90
  const registerRef = useCallback((id: string, el: HTMLElement | null) => {
44
91
  if (el) sectionRefs.current.set(id, el)
45
92
  else sectionRefs.current.delete(id)
46
93
  }, [])
47
94
 
48
- // Recompute scale + scaled height from the container width.
95
+ // No dependency array: page height changes on edits that resize nothing the
96
+ // observer watches. Both setters bail when the value is unchanged, so this
97
+ // settles after one extra pass instead of looping.
49
98
  useLayoutEffect(() => {
50
- const container = containerRef.current
51
- if (!container) return
52
-
53
- const recompute = () => {
54
- // 48px breathing room so the surface never kisses the column edges.
55
- const available = container.clientWidth - 48
56
- const next = Math.min(1, available / vp.width)
57
- setScale(next > 0 ? next : 1)
58
- if (surfaceRef.current) {
59
- setSurfaceHeight(surfaceRef.current.offsetHeight * (next > 0 ? next : 1))
60
- }
99
+ const measure = () => {
100
+ const sentinelWidth = sentinelRef.current?.offsetWidth ?? 0
101
+ if (sentinelWidth > 0) setAvailable((prev) => (prev === sentinelWidth ? prev : sentinelWidth))
102
+
103
+ const height = surfaceRef.current?.offsetHeight ?? 0
104
+ if (height > 0) setPageHeight((prev) => (prev === height ? prev : height))
61
105
  }
62
106
 
63
- recompute()
64
- const ro = new ResizeObserver(recompute)
65
- ro.observe(container)
107
+ measure()
108
+
109
+ const ro = new ResizeObserver(measure)
110
+ if (sentinelRef.current) ro.observe(sentinelRef.current)
66
111
  if (surfaceRef.current) ro.observe(surfaceRef.current)
67
112
  return () => ro.disconnect()
68
- }, [vp.width, sections])
113
+ })
69
114
 
70
115
  // Scroll the selected section into view within the canvas.
71
116
  useEffect(() => {
@@ -74,28 +119,70 @@ export function EditorCanvas({
74
119
  if (el) el.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
75
120
  }, [selectedId])
76
121
 
122
+ const scale = fitScale(available, bp.width, zoom)
123
+
124
+ useEffect(() => {
125
+ onScaleChange?.(scale)
126
+ }, [scale, onScaleChange])
127
+
77
128
  return (
78
- <div ref={containerRef} className="bg-muted h-full overflow-auto p-6">
129
+ <div className="prenta-canvas-scroll bg-muted h-full overflow-auto px-6 pt-4.5 pb-10 text-center">
130
+ {/*
131
+ * Zero-height sentinel. Its offsetWidth IS the usable width — it is
132
+ * subject to exactly the same padding, scrollbar and host scaling as the
133
+ * canvas, so there is no arithmetic to get wrong. Must stay the first
134
+ * child and must stay zero-height.
135
+ */}
136
+ <div ref={sentinelRef} aria-hidden className="h-0" />
137
+
79
138
  {sections.length === 0 ? (
80
- <EmptyCanvas onAddSection={onAddSection} />
139
+ <EmptyCanvas />
81
140
  ) : (
82
141
  <>
83
- <StructureNotice
84
- structuralTypes={structuralTypes}
85
- sitePreviewAvailable={sitePreviewAvailable}
86
- />
142
+ {/* The review bar REPLACES the editing chrome rather than joining it:
143
+ a tip about clicking sections to edit them is actively wrong while
144
+ the canvas is showing a version you cannot edit. */}
145
+ {reviewing ? (
146
+ reviewBar
147
+ ) : (
148
+ <>
149
+ <CanvasEditTip />
150
+ <StructureNotice
151
+ structuralTypes={structuralTypes}
152
+ sitePreviewAvailable={sitePreviewAvailable}
153
+ />
154
+ </>
155
+ )}
156
+ <CanvasMetaLine breakpoint={bp} pageHeight={pageHeight} scale={scale} />
157
+
158
+ {/*
159
+ * Fit box: reserves the scaled footprint so the surrounding scroll
160
+ * area sizes correctly against a transformed child. Deliberately has
161
+ * NO width/height transition — a transition frozen mid-flight (a
162
+ * preview that is not visible never finishes one) reports a bogus
163
+ * height and corrupts the next measurement.
164
+ */}
87
165
  <div
88
- className="mx-auto"
89
- style={{ width: vp.width * scale, height: surfaceHeight ?? undefined }}
166
+ className="prenta-canvas-fit mx-auto block"
167
+ style={{
168
+ width: Math.round(bp.width * scale),
169
+ height: pageHeight ? Math.round(pageHeight * scale) : undefined,
170
+ }}
90
171
  >
91
172
  {/* `prenta-canvas` is the public hook for consumer brand CSS:
92
173
  site styles that should render in this preview scope to
93
174
  `.prenta-admin .prenta-canvas` instead of the admin root. */}
94
175
  <div
95
- ref={surfaceRef}
96
- className="prenta-canvas border-border bg-card origin-top overflow-hidden rounded-xl border shadow-sm"
176
+ ref={(el) => {
177
+ surfaceRef.current = el
178
+ onCanvasElement?.(el)
179
+ }}
180
+ // `prenta-canvas` carries `container-type: inline-size` (theme.css)
181
+ // — that is what makes the `@pv-*` steps in the section renderers
182
+ // resolve against the simulated width instead of the viewport.
183
+ className="prenta-canvas border-border bg-card origin-top-left overflow-hidden rounded-lg text-left shadow-[0_2px_20px_rgba(0,0,0,0.12)] motion-safe:transition-[width,transform] motion-safe:duration-(--mo-slow) motion-safe:ease-(--ease)"
97
184
  style={{
98
- width: vp.width,
185
+ width: bp.width,
99
186
  transform: `scale(${scale})`,
100
187
  transformOrigin: 'top left',
101
188
  }}
@@ -105,6 +192,8 @@ export function EditorCanvas({
105
192
  key={section.id}
106
193
  section={section}
107
194
  editable
195
+ reviewing={reviewing}
196
+ changed={changedSectionIds?.has(section.id) ?? false}
108
197
  selected={section.id === selectedId}
109
198
  onSelect={onSelect}
110
199
  registerRef={registerRef}
@@ -118,25 +207,22 @@ export function EditorCanvas({
118
207
  )
119
208
  }
120
209
 
121
- function EmptyCanvas({ onAddSection }: { onAddSection: () => void }) {
210
+ /**
211
+ * Design-owned pages always ship the template's sections, so an empty canvas
212
+ * means the template resolved to nothing — a configuration problem, not an
213
+ * invitation to add a section. There is deliberately no "Add section" button.
214
+ */
215
+ function EmptyCanvas() {
122
216
  return (
123
217
  <div className="mx-auto flex h-full max-w-md flex-col items-center justify-center text-center">
124
218
  <div className="bg-card border-border mb-4 flex h-14 w-14 items-center justify-center rounded-full border">
125
219
  <LayoutTemplate className="text-muted-foreground h-6 w-6" aria-hidden />
126
220
  </div>
127
- <h2 className="text-foreground text-lg font-medium">This page has no sections yet</h2>
128
- <p className="text-muted-foreground mt-1 mb-5 text-sm">
129
- Add your first section to start building the page. You can reorder, hide, and edit sections
130
- at any time.
221
+ <h2 className="text-foreground text-lg font-medium">This template renders no sections</h2>
222
+ <p className="text-muted-foreground mt-1 text-sm">
223
+ Layout is design-owned sections come from the page's template in code. Check that the page
224
+ has a template assigned, or pick a different one in Page settings.
131
225
  </p>
132
- <button
133
- type="button"
134
- onClick={onAddSection}
135
- className="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors"
136
- >
137
- <Plus className="h-4 w-4" aria-hidden />
138
- Add Section
139
- </button>
140
226
  </div>
141
227
  )
142
228
  }
@@ -7,18 +7,16 @@ import {
7
7
  Eye,
8
8
  Globe,
9
9
  History,
10
- Laptop,
11
10
  Loader2,
12
- type LucideIcon,
13
- Monitor,
14
11
  Settings2,
15
- Smartphone,
16
- Tablet,
17
12
  TriangleAlert,
18
13
  } from 'lucide-react'
19
14
  import { EditorSeoScoreBadge } from '../../components/seo/EditorSeoScoreBadge.js'
15
+ import { BreakpointPicker } from '../../components/BreakpointPicker.js'
16
+ import { ZoomChip } from '../../components/ZoomChip.js'
20
17
  import type { PageStatus } from '../../lib/page-editor-service.js'
21
- import { VIEWPORTS, type ViewportId } from './viewports.js'
18
+ import type { Zoom } from '../../lib/breakpoints.js'
19
+ import { type ViewportId } from './viewports.js'
22
20
 
23
21
  export type SaveState = 'idle' | 'saving' | 'saved' | 'error'
24
22
 
@@ -35,6 +33,11 @@ interface EditorTopBarProps {
35
33
  /** Shown on hover/focus when publish is blocked by validation (not role). */
36
34
  publishDisabledReason?: string
37
35
  viewport: ViewportId
36
+ /** Canvas zoom mode; omit to hide the zoom chip (e.g. the site-preview iframe). */
37
+ zoom?: Zoom
38
+ /** Scale the canvas actually measured, 0–1 — displayed by the zoom chip. */
39
+ canvasScale?: number
40
+ onZoom?: (zoom: Zoom) => void
38
41
  /** Breadcrumb root label + back-button text (e.g. "Pages" or "Posts"). */
39
42
  backLabel?: string
40
43
  onViewport: (v: ViewportId) => void
@@ -47,10 +50,16 @@ interface EditorTopBarProps {
47
50
  */
48
51
  onViewOnSite?: () => void
49
52
  /**
50
- * Open the version history panel. When omitted the History button is
53
+ * Toggle the version history panel. When omitted the History button is
51
54
  * hidden — e.g. for unsaved documents that have no versions yet.
52
55
  */
53
56
  onHistory?: () => void
57
+ /**
58
+ * Whether history is showing. History takes over the rail rather than
59
+ * opening a dialog, so the button needs a pressed state — without one there
60
+ * is nothing in the chrome saying which mode the editor is in.
61
+ */
62
+ historyOpen?: boolean
54
63
  /** Whether the inline site preview (iframe of the public site) is showing. */
55
64
  sitePreview?: boolean
56
65
  /**
@@ -63,7 +72,14 @@ interface EditorTopBarProps {
63
72
  onOpenSeo?: () => void
64
73
  seoOpen?: boolean
65
74
  /** Live 0–100 SEO score shown left of the SEO label. */
75
+ /**
76
+ * 0-100 for the header chip. `undefined` means not known yet — the chip
77
+ * renders without a number rather than defaulting to 0, which would read as
78
+ * a catastrophic score for a page nobody has audited.
79
+ */
66
80
  seoScore?: number
81
+ /** Band for `seoScore`; omit to derive from the content-analysis scale. */
82
+ seoScoreBand?: 'good' | 'fair' | 'poor'
67
83
  onSaveDraft: () => void
68
84
  onPublish: () => void
69
85
  /** Open the schedule-publish dialog. Omitted when the document is unsaved. */
@@ -81,13 +97,6 @@ interface EditorTopBarProps {
81
97
  structuralTypes?: string[]
82
98
  }
83
99
 
84
- const VIEWPORT_ICONS: Record<string, LucideIcon> = {
85
- monitor: Monitor,
86
- laptop: Laptop,
87
- tablet: Tablet,
88
- smartphone: Smartphone,
89
- }
90
-
91
100
  const STATUS_TEXT: Record<PageStatus, { label: string; className: string }> = {
92
101
  DRAFT: { label: 'Draft', className: 'text-warning dark:text-amber-400' },
93
102
  PUBLISHED: { label: 'Published', className: 'text-emerald-600 dark:text-emerald-400' },
@@ -106,18 +115,23 @@ export function EditorTopBar({
106
115
  publishReady = true,
107
116
  publishDisabledReason,
108
117
  viewport,
118
+ zoom,
119
+ canvasScale,
120
+ onZoom,
109
121
  backLabel = 'Pages',
110
122
  onViewport,
111
123
  onBack,
112
124
  onPreview,
113
125
  onViewOnSite,
114
126
  onHistory,
127
+ historyOpen = false,
115
128
  sitePreview = false,
116
129
  onToggleSitePreview,
117
130
  onOpenSettings,
118
131
  onOpenSeo,
119
132
  seoOpen = false,
120
- seoScore = 0,
133
+ seoScore,
134
+ seoScoreBand,
121
135
  onSaveDraft,
122
136
  onPublish,
123
137
  onSchedule,
@@ -170,7 +184,7 @@ export function EditorTopBar({
170
184
  : 'Schedule a future publish date'
171
185
 
172
186
  return (
173
- <header className="bg-card border-border flex h-14 shrink-0 items-center justify-between gap-4 border-b px-4">
187
+ <header className="prenta-editor-header bg-card border-border flex h-14 shrink-0 items-center justify-between gap-4 border-b px-4">
174
188
  {/* Breadcrumb + status */}
175
189
  <div className="flex min-w-0 items-center gap-2">
176
190
  <nav aria-label="Breadcrumb" className="flex min-w-0 items-center gap-1.5 text-sm">
@@ -209,32 +223,11 @@ export function EditorTopBar({
209
223
 
210
224
  {/* Right controls */}
211
225
  <div className="flex items-center gap-2">
212
- <div
213
- className="border-border bg-background hidden items-center gap-0.5 rounded-lg border p-0.5 md:flex"
214
- role="group"
215
- aria-label="Preview viewport"
216
- >
217
- {VIEWPORTS.map((v) => {
218
- const Icon = VIEWPORT_ICONS[v.icon] ?? Monitor
219
- const active = v.id === viewport
220
- return (
221
- <button
222
- key={v.id}
223
- type="button"
224
- onClick={() => onViewport(v.id)}
225
- aria-pressed={active}
226
- title={`${v.label} (${v.width}px)`}
227
- className={`flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium transition-colors ${
228
- active
229
- ? 'bg-primary text-primary-foreground'
230
- : 'text-muted-foreground hover:text-foreground hover:bg-accent'
231
- }`}
232
- >
233
- <Icon className="h-3.5 w-3.5" aria-hidden />
234
- <span className="hidden lg:inline">{v.label}</span>
235
- </button>
236
- )
237
- })}
226
+ <div className="hidden items-center gap-1.5 md:flex">
227
+ <BreakpointPicker value={viewport} onChange={onViewport} />
228
+ {zoom !== undefined && onZoom && (
229
+ <ZoomChip zoom={zoom} scale={canvasScale ?? 1} onChange={onZoom} />
230
+ )}
238
231
  </div>
239
232
 
240
233
  <button
@@ -242,7 +235,7 @@ export function EditorTopBar({
242
235
  onClick={onOpenSettings}
243
236
  aria-label="Page settings"
244
237
  title="Page settings"
245
- className="text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
238
+ className="prenta-touch-target text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
246
239
  >
247
240
  <Settings2 className="h-4 w-4" aria-hidden />
248
241
  </button>
@@ -252,15 +245,21 @@ export function EditorTopBar({
252
245
  type="button"
253
246
  onClick={onOpenSeo}
254
247
  aria-pressed={seoOpen}
255
- aria-label={`SEO, score ${seoScore} out of 100`}
256
- title={`SEO — score ${seoScore}/100. Meta tags, social preview, schema, and analysis.`}
248
+ aria-label={seoScore === undefined ? 'SEO' : `SEO, score ${seoScore} out of 100`}
249
+ title={
250
+ seoScore === undefined
251
+ ? 'SEO — meta tags, social preview, schema, and analysis.'
252
+ : `SEO — score ${seoScore}/100. Meta tags, social preview, schema, and analysis.`
253
+ }
257
254
  className={`inline-flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-sm font-medium transition-colors ${
258
255
  seoOpen
259
256
  ? 'bg-primary text-primary-foreground'
260
257
  : 'text-muted-foreground hover:text-foreground hover:bg-accent'
261
258
  }`}
262
259
  >
263
- <EditorSeoScoreBadge score={seoScore} inverted={seoOpen} />
260
+ {seoScore !== undefined && (
261
+ <EditorSeoScoreBadge score={seoScore} band={seoScoreBand} inverted={seoOpen} />
262
+ )}
264
263
  <span className="hidden sm:inline">SEO</span>
265
264
  </button>
266
265
  )}
@@ -269,9 +268,14 @@ export function EditorTopBar({
269
268
  <button
270
269
  type="button"
271
270
  onClick={onHistory}
271
+ aria-pressed={historyOpen}
272
272
  aria-label="Version history"
273
- title="Version history"
274
- className="text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
273
+ title={historyOpen ? 'Close version history' : 'Version history'}
274
+ className={`prenta-touch-target rounded-lg p-2 transition-colors ${
275
+ historyOpen
276
+ ? 'bg-primary text-primary-foreground'
277
+ : 'text-muted-foreground hover:text-foreground hover:bg-accent'
278
+ }`}
275
279
  >
276
280
  <History className="h-4 w-4" aria-hidden />
277
281
  </button>
@@ -282,7 +286,7 @@ export function EditorTopBar({
282
286
  onClick={onPreview}
283
287
  aria-label={previewLabel}
284
288
  title={previewLabel}
285
- className="text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
289
+ className="prenta-touch-target text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
286
290
  >
287
291
  <Eye className="h-4 w-4" aria-hidden />
288
292
  </button>
@@ -298,7 +302,7 @@ export function EditorTopBar({
298
302
  ? 'Back to editor canvas'
299
303
  : 'Inline site preview — render the draft through your public site, in place'
300
304
  }
301
- className={`rounded-lg p-2 transition-colors ${
305
+ className={`prenta-touch-target rounded-lg p-2 transition-colors ${
302
306
  sitePreview
303
307
  ? 'bg-primary text-primary-foreground'
304
308
  : 'text-muted-foreground hover:text-foreground hover:bg-accent'
@@ -329,7 +333,7 @@ export function EditorTopBar({
329
333
  onClick={onViewOnSite}
330
334
  aria-label={isLive ? 'View live page' : 'View draft on site'}
331
335
  title={isLive ? 'View live page' : 'View draft on site'}
332
- className="text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
336
+ className="prenta-touch-target text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg p-2"
333
337
  >
334
338
  <ExternalLink className="h-4 w-4" aria-hidden />
335
339
  </button>