@prenta/admin 0.93.0 → 0.95.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 (130) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/dist/__tests__/lib/page-editor-service-api.test.js +37 -0
  3. package/dist/__tests__/lib/page-editor-service-api.test.js.map +1 -1
  4. package/dist/__tests__/lib/version-diff.test.d.ts +2 -0
  5. package/dist/__tests__/lib/version-diff.test.d.ts.map +1 -0
  6. package/dist/__tests__/lib/version-diff.test.js +230 -0
  7. package/dist/__tests__/lib/version-diff.test.js.map +1 -0
  8. package/dist/__tests__/lib/version-history.test.d.ts +2 -0
  9. package/dist/__tests__/lib/version-history.test.d.ts.map +1 -0
  10. package/dist/__tests__/lib/version-history.test.js +125 -0
  11. package/dist/__tests__/lib/version-history.test.js.map +1 -0
  12. package/dist/__tests__/styles/responsive-layer.test.d.ts +2 -0
  13. package/dist/__tests__/styles/responsive-layer.test.d.ts.map +1 -0
  14. package/dist/__tests__/styles/responsive-layer.test.js +127 -0
  15. package/dist/__tests__/styles/responsive-layer.test.js.map +1 -0
  16. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts +2 -0
  17. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts.map +1 -0
  18. package/dist/__tests__/views/canvas-review-mode.render.test.js +70 -0
  19. package/dist/__tests__/views/canvas-review-mode.render.test.js.map +1 -0
  20. package/dist/__tests__/views/editor-top-bar.render.test.js +29 -0
  21. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  22. package/dist/__tests__/views/section-edit-form.render.test.d.ts +2 -0
  23. package/dist/__tests__/views/section-edit-form.render.test.d.ts.map +1 -0
  24. package/dist/__tests__/views/section-edit-form.render.test.js +124 -0
  25. package/dist/__tests__/views/section-edit-form.render.test.js.map +1 -0
  26. package/dist/__tests__/views/section-inspector-media.test.js +1 -1
  27. package/dist/__tests__/views/section-inspector-media.test.js.map +1 -1
  28. package/dist/__tests__/views/section-inspector-repeater.render.test.js +2 -1
  29. package/dist/__tests__/views/section-inspector-repeater.render.test.js.map +1 -1
  30. package/dist/__tests__/views/version-history-panel.render.test.d.ts +2 -0
  31. package/dist/__tests__/views/version-history-panel.render.test.d.ts.map +1 -0
  32. package/dist/__tests__/views/version-history-panel.render.test.js +153 -0
  33. package/dist/__tests__/views/version-history-panel.render.test.js.map +1 -0
  34. package/dist/components/CanvasEditTip.js +1 -1
  35. package/dist/components/CanvasEditTip.js.map +1 -1
  36. package/dist/components/EditorRail.js +3 -3
  37. package/dist/components/EditorRail.js.map +1 -1
  38. package/dist/components/page-tab/DirectiveSwitch.d.ts.map +1 -1
  39. package/dist/components/page-tab/DirectiveSwitch.js +5 -1
  40. package/dist/components/page-tab/DirectiveSwitch.js.map +1 -1
  41. package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
  42. package/dist/layout/primitives/AdminShell.js +2 -2
  43. package/dist/layout/primitives/AdminShell.js.map +1 -1
  44. package/dist/lib/version-diff.d.ts +50 -0
  45. package/dist/lib/version-diff.d.ts.map +1 -0
  46. package/dist/lib/version-diff.js +294 -0
  47. package/dist/lib/version-diff.js.map +1 -0
  48. package/dist/lib/version-history.d.ts +73 -0
  49. package/dist/lib/version-history.d.ts.map +1 -0
  50. package/dist/lib/version-history.js +126 -0
  51. package/dist/lib/version-history.js.map +1 -0
  52. package/dist/prenta-admin.css +1 -1
  53. package/dist/views/page-editor/EditorCanvas.d.ts +14 -1
  54. package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
  55. package/dist/views/page-editor/EditorCanvas.js +3 -3
  56. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  57. package/dist/views/page-editor/EditorTopBar.d.ts +8 -2
  58. package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
  59. package/dist/views/page-editor/EditorTopBar.js +8 -6
  60. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  61. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  62. package/dist/views/page-editor/PageSectionEditor.js +129 -40
  63. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  64. package/dist/views/page-editor/ReviewBar.d.ts +21 -0
  65. package/dist/views/page-editor/ReviewBar.d.ts.map +1 -0
  66. package/dist/views/page-editor/ReviewBar.js +22 -0
  67. package/dist/views/page-editor/ReviewBar.js.map +1 -0
  68. package/dist/views/page-editor/SectionEditForm.d.ts +42 -0
  69. package/dist/views/page-editor/SectionEditForm.d.ts.map +1 -0
  70. package/dist/views/page-editor/SectionEditForm.js +48 -0
  71. package/dist/views/page-editor/SectionEditForm.js.map +1 -0
  72. package/dist/views/page-editor/SectionInspector.d.ts +0 -20
  73. package/dist/views/page-editor/SectionInspector.d.ts.map +1 -1
  74. package/dist/views/page-editor/SectionInspector.js +6 -224
  75. package/dist/views/page-editor/SectionInspector.js.map +1 -1
  76. package/dist/views/page-editor/SectionsPanel.d.ts +10 -1
  77. package/dist/views/page-editor/SectionsPanel.d.ts.map +1 -1
  78. package/dist/views/page-editor/SectionsPanel.js +11 -5
  79. package/dist/views/page-editor/SectionsPanel.js.map +1 -1
  80. package/dist/views/page-editor/VersionHistoryPanel.d.ts +29 -0
  81. package/dist/views/page-editor/VersionHistoryPanel.d.ts.map +1 -0
  82. package/dist/views/page-editor/VersionHistoryPanel.js +81 -0
  83. package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -0
  84. package/dist/views/page-editor/section-fields.d.ts +43 -0
  85. package/dist/views/page-editor/section-fields.d.ts.map +1 -0
  86. package/dist/views/page-editor/section-fields.js +236 -0
  87. package/dist/views/page-editor/section-fields.js.map +1 -0
  88. package/dist/views/page-editor/sections/ArticleBodySection.js +1 -1
  89. package/dist/views/page-editor/sections/ArticleBodySection.js.map +1 -1
  90. package/dist/views/page-editor/sections/SectionRenderer.d.ts +13 -1
  91. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  92. package/dist/views/page-editor/sections/SectionRenderer.js +23 -8
  93. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  94. package/dist/views/post-editor/PostEditorCanvas.js +1 -1
  95. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  96. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  97. package/dist/views/post-editor/PostSectionEditor.js +11 -9
  98. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  99. package/package.json +3 -3
  100. package/src/__tests__/lib/page-editor-service-api.test.ts +44 -0
  101. package/src/__tests__/lib/version-diff.test.ts +278 -0
  102. package/src/__tests__/lib/version-history.test.ts +166 -0
  103. package/src/__tests__/styles/responsive-layer.test.ts +152 -0
  104. package/src/__tests__/views/canvas-review-mode.render.test.tsx +94 -0
  105. package/src/__tests__/views/editor-top-bar.render.test.tsx +42 -0
  106. package/src/__tests__/views/section-edit-form.render.test.tsx +162 -0
  107. package/src/__tests__/views/section-inspector-media.test.ts +1 -1
  108. package/src/__tests__/views/section-inspector-repeater.render.test.tsx +2 -1
  109. package/src/__tests__/views/version-history-panel.render.test.tsx +195 -0
  110. package/src/components/CanvasEditTip.tsx +3 -3
  111. package/src/components/EditorRail.tsx +5 -5
  112. package/src/components/page-tab/DirectiveSwitch.tsx +4 -1
  113. package/src/layout/primitives/AdminShell.tsx +13 -1
  114. package/src/lib/version-diff.ts +376 -0
  115. package/src/lib/version-history.ts +192 -0
  116. package/src/styles/responsive.css +281 -0
  117. package/src/styles/theme.css +8 -0
  118. package/src/views/page-editor/EditorCanvas.tsx +34 -7
  119. package/src/views/page-editor/EditorTopBar.tsx +20 -8
  120. package/src/views/page-editor/PageSectionEditor.tsx +182 -65
  121. package/src/views/page-editor/ReviewBar.tsx +76 -0
  122. package/src/views/page-editor/SectionEditForm.tsx +161 -0
  123. package/src/views/page-editor/SectionInspector.tsx +9 -553
  124. package/src/views/page-editor/SectionsPanel.tsx +72 -16
  125. package/src/views/page-editor/VersionHistoryPanel.tsx +302 -0
  126. package/src/views/page-editor/section-fields.tsx +563 -0
  127. package/src/views/page-editor/sections/ArticleBodySection.tsx +1 -1
  128. package/src/views/page-editor/sections/SectionRenderer.tsx +53 -12
  129. package/src/views/post-editor/PostEditorCanvas.tsx +1 -1
  130. package/src/views/post-editor/PostSectionEditor.tsx +18 -26
