@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
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Check, ImageIcon, Trash2 } from 'lucide-react';
5
+ import { useApiData } from '../lib/useApiData.js';
6
+ import { CROP_RATIO, assetWash, displayName, formatBadge, ratioLabel, } from '../lib/media-format.js';
7
+ /**
8
+ * One component for every image — section slots and the social/OG card alike.
9
+ *
10
+ * ── The frame shows the TEMPLATE's crop, not the asset's ─────────────────
11
+ *
12
+ * A section image renders at 16:10 and a social card at 1.91:1 regardless of
13
+ * what was uploaded. Framing the asset's own ratio would tell an editor their
14
+ * portrait photo looks fine and then crop its subject out on the page. What
15
+ * the asset actually is gets reported in the toolbar instead, as a ratio label
16
+ * beside its filename, so both facts are visible and neither is implied.
17
+ *
18
+ * ── The toolbar is always visible ────────────────────────────────────────
19
+ *
20
+ * Never hover-only. Replace and Remove are the two things an editor comes here
21
+ * to do, and hiding them behind a hover makes them undiscoverable on touch and
22
+ * invisible to anyone scanning the panel.
23
+ *
24
+ * ── The picker opens inside the shell ────────────────────────────────────
25
+ *
26
+ * Not a modal. Choosing an image is a comparison against the slot it is going
27
+ * into, and a dialog covering the slot removes the only context that matters.
28
+ */
29
+ export function MediaBlock({ value, onChange, crop = 'section', children, disabled = false, label = 'Image', }) {
30
+ const [picking, setPicking] = useState(false);
31
+ const { data } = useApiData(picking ? '/media?pageSize=50' : null);
32
+ const items = (Array.isArray(data) ? data : (data?.items ?? [])).filter((i) => i.mimeType?.startsWith('image/'));
33
+ const ratio = CROP_RATIO[crop];
34
+ const name = value ? displayName(value) : '';
35
+ return (_jsxs("div", { className: "border-border bg-card overflow-hidden rounded-[10px] border", children: [value ? (_jsx("div", { className: "w-full bg-cover bg-center", style: { aspectRatio: ratio, backgroundImage: assetWash(name) }, children: _jsx("img", { src: value, alt: "", className: "h-full w-full object-cover", style: { aspectRatio: ratio } }) })) : (_jsx("button", { type: "button", onClick: () => setPicking(true), disabled: disabled, "aria-label": `Choose ${label.toLowerCase()}`, className: "bg-muted hover:bg-accent group flex w-full items-center justify-center p-3 transition-colors disabled:opacity-50", style: { aspectRatio: ratio }, children: _jsxs("span", { className: "border-border group-hover:border-primary group-hover:text-primary text-muted-foreground flex h-full w-full flex-col items-center justify-center gap-1.5 rounded-lg border-[1.5px] border-dashed transition-colors", children: [_jsx(ImageIcon, { size: 22, "aria-hidden": true }), _jsx("span", { className: "text-foreground text-[12.5px] font-semibold", children: "No image selected" }), _jsx("span", { className: "text-[10.5px]", children: "Choose one from the library" })] }) })), children, _jsx("div", { className: "border-border flex items-center gap-2 border-t px-2.5 py-2", children: value ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-foreground min-w-0 flex-1 truncate text-[11.5px] font-semibold", title: name, children: name }), _jsx("span", { className: "text-muted-foreground shrink-0 text-[10.5px] tabular-nums", children: formatBadge(value) }), _jsx("button", { type: "button", onClick: () => setPicking((v) => !v), disabled: disabled, className: "border-border hover:bg-accent shrink-0 rounded-md border px-2 py-1 text-[11px] font-medium disabled:opacity-50", children: "Replace" }), _jsx("button", { type: "button", onClick: () => onChange(''), disabled: disabled, "aria-label": `Remove ${label.toLowerCase()}`, className: "text-muted-foreground hover:text-destructive shrink-0 rounded p-1 disabled:opacity-50", children: _jsx(Trash2, { size: 13, "aria-hidden": true }) })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-muted-foreground min-w-0 flex-1 text-[11.5px]", children: "No image selected" }), _jsx("button", { type: "button", onClick: () => setPicking((v) => !v), disabled: disabled, className: "border-border hover:bg-accent shrink-0 rounded-md border px-2 py-1 text-[11px] font-medium disabled:opacity-50", children: "Choose" })] })) }), picking && (_jsx("div", { className: "border-border bg-muted max-h-[262px] overflow-y-auto border-t p-2", children: items.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-1 py-3 text-center text-[11px]", children: "No images in the library yet." })) : (_jsx("ul", { className: "grid grid-cols-2 gap-2", children: items.map((item) => {
36
+ const url = item.url || item.storageKey;
37
+ const selected = url === value;
38
+ const itemRatio = ratioLabel(item.width, item.height);
39
+ return (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => {
40
+ onChange(url, item);
41
+ setPicking(false);
42
+ }, "aria-current": selected || undefined, className: `border-border bg-card w-full overflow-hidden rounded-lg border text-left transition-colors ${selected ? 'border-primary' : 'hover:border-ring'}`, children: [_jsxs("span", { className: "relative block w-full", style: {
43
+ aspectRatio: '16 / 10',
44
+ backgroundImage: assetWash(item.filename),
45
+ }, children: [url && _jsx("img", { src: url, alt: "", className: "h-full w-full object-cover" }), _jsx("span", { className: "absolute top-1 left-1 rounded-[5px] bg-white/80 px-1.5 py-px text-[9.5px] font-extrabold tracking-wide text-zinc-800", children: formatBadge(item.filename, item.mimeType) }), selected && (_jsx("span", { className: "bg-primary text-primary-foreground absolute top-1 right-1 flex h-4 w-4 items-center justify-center rounded-full", children: _jsx(Check, { size: 10, "aria-hidden": true }) }))] }), _jsxs("span", { className: "block px-1.5 py-1", children: [_jsx("span", { className: "text-foreground block truncate text-[10px] font-semibold", children: item.filename }), _jsx("span", { className: "text-muted-foreground block text-[9px] tabular-nums", children: item.width && item.height
46
+ ? `${item.width} × ${item.height}${itemRatio ? ` · ${itemRatio}` : ''}`
47
+ : 'Dimensions unknown' })] })] }) }, item.id));
48
+ }) })) }))] }));
49
+ }
50
+ //# sourceMappingURL=MediaBlock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaBlock.js","sourceRoot":"","sources":["../../src/components/MediaBlock.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type BreakpointId } from '../lib/breakpoints.js';
2
+ import type { ReflowGuardResult } from '../hooks/useReflowGuard.js';
3
+ export interface ReflowMeterProps {
4
+ guard: ReflowGuardResult;
5
+ /** Character count of the current value. */
6
+ length: number;
7
+ /** Breakpoint the canvas is currently showing — marked in the row of dots. */
8
+ device: BreakpointId;
9
+ /** Switch the canvas to a breakpoint so the editor can look at the damage. */
10
+ onProof: (id: BreakpointId) => void;
11
+ }
12
+ /**
13
+ * Per-field reflow readout: character count, line count where you're looking,
14
+ * one dot per breakpoint, and a proof prompt when wrapping changed.
15
+ *
16
+ * ── Why the dots are buttons ──────────────────────────────────────────────
17
+ *
18
+ * The guard's whole value is that it reports damage at a width you are NOT
19
+ * looking at. Telling an editor "this now runs three lines on mobile" while
20
+ * making them hunt for the breakpoint switcher wastes the finding. Each dot
21
+ * takes the canvas there.
22
+ *
23
+ * Colour is never the only signal: every dot carries its breakpoint's initials
24
+ * and an accessible name stating the line count and what it was published at,
25
+ * and the alert below repeats the finding in words.
26
+ */
27
+ export declare function ReflowMeter({ guard, length, device, onProof }: ReflowMeterProps): import("react/jsx-runtime").JSX.Element;
28
+ //# sourceMappingURL=ReflowMeter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReflowMeter.d.ts","sourceRoot":"","sources":["../../src/components/ReflowMeter.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAEnE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,iBAAiB,CAAA;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,MAAM,EAAE,YAAY,CAAA;IACpB,8EAA8E;IAC9E,OAAO,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAA;CACpC;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAuF/E"}
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { AlertTriangle } from 'lucide-react';
4
+ import { BREAKPOINTS, getBreakpoint } from '../lib/breakpoints.js';
5
+ const DOT_TONE = {
6
+ same: 'bg-success/12 text-success',
7
+ grew: 'bg-warning/15 text-warning',
8
+ 'grew-badly': 'bg-destructive/12 text-destructive',
9
+ };
10
+ /**
11
+ * Per-field reflow readout: character count, line count where you're looking,
12
+ * one dot per breakpoint, and a proof prompt when wrapping changed.
13
+ *
14
+ * ── Why the dots are buttons ──────────────────────────────────────────────
15
+ *
16
+ * The guard's whole value is that it reports damage at a width you are NOT
17
+ * looking at. Telling an editor "this now runs three lines on mobile" while
18
+ * making them hunt for the breakpoint switcher wastes the finding. Each dot
19
+ * takes the canvas there.
20
+ *
21
+ * Colour is never the only signal: every dot carries its breakpoint's initials
22
+ * and an accessible name stating the line count and what it was published at,
23
+ * and the alert below repeats the finding in words.
24
+ */
25
+ export function ReflowMeter({ guard, length, device, onProof }) {
26
+ const here = guard.rows.find((r) => r.id === device);
27
+ const worst = guard.worst ? guard.rows.find((r) => r.id === guard.worst) : undefined;
28
+ // Named breakpoints while the list is short enough to read; initials once it
29
+ // isn't; "every breakpoint" when it's all of them, which is shorter and is
30
+ // also the more useful statement.
31
+ const grown = guard.grown;
32
+ const scope = grown.length === BREAKPOINTS.length
33
+ ? 'every breakpoint'
34
+ : grown.length > 3
35
+ ? grown.map((r) => getBreakpoint(r.id).abbr).join(', ')
36
+ : grown.map((r) => getBreakpoint(r.id).name).join(', ');
37
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mt-1.5 flex items-center gap-2", children: [_jsxs("span", { className: "text-muted-foreground text-[11px] whitespace-nowrap tabular-nums", children: [_jsx("b", { className: "text-foreground/80 font-semibold", children: length }), " chars", guard.delta !== 0 && (_jsxs("span", { className: guard.delta > 0 ? 'text-warning font-bold' : '', children: [' ', "(", guard.delta > 0 ? '+' : '', guard.delta, ")"] })), here && (_jsxs(_Fragment, { children: [' · ', _jsx("b", { className: "text-foreground/80 font-semibold", children: here.lines }), " line", here.lines === 1 ? '' : 's', " here"] }))] }), guard.rows.length > 0 && (_jsx("div", { className: "ml-auto flex gap-0.75", children: guard.rows.map((row) => {
38
+ const bp = getBreakpoint(row.id);
39
+ return (_jsxs("button", { type: "button", onClick: () => onProof(row.id), className: `flex h-4.25 w-4.25 items-center justify-center rounded-[5px] text-[8px] font-bold transition-transform hover:-translate-y-px ${DOT_TONE[row.state] ?? 'bg-muted text-muted-foreground'} ${device === row.id ? 'outline-primary outline-[1.5px] outline-offset-1' : ''}`, title: `${bp.name} — ${row.lines} line${row.lines === 1 ? '' : 's'}${row.diff > 0 ? ` (published: ${row.was}) — wrapping changed` : ''}. Click to proof.`, children: [_jsx("span", { "aria-hidden": true, children: bp.abbr }), _jsxs("span", { className: "sr-only", children: [bp.name, ": ", row.lines, " line", row.lines === 1 ? '' : 's', row.diff > 0 ? `, was ${row.was} when published` : '', " \u2014 proof here"] })] }, row.id));
40
+ }) }))] }), worst && (_jsxs("div", { className: "bg-warning/10 border-warning/30 mt-1.5 grid grid-cols-[auto_1fr] gap-x-2.5 gap-y-1 rounded-lg border p-2.5", children: [_jsx(AlertTriangle, { size: 14, className: "text-warning mt-px shrink-0", "aria-hidden": true }), _jsxs("p", { className: "text-[11.5px] leading-normal", children: ["Wrapping changed on ", _jsx("b", { className: "text-warning font-bold", children: scope }), " \u2014", ' ', getBreakpoint(worst.id).name, " now runs ", worst.lines, " lines instead of ", worst.was, ". Proof it before publishing."] }), _jsxs("button", { type: "button", onClick: () => onProof(worst.id), className: "border-warning text-warning hover:bg-warning/15 col-start-2 mt-0.5 justify-self-start rounded-md border px-2.5 py-1 text-[11px] font-semibold whitespace-nowrap transition-colors", children: ["Proof on ", getBreakpoint(worst.id).name] })] }))] }));
41
+ }
42
+ //# sourceMappingURL=ReflowMeter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReflowMeter.js","sourceRoot":"","sources":["../../src/components/ReflowMeter.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Zoom } from '../lib/breakpoints.js';
2
+ export interface ZoomChipProps {
3
+ /** Current zoom mode. */
4
+ zoom: Zoom;
5
+ /** Actual rendered scale, 0–1 — what the canvas measured, not the mode. */
6
+ scale: number;
7
+ onChange: (zoom: Zoom) => void;
8
+ }
9
+ /**
10
+ * Reads out the canvas scale and toggles fit ↔ 100%.
11
+ *
12
+ * It shows the *measured* scale rather than the mode, because "fit" is not a
13
+ * number an editor can reason about — at 1920px in a narrow rail it might be
14
+ * 38%, and that is the fact that explains why the preview looks small.
15
+ */
16
+ export declare function ZoomChip({ zoom, scale, onChange }: ZoomChipProps): import("react/jsx-runtime").JSX.Element;
17
+ //# sourceMappingURL=ZoomChip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZoomChip.d.ts","sourceRoot":"","sources":["../../src/components/ZoomChip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAEjD,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,IAAI,EAAE,IAAI,CAAA;IACV,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,aAAa,2CAmBhE"}
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+ import { jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Reads out the canvas scale and toggles fit ↔ 100%.
5
+ *
6
+ * It shows the *measured* scale rather than the mode, because "fit" is not a
7
+ * number an editor can reason about — at 1920px in a narrow rail it might be
8
+ * 38%, and that is the fact that explains why the preview looks small.
9
+ */
10
+ export function ZoomChip({ zoom, scale, onChange }) {
11
+ const percent = Math.round(scale * 100);
12
+ const next = zoom === 'fit' ? 1 : 'fit';
13
+ return (_jsxs("button", { type: "button", onClick: () => onChange(next), "aria-label": zoom === 'fit'
14
+ ? `Canvas scaled to ${percent} percent to fit. Switch to actual size.`
15
+ : 'Canvas at actual size. Switch to fit.', title: zoom === 'fit' ? 'Fit to window — click for 100%' : 'Actual size — click to fit', className: "border-border bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground h-[34px] min-w-[54px] rounded-lg border px-2 text-[11.5px] font-semibold tabular-nums transition-colors", children: [percent, "%"] }));
16
+ }
17
+ //# sourceMappingURL=ZoomChip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZoomChip.js","sourceRoot":"","sources":["../../src/components/ZoomChip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAYZ;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAiB;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAA;IACvC,MAAM,IAAI,GAAS,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAE7C,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAE3B,IAAI,KAAK,KAAK;YACZ,CAAC,CAAC,oBAAoB,OAAO,yCAAyC;YACtE,CAAC,CAAC,uCAAuC,EAE7C,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,4BAA4B,EACvF,SAAS,EAAC,wMAAwM,aAEjN,OAAO,SACD,CACV,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type LucideIcon } from 'lucide-react';
2
+ export declare function breakpointIcon(name: string): LucideIcon;
3
+ //# sourceMappingURL=breakpoint-icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breakpoint-icons.d.ts","sourceRoot":"","sources":["../../src/components/breakpoint-icons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAcnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEvD"}
@@ -0,0 +1,16 @@
1
+ import { Laptop, Monitor, Smartphone, Tablet } from 'lucide-react';
2
+ /**
3
+ * Maps a breakpoint's `icon` name to its component. Kept out of
4
+ * `lib/breakpoints.ts` so that module stays free of React imports — it is pure
5
+ * data and arithmetic, and its tests run without a DOM.
6
+ */
7
+ const ICONS = {
8
+ monitor: Monitor,
9
+ laptop: Laptop,
10
+ tablet: Tablet,
11
+ smartphone: Smartphone,
12
+ };
13
+ export function breakpointIcon(name) {
14
+ return ICONS[name] ?? Monitor;
15
+ }
16
+ //# sourceMappingURL=breakpoint-icons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breakpoint-icons.js","sourceRoot":"","sources":["../../src/components/breakpoint-icons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAmB,MAAM,cAAc,CAAA;AAEnF;;;;GAIG;AACH,MAAM,KAAK,GAA+B;IACxC,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,UAAU,EAAE,UAAU;CACvB,CAAA;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO,CAAA;AAC/B,CAAC"}
@@ -0,0 +1,31 @@
1
+ export interface AuthorValue {
2
+ /** Displayed byline. Empty means no byline is set. */
3
+ name: string;
4
+ /** CMS user id, when the byline is one. Empty for generic and guest. */
5
+ id: string;
6
+ }
7
+ export interface AuthorPickerProps {
8
+ value: AuthorValue;
9
+ onChange: (next: AuthorValue) => void;
10
+ /** Brand byline offered under GENERIC — usually the site or org name. */
11
+ brandName?: string;
12
+ disabled?: boolean;
13
+ }
14
+ /**
15
+ * Byline picker: a CMS user, the brand, or a one-off guest name.
16
+ *
17
+ * ── What this does and does not change ────────────────────────────────────
18
+ *
19
+ * It sets the page's DISPLAYED author, which reaches the page's structured
20
+ * data. It does not reassign the document's `createdById` — that records who
21
+ * created the record, and trading an audit trail for a label is not a swap
22
+ * worth making silently. A page written by a staff editor and bylined to the
23
+ * brand is a normal thing; a page whose history says someone else made it is
24
+ * not.
25
+ *
26
+ * The menu renders inline below the trigger rather than floating. The rail is
27
+ * narrow and scrollable, and a floating menu inside a scroll container either
28
+ * clips or detaches from its trigger on scroll.
29
+ */
30
+ export declare function AuthorPicker({ value, onChange, brandName, disabled }: AuthorPickerProps): import("react/jsx-runtime").JSX.Element;
31
+ //# sourceMappingURL=AuthorPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthorPicker.d.ts","sourceRoot":"","sources":["../../../src/components/page-tab/AuthorPicker.tsx"],"names":[],"mappings":"AAaA,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAA;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,CAAA;IAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IACrC,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAgB,EAAE,EAAE,iBAAiB,2CAwH/F"}
@@ -0,0 +1,95 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { ChevronDown, Globe } from 'lucide-react';
5
+ import { cmsApi } from '../../lib/api.js';
6
+ /**
7
+ * Byline picker: a CMS user, the brand, or a one-off guest name.
8
+ *
9
+ * ── What this does and does not change ────────────────────────────────────
10
+ *
11
+ * It sets the page's DISPLAYED author, which reaches the page's structured
12
+ * data. It does not reassign the document's `createdById` — that records who
13
+ * created the record, and trading an audit trail for a label is not a swap
14
+ * worth making silently. A page written by a staff editor and bylined to the
15
+ * brand is a normal thing; a page whose history says someone else made it is
16
+ * not.
17
+ *
18
+ * The menu renders inline below the trigger rather than floating. The rail is
19
+ * narrow and scrollable, and a floating menu inside a scroll container either
20
+ * clips or detaches from its trigger on scroll.
21
+ */
22
+ export function AuthorPicker({ value, onChange, brandName, disabled = false }) {
23
+ const [open, setOpen] = useState(false);
24
+ const [users, setUsers] = useState([]);
25
+ const [guest, setGuest] = useState('');
26
+ useEffect(() => {
27
+ if (!open || users.length > 0)
28
+ return;
29
+ let cancelled = false;
30
+ cmsApi('/users').then((res) => {
31
+ if (cancelled || !res.data)
32
+ return;
33
+ const list = Array.isArray(res.data) ? res.data : (res.data.users ?? []);
34
+ setUsers(list);
35
+ });
36
+ return () => {
37
+ cancelled = true;
38
+ };
39
+ }, [open, users.length]);
40
+ const isGeneric = Boolean(brandName) && value.name === brandName && !value.id;
41
+ const label = value.name || 'No byline';
42
+ const sub = value.id
43
+ ? (users.find((u) => u.id === value.id)?.role ?? 'CMS user')
44
+ : isGeneric
45
+ ? 'Brand byline'
46
+ : value.name
47
+ ? 'Guest byline'
48
+ : 'None set';
49
+ function pick(next) {
50
+ onChange(next);
51
+ setOpen(false);
52
+ }
53
+ return (_jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), disabled: disabled, "aria-expanded": open, className: "border-border bg-card hover:border-ring flex w-full items-center gap-2.5 rounded-[7px] border-[1.5px] px-2.5 py-[7px] text-left transition-colors disabled:opacity-50", children: [_jsx(Avatar, { name: value.name, generic: isGeneric }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "text-foreground block truncate text-[12.5px] font-semibold", children: label }), _jsx("span", { className: "text-muted-foreground block text-[10.5px]", children: sub })] }), _jsx(ChevronDown, { size: 14, "aria-hidden": true, className: `text-muted-foreground shrink-0 motion-safe:transition-transform ${open ? 'rotate-180' : ''}` })] }), open && (_jsxs("div", { className: "border-border mt-1.5 space-y-2 rounded-[9px] border p-2", children: [_jsx(Group, { label: "CMS users", children: users.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-1 py-1.5 text-[11px]", children: "Loading\u2026" })) : (users.map((u) => {
54
+ const name = u.name || u.email || 'Unnamed user';
55
+ return (_jsxs(Row, { selected: value.id === u.id, onClick: () => pick({ name, id: u.id }), children: [_jsx(Avatar, { name: name }), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "block truncate text-[12px] font-medium", children: name }), _jsx("span", { className: "text-muted-foreground block text-[10px]", children: u.role ?? 'Author' })] })] }, u.id));
56
+ })) }), brandName && (_jsx(Group, { label: "Generic", children: _jsxs(Row, { selected: isGeneric, onClick: () => pick({ name: brandName, id: '' }), children: [_jsx(Avatar, { name: brandName, generic: true }), _jsx("span", { className: "text-[12px] font-medium", children: brandName })] }) })), _jsx(Group, { label: "Guest byline", children: _jsxs("div", { className: "flex gap-1.5 px-1", children: [_jsx("input", { value: guest, onChange: (e) => setGuest(e.target.value), placeholder: "Name to display", "aria-label": "Guest byline name", className: "border-border bg-input-background focus-visible:border-ring min-w-0 flex-1 rounded-md border px-2 py-1 text-[11.5px] focus-visible:outline-none" }), _jsx("button", { type: "button",
57
+ // Disabled until non-empty: an empty guest byline would clear
58
+ // the author while looking like it set one.
59
+ disabled: guest.trim().length === 0, onClick: () => {
60
+ pick({ name: guest.trim(), id: '' });
61
+ setGuest('');
62
+ }, className: "bg-primary text-primary-foreground rounded-md px-2 py-1 text-[11px] font-semibold disabled:opacity-40", children: "Add" })] }) })] }))] }));
63
+ }
64
+ function Group({ label, children }) {
65
+ return (_jsxs("div", { children: [_jsx("p", { className: "text-muted-foreground px-1 pb-1 text-[9.5px] font-bold tracking-wide uppercase", children: label }), _jsx("div", { className: "space-y-0.5", children: children })] }));
66
+ }
67
+ function Row({ selected, onClick, children, }) {
68
+ return (_jsx("button", { type: "button", onClick: onClick, "aria-current": selected || undefined, className: `flex w-full items-center gap-2 rounded-md px-1.5 py-1.5 text-left transition-colors ${selected ? 'bg-accent' : 'hover:bg-accent/60'}`, children: children }));
69
+ }
70
+ /**
71
+ * Initials on a tint derived from the name, so the same person is the same
72
+ * colour everywhere without storing one. A globe replaces initials for the
73
+ * brand byline — "Ex" for "Example Inc" reads as a person, which is the one
74
+ * thing the generic option is not.
75
+ */
76
+ function Avatar({ name, generic = false }) {
77
+ if (generic) {
78
+ return (_jsx("span", { className: "bg-muted text-muted-foreground flex h-[27px] w-[27px] shrink-0 items-center justify-center rounded-full", children: _jsx(Globe, { size: 14, "aria-hidden": true }) }));
79
+ }
80
+ const initials = name
81
+ .trim()
82
+ .split(/\s+/)
83
+ .slice(0, 2)
84
+ .map((w) => w[0] ?? '')
85
+ .join('')
86
+ .toUpperCase() || '—';
87
+ let hash = 0;
88
+ for (let i = 0; i < name.length; i++)
89
+ hash = (hash * 31 + name.charCodeAt(i)) % 360;
90
+ return (_jsx("span", { "aria-hidden": true, className: "flex h-[27px] w-[27px] shrink-0 items-center justify-center rounded-full text-[10px] font-bold", style: {
91
+ backgroundColor: `oklch(0.92 0.05 ${hash})`,
92
+ color: `oklch(0.42 0.12 ${hash})`,
93
+ }, children: initials }));
94
+ }
95
+ //# sourceMappingURL=AuthorPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthorPicker.js","sourceRoot":"","sources":["../../../src/components/page-tab/AuthorPicker.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export interface DirectiveSwitchProps {
2
+ id: string;
3
+ /** Human label, e.g. "Show in search results". */
4
+ label: string;
5
+ /** One line on what turning it off actually costs. */
6
+ hint?: string;
7
+ /** `true` = permissive. */
8
+ checked: boolean;
9
+ onChange: (next: boolean) => void;
10
+ /** Directive token when permitted, e.g. `index`. */
11
+ permissiveToken: string;
12
+ /** Directive token when restricted, e.g. `noindex`. */
13
+ restrictiveToken: string;
14
+ disabled?: boolean;
15
+ }
16
+ /**
17
+ * A robots-directive switch.
18
+ *
19
+ * ── Why this is not the ordinary Toggle ───────────────────────────────────
20
+ *
21
+ * The admin's `Toggle` turns brand purple when on, because "on" is the state
22
+ * the product is nudging you towards. That reading is wrong here. These
23
+ * switches are not on/off, they are permissive/restrictive — and the meaningful
24
+ * distinction is not "did I enable something" but "is this page still allowed
25
+ * to be found". Purple would say "enabled" about a switch whose enabled state
26
+ * is simply the default, and say nothing about the one state worth noticing.
27
+ *
28
+ * So: green when permitted, red when restricted. And the literal directive
29
+ * token sits beside it, because the failure this UI has to prevent is an editor
30
+ * flipping something whose consequence they could not name. `noindex` next to
31
+ * the switch turns an abstract toggle into the thing it actually writes into
32
+ * the page's head.
33
+ *
34
+ * Colour never carries it alone — the token chip is text, and the switch's
35
+ * accessible name states the label and the token it will produce.
36
+ */
37
+ export declare function DirectiveSwitch({ id, label, hint, checked, onChange, permissiveToken, restrictiveToken, disabled, }: DirectiveSwitchProps): import("react/jsx-runtime").JSX.Element;
38
+ //# sourceMappingURL=DirectiveSwitch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DirectiveSwitch.d.ts","sourceRoot":"","sources":["../../../src/components/page-tab/DirectiveSwitch.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACjC,oDAAoD;IACpD,eAAe,EAAE,MAAM,CAAA;IACvB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,QAAgB,GACjB,EAAE,oBAAoB,2CAsCtB"}
@@ -0,0 +1,33 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as Switch from '@radix-ui/react-switch';
4
+ /**
5
+ * A robots-directive switch.
6
+ *
7
+ * ── Why this is not the ordinary Toggle ───────────────────────────────────
8
+ *
9
+ * The admin's `Toggle` turns brand purple when on, because "on" is the state
10
+ * the product is nudging you towards. That reading is wrong here. These
11
+ * switches are not on/off, they are permissive/restrictive — and the meaningful
12
+ * distinction is not "did I enable something" but "is this page still allowed
13
+ * to be found". Purple would say "enabled" about a switch whose enabled state
14
+ * is simply the default, and say nothing about the one state worth noticing.
15
+ *
16
+ * So: green when permitted, red when restricted. And the literal directive
17
+ * token sits beside it, because the failure this UI has to prevent is an editor
18
+ * flipping something whose consequence they could not name. `noindex` next to
19
+ * the switch turns an abstract toggle into the thing it actually writes into
20
+ * the page's head.
21
+ *
22
+ * Colour never carries it alone — the token chip is text, and the switch's
23
+ * accessible name states the label and the token it will produce.
24
+ */
25
+ export function DirectiveSwitch({ id, label, hint, checked, onChange, permissiveToken, restrictiveToken, disabled = false, }) {
26
+ const token = checked ? permissiveToken : restrictiveToken;
27
+ return (_jsxs("div", { className: "flex items-start justify-between gap-3 py-1.5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("label", { htmlFor: id, className: "text-foreground block text-[12.5px] font-medium", children: label }), hint && _jsx("p", { className: "text-muted-foreground mt-0.5 text-[11px] leading-snug", children: hint })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx("code", { className: `rounded px-1.5 py-0.5 font-mono text-[9.5px] font-bold ${checked ? 'bg-success/12 text-success' : 'bg-destructive/12 text-destructive'}`, children: token }), _jsx(Switch.Root, { id: id, checked: checked, onCheckedChange: onChange, disabled: disabled, "aria-label": `${label} — currently ${token}`,
28
+ // `prenta-touch-hit`, not `prenta-touch-target`: growing the track to
29
+ // 44px would strand the thumb, which is positioned against it. The
30
+ // hit area grows; the switch keeps its measured 34×19.
31
+ className: `prenta-touch-hit focus-visible:ring-ring relative h-[19px] w-[34px] shrink-0 rounded-full transition-colors duration-(--mo-base) focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50 ${checked ? 'bg-success' : 'bg-destructive/55'}`, children: _jsx(Switch.Thumb, { className: "block h-3.5 w-3.5 translate-x-[2.5px] rounded-full bg-white shadow-[0_1px_3px_rgba(0,0,0,0.25)] transition-transform duration-(--mo-base) data-[state=checked]:translate-x-[18px]" }) })] })] }));
32
+ }
33
+ //# sourceMappingURL=DirectiveSwitch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DirectiveSwitch.js","sourceRoot":"","sources":["../../../src/components/page-tab/DirectiveSwitch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAA;AAkBhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,EAAE,EACF,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,QAAQ,GAAG,KAAK,GACK;IACrB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,CAAA;IAE1D,OAAO,CACL,eAAK,SAAS,EAAC,+CAA+C,aAC5D,eAAK,SAAS,EAAC,SAAS,aACtB,gBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAC,iDAAiD,YAC5E,KAAK,GACA,EACP,IAAI,IAAI,YAAG,SAAS,EAAC,uDAAuD,YAAE,IAAI,GAAK,IACpF,EAEN,eAAK,SAAS,EAAC,kCAAkC,aAC/C,eACE,SAAS,EAAE,0DACT,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,oCAC3C,EAAE,YAED,KAAK,GACD,EACP,KAAC,MAAM,CAAC,IAAI,IACV,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,QAAQ,EACzB,QAAQ,EAAE,QAAQ,gBACN,GAAG,KAAK,gBAAgB,KAAK,EAAE;wBAC3C,sEAAsE;wBACtE,mEAAmE;wBACnE,uDAAuD;wBACvD,SAAS,EAAE,wMACT,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,mBAC3B,EAAE,YAEF,KAAC,MAAM,CAAC,KAAK,IAAC,SAAS,EAAC,mLAAmL,GAAG,GAClM,IACV,IACF,CACP,CAAA;AACH,CAAC"}
@@ -1,6 +1,13 @@
1
1
  /** Compact color-coded score for the page/post editor toolbar (`77/100` left of "SEO"). */