@@ -0,0 +1,281 @@
1
+ /*
2
+ * Prenta admin — responsive + accessibility layer.
3
+ *
4
+ * Port of `design-system/cms-responsive.css` from the page-builder design
5
+ * bundle. The prototype's own selectors (`.ni`, `.sec-panel`, `.icbtn`) do not
6
+ * exist here — this admin is Tailwind over the same tokens — so what is ported
7
+ * is the RULES, re-expressed against this codebase's real structure.
8
+ *
9
+ * Loaded after `theme.css`'s token blocks so it can adapt them, and scoped to
10
+ * `.prenta-admin` throughout: the admin renders inside consumer applications
11
+ * and must not restyle the host.
12
+ *
13
+ * Two rules from the source deliberately did NOT come across:
14
+ *
15
+ * - The prototype turns the sidebar into a fixed bottom bar under 768px.
16
+ * `AdminShell` already solves that size with a slide-in overlay driven by
17
+ * `matchMedia`, which the whole admin is built around; replacing a working
18
+ * navigation pattern was not part of finishing the page builder.
19
+ * - The blanket `min-height: 44px` on a list of prototype control classes.
20
+ * The equivalent here is `.prenta-touch-target`, applied per control —
21
+ * see the coarse-pointer block below for why a blanket `button` rule is
22
+ * the wrong shape.
23
+ */
24
+
25
+ /* ── Accessibility: applies at every size ─────────────────────────── */
26
+
27
+ /*
28
+ * A visible focus ring on everything, as a floor.
29
+ *
30
+ * `:focus-visible` rather than `:focus` so pointer users never see it. This
31
+ * sits in the base layer, so any component that opts into its own ring
32
+ * (`focus-visible:ring-2 focus-visible:outline-none`) still wins — utilities
33
+ * are a later layer — and this only fills in for the controls that have none.
34
+ */
35
+ .prenta-admin :focus-visible {
36
+ outline: var(--bw-focus, 2px) solid var(--acc);
37
+ outline-offset: 2px;
38
+ border-radius: 4px;
39
+ }
40
+
41
+ /* Controls flush against a panel edge draw the ring inside their own box, or
42
+ it is clipped by the scroll container they sit in. */
43
+ .prenta-admin [role='tab']:focus-visible,
44
+ .prenta-admin [role='separator']:focus-visible {
45
+ outline-offset: -2px;
46
+ }
47
+
48
+ /*
49
+ * Skip link. Rendered as the first child of the admin root by `AdminShell`,
50
+ * which also owns the `#prenta-main` target.
51
+ */
52
+ .prenta-admin .prenta-skip-link {
53
+ position: absolute;
54
+ left: -9999px;
55
+ top: 0;
56
+ z-index: 999;
57
+ padding: 10px 16px;
58
+ background: var(--acc);
59
+ color: #fff;
60
+ font-size: var(--fs-body, 13px);
61
+ font-weight: 600;
62
+ border-radius: 0 0 8px 0;
63
+ }
64
+
65
+ .prenta-admin .prenta-skip-link:focus {
66
+ left: 0;
67
+ }
68
+
69
+ /*
70
+ * Honour a stated preference for less motion.
71
+ *
72
+ * Tailwind's `motion-safe:` variant already covers the transitions written
73
+ * with it, but plenty of the admin's motion is unconditional, and a preference
74
+ * that holds for most of a screen is not honoured. `.reduce-motion` (an
75
+ * explicit Appearance setting, in theme.css) is the same rule by another
76
+ * trigger.
77
+ */
78
+ @media (prefers-reduced-motion: reduce) {
79
+ .prenta-admin,
80
+ .prenta-admin *,
81
+ .prenta-admin *::before,
82
+ .prenta-admin *::after {
83
+ animation-duration: 0.01ms !important;
84
+ animation-iteration-count: 1 !important;
85
+ transition-duration: 0.01ms !important;
86
+ scroll-behavior: auto !important;
87
+ }
88
+ }
89
+
90
+ /*
91
+ * Honour a stated preference for more contrast.
92
+ *
93
+ * Only the three tertiary tokens move, and only in the direction of more
94
+ * contrast than the shipped values — which are already an AA correction over
95
+ * the handoff's own numbers (see the `--muted` note in prenta-tokens.css).
96
+ * Set here rather than in the token file because that file is generated.
97
+ */
98
+ @media (prefers-contrast: more) {
99
+ .prenta-admin {
100
+ --muted: #5a5770;
101
+ --sub: #3d3a52;
102
+ --bdr: #c9c5dc;
103
+ }
104
+
105
+ .dark .prenta-admin,
106
+ .prenta-admin.dark,
107
+ .prenta-admin[data-theme='dark'] {
108
+ --muted: #a9a6c0;
109
+ --sub: #c4c1d8;
110
+ --bdr: #454263;
111
+ }
112
+ }
113
+
114
+ /*
115
+ * Touch devices: named controls clear the 44px target minimum.
116
+ *
117
+ * Opt-in per control rather than a blanket `button { min-height: 44px }`.
118
+ * The admin is full of dense tables and inline row actions where growing
119
+ * every button reflows the layout it sits in, and the prototype hit the same
120
+ * wall — it carries a curated list for exactly this reason. `.prenta-touch-target`
121
+ * is that list, expressed where the control is written instead of in a
122
+ * stylesheet that has to be kept in sync with class names.
123
+ *
124
+ * Pointer-based sizing is untouched: a 26px button is right with a mouse and
125
+ * wrong with a thumb.
126
+ */
127
+ @media (pointer: coarse) {
128
+ .prenta-admin .prenta-touch-target {
129
+ min-height: 44px;
130
+ min-width: 44px;
131
+ }
132
+
133
+ /*
134
+ * The exception, and the reason this is not one rule: a switch positions its
135
+ * knob against the track's own box, so stretching the track to 44px leaves
136
+ * the knob floating in the middle of dead space. Grow the HIT AREA instead
137
+ * and let the control paint at its designed size. Use this for any small
138
+ * control whose internals are positioned against its box.
139
+ *
140
+ * The insets are sized for the 34×19 directive switch: 19 + 26 = 45 tall,
141
+ * 34 + 12 = 46 wide.
142
+ */
143
+ .prenta-admin .prenta-touch-hit {
144
+ position: relative;
145
+ }
146
+
147
+ .prenta-admin .prenta-touch-hit::after {
148
+ content: '';
149
+ position: absolute;
150
+ inset-block: -13px;
151
+ inset-inline: -6px;
152
+ }
153
+ }
154
+
155
+ /* ── 4K / Retina (≥2000px) ────────────────────────────────────────── */
156
+ /* Stop the chrome thinning out to a ribbon on a very wide display. */
157
+ @media (min-width: 2000px) {
158
+ .prenta-admin {
159
+ --sbw: 280px;
160
+ }
161
+ }
162
+
163
+ /* ── Editor header (≤1180px): let the action cluster wrap ─────────── */
164
+ /*
165
+ * The breakpoint picker and zoom chip already hide below `md`. What remains
166
+ * still outgrows the bar before then, and a fixed-height flex row resolves
167
+ * that by crushing the title. Wrapping keeps the title readable and gives the
168
+ * actions a second line.
169
+ */
170
+ @media (max-width: 1180px) {
171
+ .prenta-admin .prenta-editor-header {
172
+ height: auto;
173
+ min-height: 0;
174
+ flex-wrap: wrap;
175
+ row-gap: 8px;
176
+ padding-top: 8px;
177
+ padding-bottom: 8px;
178
+ }
179
+
180
+ .prenta-admin .prenta-editor-header > * {
181
+ min-width: 0;
182
+ }
183
+ }
184
+
185
+ /* ── Tablet portrait (≤900px): the two-pane editor stacks ─────────── */
186
+ /*
187
+ * Side by side stops working before the canvas becomes useless, so the rail
188
+ * moves ABOVE the canvas and both take the full width. `!important` is
189
+ * required on the width: the rail's is an inline style (it is drag-resizable
190
+ * and persisted), and at this size a stored pixel width is meaningless anyway.
191
+ */
192
+ @media (max-width: 900px) {
193
+ .prenta-admin .prenta-editor-body {
194
+ flex-direction: column;
195
+ }
196
+
197
+ .prenta-admin .prenta-editor-rail {
198
+ width: 100% !important;
199
+ min-width: 0 !important;
200
+ max-height: 46vh;
201
+ border-right: none;
202
+ border-bottom: 1px solid var(--bdr);
203
+ }
204
+
205
+ /* Dragging a horizontal edge to set a width that no longer applies. */
206
+ .prenta-admin .prenta-editor-rail [role='separator'] {
207
+ display: none;
208
+ }
209
+
210
+ /* The collapsed strip's vertical label has no room to be vertical. */
211
+ .prenta-admin .prenta-editor-rail-collapsed {
212
+ width: 100% !important;
213
+ flex-direction: row;
214
+ align-items: center;
215
+ justify-content: flex-start;
216
+ gap: 10px;
217
+ padding: 0 12px;
218
+ height: 44px;
219
+ border-right: none;
220
+ border-bottom: 1px solid var(--bdr);
221
+ }
222
+
223
+ .prenta-admin .prenta-editor-rail-collapsed .prenta-rail-label {
224
+ writing-mode: horizontal-tb;
225
+ }
226
+
227
+ /* The inspector is a third column that no longer fits beside two others. */
228
+ .prenta-admin .prenta-editor-inspector {
229
+ width: 100% !important;
230
+ max-height: 46vh;
231
+ }
232
+ }
233
+
234
+ /* ── Mobile (≤460px) ──────────────────────────────────────────────── */
235
+ @media (max-width: 460px) {
236
+ /* Buttons that read as a pair go full width rather than shrinking to
237
+ nothing — the review bar's Restore / Back to current, in particular. */
238
+ .prenta-admin .prenta-editor-header button {
239
+ flex: 1 1 auto;
240
+ justify-content: center;
241
+ }
242
+ }
243
+
244
+ /* Landscape phones are short, not narrow — reclaim vertical space. */
245
+ @media (max-height: 520px) and (orientation: landscape) {
246
+ .prenta-admin .prenta-editor-rail {
247
+ max-height: none;
248
+ }
249
+
250
+ .prenta-admin .prenta-editor-header {
251
+ padding-top: 4px;
252
+ padding-bottom: 4px;
253
+ }
254
+ }
255
+
256
+ /*
257
+ * Printing a CMS screen is almost always a mistake. If it happens, drop the
258
+ * chrome and let the canvas print at its natural size rather than as a
259
+ * transformed, clipped thumbnail.
260
+ */
261
+ @media print {
262
+ .prenta-admin .prenta-editor-header,
263
+ .prenta-admin .prenta-editor-rail,
264
+ .prenta-admin .prenta-editor-rail-collapsed,
265
+ .prenta-admin .prenta-skip-link {
266
+ display: none !important;
267
+ }
268
+
269
+ .prenta-admin .prenta-canvas-scroll {
270
+ overflow: visible !important;
271
+ padding: 0 !important;
272
+ }
273
+
274
+ .prenta-admin .prenta-canvas-fit,
275
+ .prenta-admin .prenta-canvas {
276
+ width: auto !important;
277
+ height: auto !important;
278
+ transform: none !important;
279
+ box-shadow: none !important;
280
+ }
281
+ }
@@ -524,3 +524,11 @@
524
524
  transition-duration: 0.001ms;
525
525
  scroll-behavior: auto;
526
526
  }
527
+
528
+ /*
529
+ * Responsive + accessibility layer. LAST on purpose: it adapts the tokens and
530
+ * rules above (the `prefers-contrast` block overrides token values, the
531
+ * editor-stacking rules override the rail's own borders), so it has to come
532
+ * after them.
533
+ */
534
+ @import './responsive.css';
@@ -30,6 +30,19 @@ interface EditorCanvasProps {
30
30
  /** Section types rendered as placeholders — shows the "Structure view" notice. */
31
31
  structuralTypes?: string[]
32
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
33
46
  }
34
47
 
35
48
  /**
@@ -62,6 +75,9 @@ export function EditorCanvas({
62
75
  onCanvasElement,
63
76
  structuralTypes = [],
64
77
  sitePreviewAvailable = false,
78
+ reviewing = false,
79
+ changedSectionIds,
80
+ reviewBar,
65
81
  }: EditorCanvasProps) {
66
82
  const bp = getBreakpoint(breakpoint)
67
83
  const sentinelRef = useRef<HTMLDivElement>(null)
@@ -110,7 +126,7 @@ export function EditorCanvas({
110
126
  }, [scale, onScaleChange])
111
127
 
112
128
  return (
113
- <div className="bg-muted h-full overflow-auto px-6 pt-4.5 pb-10 text-center">
129
+ <div className="prenta-canvas-scroll bg-muted h-full overflow-auto px-6 pt-4.5 pb-10 text-center">
114
130
  {/*
115
131
  * Zero-height sentinel. Its offsetWidth IS the usable width — it is
116
132
  * subject to exactly the same padding, scrollbar and host scaling as the
@@ -123,11 +139,20 @@ export function EditorCanvas({
123
139
  <EmptyCanvas />
124
140
  ) : (
125
141
  <>
126
- <CanvasEditTip />
127
- <StructureNotice
128
- structuralTypes={structuralTypes}
129
- sitePreviewAvailable={sitePreviewAvailable}
130
- />
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
+ )}
131
156
  <CanvasMetaLine breakpoint={bp} pageHeight={pageHeight} scale={scale} />
132
157
 
133
158
  {/*
@@ -138,7 +163,7 @@ export function EditorCanvas({
138
163
  * height and corrupts the next measurement.
139
164
  */}