2
- export declare function EditorSeoScoreBadge({ score, inverted, }: {
2
+ export declare function EditorSeoScoreBadge({ score, band, inverted, }: {
3
3
  score: number;
4
+ /**
5
+ * Band for the colour. Supplied by the caller because different scores use
6
+ * different scales: the page audit bands at 80/55, `analyzeContent` at
7
+ * 80/60/1. Deriving it here would colour one model's number with another
8
+ * model's thresholds — they disagree between 55 and 59.
9
+ */
10
+ band?: 'good' | 'fair' | 'poor';
4
11
  /** When the SEO toggle uses `bg-primary`, render score in primary-foreground. */
5
12
  inverted?: boolean;
6
13
  }): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"EditorSeoScoreBadge.d.ts","sourceRoot":"","sources":["../../../src/components/seo/EditorSeoScoreBadge.tsx"],"names":[],"mappings":"AAIA,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAgB,GACjB,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,2CAaA"}
1
+ {"version":3,"file":"EditorSeoScoreBadge.d.ts","sourceRoot":"","sources":["../../../src/components/seo/EditorSeoScoreBadge.tsx"],"names":[],"mappings":"AAIA,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,IAAI,EACJ,QAAgB,GACjB,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,2CAaA"}
@@ -2,8 +2,8 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { gradeFromScore, gradeMeta } from './primitives.js';
4
4
  /** Compact color-coded score for the page/post editor toolbar (`77/100` left of "SEO"). */
5
- export function EditorSeoScoreBadge({ score, inverted = false, }) {
6
- const meta = gradeMeta(gradeFromScore(score));
5
+ export function EditorSeoScoreBadge({ score, band, inverted = false, }) {
6
+ const meta = gradeMeta(band ?? gradeFromScore(score));
7
7
  return (_jsxs("span", { className: `inline-flex items-baseline gap-0.5 text-xs font-medium tabular-nums ${inverted ? 'text-primary-foreground' : meta.text}`, "aria-hidden": true, children: [score, _jsx("span", { className: inverted ? 'text-primary-foreground/80' : 'opacity-70', children: "/100" })] }));
8
8
  }
9
9
  //# sourceMappingURL=EditorSeoScoreBadge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EditorSeoScoreBadge.js","sourceRoot":"","sources":["../../../src/components/seo/EditorSeoScoreBadge.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3D,2FAA2F;AAC3F,MAAM,UAAU,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,GAAG,KAAK,GAKjB;IACC,MAAM,IAAI,GAAG,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7C,OAAO,CACL,gBACE,SAAS,EAAE,uEACT,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI,CAAC,IAC9C,EAAE,kCAGD,KAAK,EACN,eAAM,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,YAAY,qBAAa,IAC/E,CACR,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"EditorSeoScoreBadge.js","sourceRoot":"","sources":["../../../src/components/seo/EditorSeoScoreBadge.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3D,2FAA2F;AAC3F,MAAM,UAAU,mBAAmB,CAAC,EAClC,KAAK,EACL,IAAI,EACJ,QAAQ,GAAG,KAAK,GAYjB;IACC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IACrD,OAAO,CACL,gBACE,SAAS,EAAE,uEACT,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI,CAAC,IAC9C,EAAE,kCAGD,KAAK,EACN,eAAM,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,YAAY,qBAAa,IAC/E,CACR,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type PageAuditResult } from '@prenta/core/seo/page-audit';
2
+ export interface PageAuditPanelProps {
3
+ audit: PageAuditResult;
4
+ }
5
+ /**
6
+ * Twin score rings over the SEO and GEO check lists.
7
+ *
8
+ * Both scores are reported the same way and neither is folded into a single
9
+ * headline: classic search and AI answer visibility fail for different reasons
10
+ * and are fixed by different edits, so averaging them would hide whichever is
11
+ * worse.
12
+ */
13
+ export declare function PageAuditPanel({ audit }: PageAuditPanelProps): import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=PageAuditPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageAuditPanel.d.ts","sourceRoot":"","sources":["../../../src/components/seo/PageAuditPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,6BAA6B,CAAA;AA4IpC,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,eAAe,CAAA;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE,mBAAmB,2CA8B5D"}
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { ChevronDown, Search, Sparkles } from 'lucide-react';
5
+ import { scoreBand, } from '@prenta/core/seo/page-audit';
6
+ const BAND_TEXT = { good: 'text-success', fair: 'text-warning', poor: 'text-destructive' };
7
+ const BAND_STROKE = {
8
+ good: 'stroke-success',
9
+ fair: 'stroke-warning',
10
+ poor: 'stroke-destructive',
11
+ };
12
+ /**
13
+ * A 52px score ring.
14
+ *
15
+ * `null` is a real state, not an error: a page held back from search has no
16
+ * search performance to rate. It renders as a dash on a neutral track rather
17
+ * than an alarming zero.
18
+ */
19
+ function ScoreRing({ score, label }) {
20
+ const R = 21;
21
+ const CIRCUMFERENCE = 2 * Math.PI * R;
22
+ const band = score === null ? null : scoreBand(score);
23
+ const dash = score === null ? 0 : (score / 100) * CIRCUMFERENCE;
24
+ return (_jsxs("svg", { width: "52", height: "52", viewBox: "0 0 52 52", role: "img", "aria-label": score === null ? `${label}: not rated` : `${label} score: ${score} of 100`, children: [_jsx("circle", { cx: "26", cy: "26", r: R, className: "stroke-border", strokeWidth: "5", fill: "none" }), score !== null && (_jsx("circle", { cx: "26", cy: "26", r: R, className: `${BAND_STROKE[band]} motion-safe:transition-[stroke-dasharray,stroke] motion-safe:duration-350`, strokeWidth: "5", fill: "none", strokeLinecap: "round", strokeDasharray: `${dash} ${CIRCUMFERENCE - dash}`,
25
+ // Start the arc at twelve o'clock instead of three.
26
+ transform: "rotate(-90 26 26)" })), _jsx("text", { x: "26", y: "26", textAnchor: "middle", dominantBaseline: "central", className: `fill-current text-[15px] font-bold tabular-nums ${band ? BAND_TEXT[band] : 'text-muted-foreground'}`, children: score === null ? '—' : score })] }));
27
+ }
28
+ function CheckRow({ check }) {
29
+ const na = check.outcome === 'not-applicable';
30
+ const pass = check.outcome === 'pass';
31
+ return (_jsxs("li", { className: "border-border flex gap-2 border-b py-[7px] last:border-b-0", children: [_jsx("span", { "aria-hidden": true, className: `mt-0.5 h-4 w-4 shrink-0 rounded ${na ? 'bg-muted' : pass ? 'bg-success/15 text-success' : 'bg-warning/15 text-warning'}` }), _jsxs("div", { className: "min-w-0", children: [_jsxs("p", { className: `text-xs font-medium ${na ? 'text-muted-foreground' : 'text-foreground'}`, children: [check.label, _jsx("span", { className: "sr-only", children: na ? ' — not applicable' : pass ? ' — passing' : ' — needs attention' })] }), na ? (_jsx("p", { className: "text-muted-foreground text-[10.5px]", children: check.naReason })) : pass ? null : (_jsx("p", { className: "text-muted-foreground text-[10.5px]", children: check.hint }))] })] }));
32
+ }
33
+ function CheckGroup({ result, title }) {
34
+ const [open, setOpen] = useState(true);
35
+ const band = result.score === null ? null : scoreBand(result.score);
36
+ return (_jsxs("section", { className: "border-border border-b", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), "aria-expanded": open, className: "hover:bg-accent flex w-full items-center justify-between px-3.5 py-2.5 transition-colors", children: [_jsx("span", { className: "text-muted-foreground text-[10px] font-bold tracking-[0.7px] uppercase", children: title }), _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: `rounded-full px-1.5 text-[10px] font-bold tabular-nums ${band === 'good'
37
+ ? 'bg-success/15 text-success'
38
+ : band === 'fair'
39
+ ? 'bg-warning/15 text-warning'
40
+ : band === 'poor'
41
+ ? 'bg-destructive/15 text-destructive'
42
+ : 'bg-muted text-muted-foreground'}`, children: result.score === null ? 'n/a' : `${result.passed}/${result.applicable}` }), _jsx(ChevronDown, { className: `text-muted-foreground h-3.5 w-3.5 transition-transform ${open ? 'rotate-180' : ''}`, "aria-hidden": true })] })] }), open && (_jsx("ul", { className: "px-3.5 pb-3.5", children: result.checks.map((c) => (_jsx(CheckRow, { check: c }, c.id))) }))] }));
43
+ }
44
+ /**
45
+ * Twin score rings over the SEO and GEO check lists.
46
+ *
47
+ * Both scores are reported the same way and neither is folded into a single
48
+ * headline: classic search and AI answer visibility fail for different reasons
49
+ * and are fixed by different edits, so averaging them would hide whichever is
50
+ * worse.
51
+ */
52
+ export function PageAuditPanel({ audit }) {
53
+ const { seo, geo } = audit;
54
+ return (_jsxs("div", { className: "border-border border-b", children: [_jsx("div", { className: "flex items-start justify-around gap-3 px-3.5 py-4", children: [
55
+ { r: seo, icon: Search, label: 'SEO', sub: 'Classic search & crawlability' },
56
+ { r: geo, icon: Sparkles, label: 'GEO', sub: 'AI answer visibility' },
57
+ ].map(({ r, icon: Icon, label, sub }) => (_jsxs("div", { className: "flex min-w-0 flex-col items-center gap-1.5 text-center", children: [_jsx(ScoreRing, { score: r.score, label: label }), _jsxs("span", { className: "text-foreground flex items-center gap-1 text-xs font-bold", children: [_jsx(Icon, { className: "h-3 w-3", "aria-hidden": true }), label] }), _jsx("span", { className: "text-muted-foreground text-[10.5px] leading-tight", children: sub }), _jsx("span", { className: "text-muted-foreground text-[10px] tabular-nums", children: r.score === null ? 'not rated' : `${r.applicable} of ${r.total} apply` })] }, label))) }), _jsx(CheckGroup, { result: seo, title: "SEO checks" }), _jsx(CheckGroup, { result: geo, title: "GEO checks" })] }));
58
+ }
59
+ //# sourceMappingURL=PageAuditPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageAuditPanel.js","sourceRoot":"","sources":["../../../src/components/seo/PageAuditPanel.tsx"],"names":[],"mappings":"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"}