140
165
  <div
141
- className="mx-auto block"
166
+ className="prenta-canvas-fit mx-auto block"
142
167
  style={{
143
168
  width: Math.round(bp.width * scale),
144
169
  height: pageHeight ? Math.round(pageHeight * scale) : undefined,
@@ -167,6 +192,8 @@ export function EditorCanvas({
167
192
  key={section.id}
168
193
  section={section}
169
194
  editable
195
+ reviewing={reviewing}
196
+ changed={changedSectionIds?.has(section.id) ?? false}
170
197
  selected={section.id === selectedId}
171
198
  onSelect={onSelect}
172
199
  registerRef={registerRef}
@@ -50,10 +50,16 @@ interface EditorTopBarProps {
50
50
  */
51
51
  onViewOnSite?: () => void
52
52
  /**
53
- * Open the version history panel. When omitted the History button is
53
+ * Toggle the version history panel. When omitted the History button is
54
54
  * hidden — e.g. for unsaved documents that have no versions yet.
55
55
  */
56
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
57
63
  /** Whether the inline site preview (iframe of the public site) is showing. */
58
64
  sitePreview?: boolean
59
65
  /**
@@ -118,6 +124,7 @@ export function EditorTopBar({
118
124
  onPreview,
119
125
  onViewOnSite,
120
126
  onHistory,
127
+ historyOpen = false,
121
128
  sitePreview = false,
122
129
  onToggleSitePreview,
123
130
  onOpenSettings,
@@ -177,7 +184,7 @@ export function EditorTopBar({
177
184
  : 'Schedule a future publish date'
178
185
 
179
186
  return (
180
- <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">
181
188
  {/* Breadcrumb + status */}
182
189
  <div className="flex min-w-0 items-center gap-2">
183
190
  <nav aria-label="Breadcrumb" className="flex min-w-0 items-center gap-1.5 text-sm">
@@ -228,7 +235,7 @@ export function EditorTopBar({
228
235
  onClick={onOpenSettings}
229
236
  aria-label="Page settings"
230
237
  title="Page settings"
231
- 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"
232
239
  >
233
240
  <Settings2 className="h-4 w-4" aria-hidden />
234
241
  </button>
@@ -261,9 +268,14 @@ export function EditorTopBar({
261
268
  <button
262
269
  type="button"
263
270
  onClick={onHistory}
271
+ aria-pressed={historyOpen}
264
272
  aria-label="Version history"
265
- title="Version history"
266
- 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
+ }`}
267
279
  >
268
280
  <History className="h-4 w-4" aria-hidden />
269
281
  </button>
@@ -274,7 +286,7 @@ export function EditorTopBar({
274
286
  onClick={onPreview}
275
287
  aria-label={previewLabel}
276
288
  title={previewLabel}
277
- 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"
278
290
  >
279
291
  <Eye className="h-4 w-4" aria-hidden />
280
292
  </button>
@@ -290,7 +302,7 @@ export function EditorTopBar({
290
302
  ? 'Back to editor canvas'
291
303
  : 'Inline site preview — render the draft through your public site, in place'
292
304
  }
293
- className={`rounded-lg p-2 transition-colors ${
305
+ className={`prenta-touch-target rounded-lg p-2 transition-colors ${
294
306
  sitePreview
295
307
  ? 'bg-primary text-primary-foreground'
296
308
  : 'text-muted-foreground hover:text-foreground hover:bg-accent'
@@ -321,7 +333,7 @@ export function EditorTopBar({
321
333
  onClick={onViewOnSite}
322
334
  aria-label={isLive ? 'View live page' : 'View draft on site'}
323
335
  title={isLive ? 'View live page' : 'View draft on site'}
324
- 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"
325
337
  >
326
338
  <ExternalLink className="h-4 w-4" aria-hidden />
327
339
  </button>