@prenta/admin 1.0.0 → 1.2.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 (149) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/AdminRoot.d.ts.map +1 -1
  3. package/dist/AdminRoot.js +5 -56
  4. package/dist/AdminRoot.js.map +1 -1
  5. package/dist/__tests__/components/breakpoint-controls.render.test.js +4 -4
  6. package/dist/__tests__/components/breakpoint-controls.render.test.js.map +1 -1
  7. package/dist/__tests__/lib/canvas-edit-chrome.test.js +1 -22
  8. package/dist/__tests__/lib/canvas-edit-chrome.test.js.map +1 -1
  9. package/dist/__tests__/lib/open-public-site-tab.test.d.ts +2 -0
  10. package/dist/__tests__/lib/open-public-site-tab.test.d.ts.map +1 -0
  11. package/dist/__tests__/lib/open-public-site-tab.test.js +64 -0
  12. package/dist/__tests__/lib/open-public-site-tab.test.js.map +1 -0
  13. package/dist/__tests__/lib/preview-bridge.test.js +19 -79
  14. package/dist/__tests__/lib/preview-bridge.test.js.map +1 -1
  15. package/dist/__tests__/lib/view-site-chrome.test.d.ts +2 -0
  16. package/dist/__tests__/lib/view-site-chrome.test.d.ts.map +1 -0
  17. package/dist/__tests__/lib/view-site-chrome.test.js +69 -0
  18. package/dist/__tests__/lib/view-site-chrome.test.js.map +1 -0
  19. package/dist/__tests__/router/admin-routes.test.js +4 -0
  20. package/dist/__tests__/router/admin-routes.test.js.map +1 -1
  21. package/dist/__tests__/views/canvas-review-mode.render.test.js +11 -1
  22. package/dist/__tests__/views/canvas-review-mode.render.test.js.map +1 -1
  23. package/dist/__tests__/views/canvas-surface-shared.test.js +0 -16
  24. package/dist/__tests__/views/canvas-surface-shared.test.js.map +1 -1
  25. package/dist/__tests__/views/editor-top-bar.render.test.js +52 -22
  26. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  27. package/dist/__tests__/views/page-section-editor.test.js +53 -18
  28. package/dist/__tests__/views/page-section-editor.test.js.map +1 -1
  29. package/dist/__tests__/views/post-section-editor.test.js +23 -0
  30. package/dist/__tests__/views/post-section-editor.test.js.map +1 -1
  31. package/dist/components/BreakpointPicker.d.ts +3 -2
  32. package/dist/components/BreakpointPicker.d.ts.map +1 -1
  33. package/dist/components/BreakpointPicker.js +5 -3
  34. package/dist/components/BreakpointPicker.js.map +1 -1
  35. package/dist/components/CanvasEditTip.js +1 -1
  36. package/dist/components/CanvasEditTip.js.map +1 -1
  37. package/dist/lib/canvas-edit-chrome.d.ts +0 -17
  38. package/dist/lib/canvas-edit-chrome.d.ts.map +1 -1
  39. package/dist/lib/canvas-edit-chrome.js +0 -62
  40. package/dist/lib/canvas-edit-chrome.js.map +1 -1
  41. package/dist/lib/editor-preview.d.ts +4 -1
  42. package/dist/lib/editor-preview.d.ts.map +1 -1
  43. package/dist/lib/editor-preview.js +4 -1
  44. package/dist/lib/editor-preview.js.map +1 -1
  45. package/dist/lib/open-public-site-tab.d.ts +14 -0
  46. package/dist/lib/open-public-site-tab.d.ts.map +1 -0
  47. package/dist/lib/open-public-site-tab.js +46 -0
  48. package/dist/lib/open-public-site-tab.js.map +1 -0
  49. package/dist/lib/preview-bridge.d.ts +7 -74
  50. package/dist/lib/preview-bridge.d.ts.map +1 -1
  51. package/dist/lib/preview-bridge.js +12 -73
  52. package/dist/lib/preview-bridge.js.map +1 -1
  53. package/dist/lib/view-site-chrome.d.ts +19 -0
  54. package/dist/lib/view-site-chrome.d.ts.map +1 -0
  55. package/dist/lib/view-site-chrome.js +24 -0
  56. package/dist/lib/view-site-chrome.js.map +1 -0
  57. package/dist/router/admin-routes.d.ts.map +1 -1
  58. package/dist/router/admin-routes.js +0 -2
  59. package/dist/router/admin-routes.js.map +1 -1
  60. package/dist/views/page-editor/EditorCanvas.d.ts +2 -3
  61. package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
  62. package/dist/views/page-editor/EditorCanvas.js +2 -2
  63. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  64. package/dist/views/page-editor/EditorTopBar.d.ts +15 -17
  65. package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
  66. package/dist/views/page-editor/EditorTopBar.js +20 -21
  67. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  68. package/dist/views/page-editor/PageSectionEditor.d.ts +1 -7
  69. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  70. package/dist/views/page-editor/PageSectionEditor.js +36 -141
  71. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  72. package/dist/views/page-editor/StructureNotice.d.ts +2 -5
  73. package/dist/views/page-editor/StructureNotice.d.ts.map +1 -1
  74. package/dist/views/page-editor/StructureNotice.js +6 -10
  75. package/dist/views/page-editor/StructureNotice.js.map +1 -1
  76. package/dist/views/page-editor/sections/SectionRenderer.d.ts +1 -1
  77. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  78. package/dist/views/page-editor/sections/SectionRenderer.js +2 -1
  79. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  80. package/dist/views/post-editor/PostEditorCanvas.d.ts +2 -4
  81. package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
  82. package/dist/views/post-editor/PostEditorCanvas.js +3 -3
  83. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  84. package/dist/views/post-editor/PostSectionEditor.d.ts +1 -15
  85. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  86. package/dist/views/post-editor/PostSectionEditor.js +36 -128
  87. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  88. package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
  89. package/dist/views/settings/SeoSettingsTab.js +2 -1
  90. package/dist/views/settings/SeoSettingsTab.js.map +1 -1
  91. package/dist/views/settings/SiteInformationCard.d.ts.map +1 -1
  92. package/dist/views/settings/SiteInformationCard.js +3 -1
  93. package/dist/views/settings/SiteInformationCard.js.map +1 -1
  94. package/package.json +6 -6
  95. package/src/AdminRoot.tsx +0 -70
  96. package/src/__tests__/components/breakpoint-controls.render.test.tsx +6 -4
  97. package/src/__tests__/lib/canvas-edit-chrome.test.ts +0 -27
  98. package/src/__tests__/lib/open-public-site-tab.test.ts +74 -0
  99. package/src/__tests__/lib/preview-bridge.test.ts +21 -110
  100. package/src/__tests__/lib/view-site-chrome.test.ts +80 -0
  101. package/src/__tests__/router/admin-routes.test.ts +5 -0
  102. package/src/__tests__/views/canvas-review-mode.render.test.tsx +14 -1
  103. package/src/__tests__/views/canvas-surface-shared.test.ts +0 -19
  104. package/src/__tests__/views/editor-top-bar.render.test.tsx +104 -22
  105. package/src/__tests__/views/page-section-editor.test.tsx +65 -22
  106. package/src/__tests__/views/post-section-editor.test.tsx +35 -0
  107. package/src/components/BreakpointPicker.tsx +6 -3
  108. package/src/components/CanvasEditTip.tsx +2 -2
  109. package/src/lib/canvas-edit-chrome.ts +0 -64
  110. package/src/lib/editor-preview.ts +4 -1
  111. package/src/lib/open-public-site-tab.ts +57 -0
  112. package/src/lib/preview-bridge.ts +11 -157
  113. package/src/lib/view-site-chrome.ts +46 -0
  114. package/src/router/admin-routes.ts +0 -2
  115. package/src/styles/theme.css +4 -4
  116. package/src/views/page-editor/EditorCanvas.tsx +2 -7
  117. package/src/views/page-editor/EditorTopBar.tsx +85 -82
  118. package/src/views/page-editor/PageSectionEditor.tsx +83 -220
  119. package/src/views/page-editor/StructureNotice.tsx +7 -42
  120. package/src/views/page-editor/sections/SectionRenderer.tsx +5 -2
  121. package/src/views/post-editor/PostEditorCanvas.tsx +3 -9
  122. package/src/views/post-editor/PostSectionEditor.tsx +71 -195
  123. package/src/views/settings/SeoSettingsTab.tsx +21 -0
  124. package/src/views/settings/SiteInformationCard.tsx +7 -0
  125. package/dist/__tests__/views/use-site-preview.render.test.d.ts +0 -2
  126. package/dist/__tests__/views/use-site-preview.render.test.d.ts.map +0 -1
  127. package/dist/__tests__/views/use-site-preview.render.test.js +0 -120
  128. package/dist/__tests__/views/use-site-preview.render.test.js.map +0 -1
  129. package/dist/views/page-editor/PagePreview.d.ts +0 -13
  130. package/dist/views/page-editor/PagePreview.d.ts.map +0 -1
  131. package/dist/views/page-editor/PagePreview.js +0 -46
  132. package/dist/views/page-editor/PagePreview.js.map +0 -1
  133. package/dist/views/page-editor/SitePreviewFrame.d.ts +0 -43
  134. package/dist/views/page-editor/SitePreviewFrame.d.ts.map +0 -1
  135. package/dist/views/page-editor/SitePreviewFrame.js +0 -165
  136. package/dist/views/page-editor/SitePreviewFrame.js.map +0 -1
  137. package/dist/views/page-editor/useSitePreview.d.ts +0 -47
  138. package/dist/views/page-editor/useSitePreview.d.ts.map +0 -1
  139. package/dist/views/page-editor/useSitePreview.js +0 -96
  140. package/dist/views/page-editor/useSitePreview.js.map +0 -1
  141. package/dist/views/post-editor/PostPreview.d.ts +0 -14
  142. package/dist/views/post-editor/PostPreview.d.ts.map +0 -1
  143. package/dist/views/post-editor/PostPreview.js +0 -63
  144. package/dist/views/post-editor/PostPreview.js.map +0 -1
  145. package/src/__tests__/views/use-site-preview.render.test.tsx +0 -164
  146. package/src/views/page-editor/PagePreview.tsx +0 -105
  147. package/src/views/page-editor/SitePreviewFrame.tsx +0 -250
  148. package/src/views/page-editor/useSitePreview.ts +0 -158
  149. package/src/views/post-editor/PostPreview.tsx +0 -125
@@ -20,20 +20,16 @@ import {
20
20
  savePostDraft,
21
21
  toggleSectionVisibility,
22
22
  updateSectionContent,
23
- updateSectionContentAtPath,
24
23
  updateSectionMeta,
25
24
  validatePost,
26
25
  type EditorPost,
27
26
  type PostHeaderConfig,
28
27
  type ValidationResult,
29
28
  } from '../../lib/post-editor-service.js'
30
- import { MediaPickerModal } from '../../components/MediaPickerModal.js'
29
+ import { SharePreviewLinkDialog } from '../../components/SharePreviewLinkDialog.js'
31
30
  import { defaultPostHeader } from '@prenta/core/page-sections'
32
- import {
33
- buildPublicPreviewUrl,
34
- buildPublicUrl,
35
- createPreviewToken,
36
- } from '../../lib/preview-link.js'
31
+ import { openPublicSiteTab } from '../../lib/open-public-site-tab.js'
32
+ import type { ViewSiteIntent } from '../../lib/view-site-chrome.js'
37
33
  import { usePublicSiteUrl } from '../../hooks/usePublicSiteUrl.js'
38
34
  import {
39
35
  hasCanvasRenderer,
@@ -42,17 +38,14 @@ import {
42
38
  } from '../page-editor/sections/index.js'
43
39
  import { DEFAULT_VIEWPORT, type ViewportId } from '../page-editor/viewports.js'
44
40
  import { EditorTopBar, type SaveState } from '../page-editor/EditorTopBar.js'
45
- import { SitePreviewFrame } from '../page-editor/SitePreviewFrame.js'
46
- import { useSitePreview } from '../page-editor/useSitePreview.js'
47
41
  import { SectionsList } from '../page-editor/SectionsPanel.js'
48
42
  import { SectionEditForm } from '../page-editor/SectionEditForm.js'
49
43
  import { ValidationSummary } from '../page-editor/ValidationSummary.js'
50
- import { resolveDefaultSitePreview } from '../../lib/editor-preview.js'
51
44
  import { buildEditorContentHtml, computeLiveSeoScore } from '../../lib/editor-seo-content.js'
52
45
  import { snapshotBaseline, type ReflowBaseline } from '../../lib/reflow-baseline.js'
53
46
  import { ReflowContext } from '../page-editor/reflow-context.js'
54
47
  import type { Zoom } from '../../lib/breakpoints.js'
55
- import { companionDimensionPaths, inspectorIdFromFieldPath } from '../../lib/preview-bridge.js'
48
+ import { inspectorIdFromFieldPath } from '../../lib/preview-bridge.js'
56
49
  import { PostEditorCanvas } from './PostEditorCanvas.js'
57
50
  import { PostFieldsModal, type PostFieldConfig } from './PostFieldsModal.js'
58
51
 
@@ -68,7 +61,6 @@ interface EditorConfig {
68
61
  | undefined
69
62
  >
70
63
  seo?: { siteUrl?: string }
71
- admin?: { editor?: { defaultSitePreview?: boolean | { pages?: boolean; posts?: boolean } } }
72
64
  }
73
65
 
74
66
  /** The slice of the admin session this editor reads. */
@@ -83,12 +75,6 @@ interface PostSectionEditorProps {
83
75
  config?: EditorConfig
84
76
  session?: EditorSession
85
77
  onNavigate: (path: string) => void
86
- /**
87
- * Open a preview route in a new browser tab. `prepare` runs before the tab
88
- * navigates (used to save an unsaved draft first); returning `false` cancels
89
- * the open. Falls back to in-tab navigation when not provided.
90
- */
91
- onOpenPreview?: (path: string, prepare?: () => Promise<boolean | void> | boolean | void) => void
92
78
  }
93
79
 
94
80
  function deriveCan(session: EditorSession | undefined): {
@@ -111,7 +97,6 @@ export function PostSectionEditor({
111
97
  config,
112
98
  session,
113
99
  onNavigate,
114
- onOpenPreview,
115
100
  }: PostSectionEditorProps) {
116
101
  const [post, setPost] = useState<EditorPost | null>(null)
117
102
  const [header, setHeader] = useState<PostHeaderConfig>(defaultPostHeader())
@@ -121,13 +106,6 @@ export function PostSectionEditor({
121
106
  const [selectedId, setSelectedId] = useState<string | null>(null)
122
107
  /** Canvas field click — focused after the inspector mounts for `selectedId`. */
123
108
  const [pendingFocusPath, setPendingFocusPath] = useState<string | null>(null)
124
- /** Bump to skip the next `prenta-preview:sections` echo after a canvas text edit. */
125
- const [suppressSectionsEcho, setSuppressSectionsEcho] = useState(0)
126
- /** Canvas image Replace — opens MediaPickerModal for this field path. */
127
- const [canvasMediaTarget, setCanvasMediaTarget] = useState<{
128
- sectionId: string
129
- fieldPath: string
130
- } | null>(null)
131
109
  const [viewport, setViewport] = useState<ViewportId>(DEFAULT_VIEWPORT)
132
110
  const [zoom, setZoom] = useState<Zoom>('fit')
133
111
  /** Scale the canvas measured — reported upward so the zoom chip shows a real %. */
@@ -151,6 +129,7 @@ export function PostSectionEditor({
151
129
  const [historyOpen, setHistoryOpen] = useState(false)
152
130
  const [confirmPublish, setConfirmPublish] = useState(false)
153
131
  const [scheduleOpen, setScheduleOpen] = useState(false)
132
+ const [shareOpen, setShareOpen] = useState(false)
154
133
  const [leaveTarget, setLeaveTarget] = useState<string | null>(null)
155
134
  const [validation, setValidation] = useState<ValidationResult | null>(null)
156
135
 
@@ -170,13 +149,15 @@ export function PostSectionEditor({
170
149
 
171
150
  const { canEdit, canPublish } = useMemo(() => deriveCan(session), [session])
172
151
  const customRenderers = useAdminSectionRenderers()
173
- const { siteUrl: publicSiteUrl } = usePublicSiteUrl(config?.seo?.siteUrl)
152
+ const { siteUrl: publicSiteUrl, matchesAdminOrigin } = usePublicSiteUrl(config?.seo?.siteUrl)
174
153
 
175
154
  const typeLabel = useMemo(() => {
176
155
  const col = config?.collections?.[postType]
177
156
  return col?.labels?.singular ?? postType
178
157
  }, [config, postType])
179
158
 
159
+ const urlPrefix = config?.collections?.[postType]?.urlPrefix ?? postType
160
+
180
161
  // A misconfigured post-type collection (missing the fields the editor
181
162
  // writes) would silently drop content on save — detect it up front.
182
163
  // Memoized to a string/null so the load effect can depend on it without
@@ -390,21 +371,6 @@ export function PostSectionEditor({
390
371
  }
391
372
  }, [post, documentId, postType, onNavigate])
392
373
 
393
- // Inline branded preview — Next builder canvas (same origin as admin).
394
- // "View on site" still uses publicSiteUrl for the Astro/public apex.
395
- const sitePreview = useSitePreview({
396
- collection: postType,
397
- documentId: post?.id,
398
- slug: post?.slug,
399
- urlPrefix: config?.collections?.[postType]?.urlPrefix ?? postType,
400
- dirty,
401
- saveState,
402
- saveDraft: handleSaveDraft,
403
- defaultActive: resolveDefaultSitePreview(config?.admin?.editor, 'posts'),
404
- })
405
-
406
- const sitePreviewAvailable = Boolean(post?.id && post?.slug)
407
-
408
374
  const requestPublish = useCallback(() => {
409
375
  if (!post) return
410
376
  const result = validatePost(post, true)
@@ -510,32 +476,11 @@ export function PostSectionEditor({
510
476
  setRailTab('sections')
511
477
  setPendingFocusPath(fieldPath ?? null)
512
478
  // Toggles, because selection is now disclosure — see the note on the page
513
- // editor's copy. A `fieldPath` means the site preview is pointing at a
514
- // specific field, which must open rather than toggle.
479
+ // editor's copy. A `fieldPath` means a canvas field click, which must
480
+ // open rather than toggle.
515
481
  setSelectedId((current) => (fieldPath ? id : current === id ? null : id))
516
482
  }, [])
517
483
 
518
- const handleCanvasEdit = useCallback(
519
- (edit: { sectionId: string; fieldPath: string; value: string }) => {
520
- if (!canEdit) return
521
- setSuppressSectionsEcho((n) => n + 1)
522
- mutateSections((s) =>
523
- updateSectionContentAtPath(s, edit.sectionId, edit.fieldPath, edit.value),
524
- )
525
- setSelectedId(edit.sectionId)
526
- },
527
- [canEdit, mutateSections],
528
- )
529
-
530
- const handleCanvasRequestMedia = useCallback(
531
- (request: { sectionId: string; fieldPath: string }) => {
532
- if (!canEdit) return
533
- setSelectedId(request.sectionId)
534
- setCanvasMediaTarget(request)
535
- },
536
- [canEdit],
537
- )
538
-
539
484
  // After a canvas field click, focus the matching inspector input once painted.
540
485
  useEffect(() => {
541
486
  if (!pendingFocusPath || !selectedId) return
@@ -555,78 +500,37 @@ export function PostSectionEditor({
555
500
  [dirty, onNavigate],
556
501
  )
557
502
 
558
- const handlePreview = useCallback(() => {
559
- if (!post?.id) {
560
- toast.error('Save the post before previewing')
561
- return
562
- }
563
- const path = `/posts/${postType}/${post.id}/preview`
564
- // New-tab preview: save first when there are unsaved edits so the preview
565
- // (which reads the persisted document) reflects what's on screen.
566
- if (onOpenPreview) {
567
- onOpenPreview(path, dirty ? handleSaveDraft : undefined)
568
- } else {
569
- guardedNavigate(path)
570
- }
571
- }, [post, postType, dirty, onOpenPreview, handleSaveDraft, guardedNavigate])
503
+ const handleViewOnSite = useCallback(
504
+ (intent: ViewSiteIntent) => {
505
+ if (!post?.id || !post.slug) {
506
+ toast.error('Save the post before viewing it on the site')
507
+ return
508
+ }
509
+ void openPublicSiteTab({
510
+ intent,
511
+ siteUrl: publicSiteUrl,
512
+ collection: postType,
513
+ documentId: post.id,
514
+ slug: post.slug,
515
+ urlPrefix,
516
+ data: { path: (post as { path?: string }).path },
517
+ dirty,
518
+ saveDraft: handleSaveDraft,
519
+ }).catch((err) => {
520
+ toast.error(err instanceof Error ? err.message : 'Failed to open the site')
521
+ })
522
+ },
523
+ [post, postType, urlPrefix, dirty, handleSaveDraft, publicSiteUrl],
524
+ )
572
525
 
573
- // "View on site": render the draft through the consumer's real public route
574
- // (`/<urlPrefix>/<slug>?preview=<token>`) via a signed preview token.
575
- const handleViewOnSite = useCallback(() => {
576
- if (!post?.id || !post.slug) {
577
- toast.error('Save the post before viewing it on the site')
578
- return
579
- }
580
- // Published → open the LIVE post directly (no preview token, no forced
581
- // save). Pending edits stay previewable via the eye + globe.
582
- if (post.status === 'PUBLISHED') {
583
- window.open(
584
- buildPublicUrl({
585
- siteUrl: publicSiteUrl,
586
- urlPrefix: config?.collections?.[postType]?.urlPrefix ?? postType,
587
- slug: post.slug,
588
- data: { path: (post as { path?: string }).path },
589
- }),
590
- '_blank',
591
- 'noopener',
592
- )
593
- return
594
- }
595
- const tab = window.open('about:blank', '_blank')
596
- if (!tab) {
597
- toast.error('Enable pop-ups for this site to open the preview in a new tab.')
598
- return
526
+ const handleShare = useCallback(async () => {
527
+ if (!post?.id) return
528
+ if (dirty) {
529
+ const ok = await handleSaveDraft()
530
+ if (!ok) return
599
531
  }
600
- void (async () => {
601
- try {
602
- if (dirty) {
603
- const ok = await handleSaveDraft()
604
- if (!ok) {
605
- tab.close()
606
- return
607
- }
608
- }
609
- const { token } = await createPreviewToken(postType, post.id!)
610
- const urlPrefix = config?.collections?.[postType]?.urlPrefix ?? postType
611
- const target = buildPublicPreviewUrl({
612
- siteUrl: publicSiteUrl,
613
- urlPrefix,
614
- slug: post.slug,
615
- data: { path: (post as { path?: string }).path },
616
- token,
617
- })
618
- try {
619
- tab.opener = null
620
- } catch {
621
- /* same-origin guard */
622
- }
623
- tab.location.replace(target)
624
- } catch (err) {
625
- tab.close()
626
- toast.error(err instanceof Error ? err.message : 'Failed to open site preview')
627
- }
628
- })()
629
- }, [post, postType, dirty, config, handleSaveDraft, publicSiteUrl])
532
+ setShareOpen(true)
533
+ }, [post, dirty, handleSaveDraft])
630
534
 
631
535
  // ─── Render states ───────────────────────────────────────────────────
632
536
  if (loading) {
@@ -693,16 +597,14 @@ export function PostSectionEditor({
693
597
  viewport={viewport}
694
598
  backLabel="Posts"
695
599
  onViewport={setViewport}
696
- {...(sitePreview.active
697
- ? // The site preview is an iframe of the real front end, not a
698
- // scaled canvas — a zoom percentage there would be a lie.
699
- {}
700
- : { zoom, canvasScale, onZoom: setZoom })}
600
+ zoom={zoom}
601
+ canvasScale={canvasScale}
602
+ onZoom={setZoom}
701
603
  onBack={() => guardedNavigate('/posts')}
702
- onPreview={handlePreview}
703
- onViewOnSite={post.id ? handleViewOnSite : undefined}
704
- sitePreview={sitePreview.active}
705
- onToggleSitePreview={post.id && post.slug ? sitePreview.toggle : undefined}
604
+ onViewOnSite={post.id && post.slug ? handleViewOnSite : undefined}
605
+ onShare={post.id ? handleShare : undefined}
606
+ hasPublicSiteUrl={Boolean(publicSiteUrl)}
607
+ matchesAdminOrigin={matchesAdminOrigin}
706
608
  onHistory={post.id ? () => setHistoryOpen(true) : undefined}
707
609
  onOpenSettings={() => setFieldsOpen(true)}
708
610
  onOpenSeo={handleToggleSeo}
@@ -801,34 +703,18 @@ export function PostSectionEditor({
801
703
  </EditorRail>
802
704
 
803
705
  <div className="flex-1 overflow-hidden">
804
- {sitePreview.active ? (
805
- <SitePreviewFrame
806
- src={sitePreview.url}
807
- viewport={viewport}
808
- reloadKey={sitePreview.reloadKey}
809
- title={`Site preview: ${post.title || `New ${typeLabel}`}`}
810
- selectedId={selectedId}
811
- sections={post.sections}
812
- suppressSectionsEcho={suppressSectionsEcho}
813
- onSelectSection={handleSelectSection}
814
- onCanvasEdit={handleCanvasEdit}
815
- onCanvasRequestMedia={handleCanvasRequestMedia}
816
- />
817
- ) : (
818
- <PostEditorCanvas
819
- sections={post.sections}
820
- header={header}
821
- context={context}
822
- selectedId={selectedId}
823
- viewport={viewport}
824
- zoom={zoom}
825
- onScaleChange={setCanvasScale}
826
- onCanvasElement={setCanvasEl}
827
- onSelect={handleSelectSection}
828
- structuralTypes={structuralTypes}
829
- sitePreviewAvailable={sitePreviewAvailable && !sitePreview.active}
830
- />
831
- )}
706
+ <PostEditorCanvas
707
+ sections={post.sections}
708
+ header={header}
709
+ context={context}
710
+ selectedId={selectedId}
711
+ viewport={viewport}
712
+ zoom={zoom}
713
+ onScaleChange={setCanvasScale}
714
+ onCanvasElement={setCanvasEl}
715
+ onSelect={handleSelectSection}
716
+ structuralTypes={structuralTypes}
717
+ />
832
718
  </div>
833
719
  </div>
834
720
  </ReflowContext.Provider>
@@ -874,6 +760,19 @@ export function PostSectionEditor({
874
760
  />
875
761
  )}
876
762
 
763
+ {post.id && (
764
+ <SharePreviewLinkDialog
765
+ collectionSlug={postType}
766
+ documentId={post.id}
767
+ documentSlug={post.slug}
768
+ documentPath={(post as { path?: string }).path}
769
+ siteUrl={publicSiteUrl}
770
+ urlPrefix={urlPrefix}
771
+ open={shareOpen}
772
+ onClose={() => setShareOpen(false)}
773
+ />
774
+ )}
775
+
877
776
  <ConfirmDialog
878
777
  open={leaveTarget !== null}
879
778
  onClose={() => setLeaveTarget(null)}
@@ -889,29 +788,6 @@ export function PostSectionEditor({
889
788
  cancelLabel="Stay"
890
789
  destructive
891
790
  />
892
-
893
- <MediaPickerModal
894
- open={canvasMediaTarget !== null}
895
- onClose={() => setCanvasMediaTarget(null)}
896
- accept="image/*"
897
- onSelectItem={(item) => {
898
- if (!canvasMediaTarget) return
899
- const { sectionId, fieldPath } = canvasMediaTarget
900
- const { widthPath, heightPath } = companionDimensionPaths(fieldPath)
901
- mutateSections((s) => {
902
- let next = updateSectionContentAtPath(s, sectionId, fieldPath, item.url)
903
- if (typeof item.width === 'number') {
904
- next = updateSectionContentAtPath(next, sectionId, widthPath, item.width)
905
- }
906
- if (typeof item.height === 'number') {
907
- next = updateSectionContentAtPath(next, sectionId, heightPath, item.height)
908
- }
909
- return next
910
- })
911
- setCanvasMediaTarget(null)
912
- }}
913
- onSelect={() => setCanvasMediaTarget(null)}
914
- />
915
791
  </ErrorBoundary>
916
792
  )
917
793
  }
@@ -13,6 +13,7 @@ import {
13
13
  Upload,
14
14
  X,
15
15
  } from 'lucide-react'
16
+ import { siteUrlMatchesAdminOrigin } from '../../lib/preview-link.js'
16
17
  import { MediaPickerModal } from '../../components/MediaPickerModal.js'
17
18
  import { SEOConfigPanel } from '../../components/SEOConfigPanel.js'
18
19
  import {
@@ -125,6 +126,26 @@ export function SeoSettingsTab({ onNavigate, role }: SeoSettingsTabProps) {
125
126
 
126
127
  <SettingsValidationSummary issues={seo.issues} />
127
128
 
129
+ {!seo.siteUrl ? (
130
+ <div
131
+ role="status"
132
+ className="border-warning/30 bg-warning/10 text-warning flex items-start gap-2 rounded-lg border p-4 text-sm"
133
+ >
134
+ <AlertTriangle size={16} className="mt-0.5 shrink-0" aria-hidden="true" />
135
+ Set the public site URL in Settings → General. View site and Share stay disabled until it
136
+ is set.
137
+ </div>
138
+ ) : siteUrlMatchesAdminOrigin(seo.siteUrl) ? (
139
+ <div
140
+ role="status"
141
+ className="border-warning/30 bg-warning/10 text-warning flex items-start gap-2 rounded-lg border p-4 text-sm"
142
+ >
143
+ <AlertTriangle size={16} className="mt-0.5 shrink-0" aria-hidden="true" />
144
+ This origin is the admin, not the public site. Set the public site URL to the live apex —
145
+ View site and Share stay disabled while it matches this CMS host.
146
+ </div>
147
+ ) : null}
148
+
128
149
  <MetaDefaultsCard seo={seo} canEdit={canEdit} />
129
150
  <OrganizationCard seo={seo} canEdit={canEdit} />
130
151
  <SearchEngineVerificationCard seo={seo} canEdit={canEdit} />
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useId } from 'react'
4
4
  import { CheckCircle2 } from 'lucide-react'
5
+ import { siteUrlMatchesAdminOrigin } from '../../lib/preview-link.js'
5
6
  import { SettingsCard, SettingsSourceBadge } from './components.js'
6
7
  import type {
7
8
  GeneralSettingsForm,
@@ -37,6 +38,7 @@ export function SiteInformationCard({
37
38
  const urlIssue = issues.find((i) => i.field === 'siteUrl')
38
39
  const urlEditable = sources.siteUrl?.editable !== false && canEdit
39
40
  const urlValid = !urlIssue && form.siteUrl.trim().length > 0
41
+ const urlIsAdminOrigin = siteUrlMatchesAdminOrigin(form.siteUrl)
40
42
 
41
43
  return (
42
44
  <SettingsCard title="Site Information" description="Your site's name, tagline, and public URL.">
@@ -99,6 +101,11 @@ export function SiteInformationCard({
99
101
  >
100
102
  {urlIssue.message}
101
103
  </p>
104
+ ) : urlIsAdminOrigin ? (
105
+ <p role="status" className="text-warning mt-1 text-sm">
106
+ This origin is the admin, not the public site. Set the public apex (Astro or the live
107
+ Next site), not this CMS host — View site and Share will stay disabled until you do.
108
+ </p>
102
109
  ) : urlValid ? (
103
110
  <p className="text-muted-foreground mt-1 flex items-center gap-1.5 text-sm">
104
111
  <CheckCircle2 size={13} className="text-success" aria-hidden="true" />
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=use-site-preview.render.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-site-preview.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/use-site-preview.render.test.tsx"],"names":[],"mappings":""}
@@ -1,120 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // @vitest-environment happy-dom
3
- import { beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { fireEvent, render, screen, waitFor } from '@testing-library/react';
5
- /**
6
- * useSitePreview — drives the inline branded preview (iframe of the public
7
- * site rendering a draft). Pins: token minted + URL built on activation,
8
- * unsaved drafts are persisted first (a failed save cancels activation), and
9
- * the frame reloads (reloadKey bump) after each completed save.
10
- */
11
- const createPreviewToken = vi.fn(async () => ({
12
- token: 'tok-123',
13
- expiresAt: '2026-06-19T00:00:00Z',
14
- }));
15
- vi.mock('../../lib/preview-link.js', () => ({
16
- createPreviewToken: (...args) => createPreviewToken(...args),
17
- buildPublicPreviewUrl: ({ siteUrl, urlPrefix, slug, path, token }) => {
18
- const p = path === '/' || path === '' ? '/' : path || `${urlPrefix ? `/${urlPrefix}` : ''}/${slug}`;
19
- return p === '/'
20
- ? `${siteUrl}/?preview=${token}`
21
- : `${siteUrl}${p.startsWith('/') ? p : `/${p}`}?preview=${token}`;
22
- },
23
- resolveSiteUrl: (u) => u ?? 'https://fallback.test',
24
- }));
25
- vi.mock('sonner', () => ({
26
- toast: { error: vi.fn(), success: vi.fn() },
27
- }));
28
- const { useSitePreview } = await import('../../views/page-editor/useSitePreview.js');
29
- const { toast } = await import('sonner');
30
- function Harness({ documentId = 'doc-1', slug = 'about', dirty = false, saveState = 'idle', saveDraft = vi.fn(async () => true), defaultActive = false, }) {
31
- const sp = useSitePreview({
32
- collection: 'pages',
33
- documentId,
34
- slug,
35
- urlPrefix: '',
36
- // Canvas defaults to window.location.origin (Next builder / CMS host).
37
- dirty,
38
- saveState,
39
- saveDraft,
40
- defaultActive,
41
- });
42
- return (_jsxs("div", { children: [_jsx("button", { type: "button", onClick: sp.toggle, children: "toggle" }), _jsx("output", { "data-testid": "state", children: JSON.stringify({ active: sp.active, url: sp.url, reloadKey: sp.reloadKey }) })] }));
43
- }
44
- function state() {
45
- return JSON.parse(screen.getByTestId('state').textContent ?? '{}');
46
- }
47
- beforeEach(() => {
48
- createPreviewToken.mockClear();
49
- vi.mocked(toast.error).mockClear();
50
- });
51
- describe('useSitePreview', () => {
52
- it('mints a token and builds the canvas draft URL on activation', async () => {
53
- render(_jsx(Harness, {}));
54
- fireEvent.click(screen.getByText('toggle'));
55
- expect(state().active).toBe(true);
56
- await waitFor(() => {
57
- expect(state().url).toBe(`${window.location.origin}/about?preview=tok-123`);
58
- });
59
- expect(createPreviewToken).toHaveBeenCalledWith('pages', 'doc-1');
60
- });
61
- it('saves a dirty draft before minting; a failed save cancels activation', async () => {
62
- const saveDraft = vi.fn(async () => false);
63
- render(_jsx(Harness, { dirty: true, saveDraft: saveDraft }));
64
- fireEvent.click(screen.getByText('toggle'));
65
- await waitFor(() => expect(saveDraft).toHaveBeenCalled());
66
- await waitFor(() => expect(state().active).toBe(false));
67
- expect(createPreviewToken).not.toHaveBeenCalled();
68
- });
69
- it('refuses to activate for unsaved documents', () => {
70
- render(_jsx(Harness, { documentId: null }));
71
- fireEvent.click(screen.getByText('toggle'));
72
- expect(state().active).toBe(false);
73
- expect(toast.error).toHaveBeenCalled();
74
- });
75
- it('toggles back to the canvas on second click', async () => {
76
- render(_jsx(Harness, {}));
77
- fireEvent.click(screen.getByText('toggle'));
78
- await waitFor(() => expect(state().url).not.toBeNull());
79
- fireEvent.click(screen.getByText('toggle'));
80
- expect(state().active).toBe(false);
81
- });
82
- it('auto-activates when defaultActive is true', async () => {
83
- render(_jsx(Harness, { defaultActive: true }));
84
- await waitFor(() => {
85
- expect(state().active).toBe(true);
86
- expect(state().url).toBe(`${window.location.origin}/about?preview=tok-123`);
87
- });
88
- expect(createPreviewToken).toHaveBeenCalledWith('pages', 'doc-1');
89
- });
90
- it('honors an explicit canvasUrl override', async () => {
91
- function CanvasHarness() {
92
- const sp = useSitePreview({
93
- collection: 'pages',
94
- documentId: 'doc-1',
95
- slug: 'about',
96
- urlPrefix: '',
97
- canvasUrl: 'https://cms.test',
98
- dirty: false,
99
- saveState: 'idle',
100
- saveDraft: vi.fn(async () => true),
101
- });
102
- return (_jsx("button", { type: "button", onClick: sp.toggle, children: sp.url ?? 'none' }));
103
- }
104
- render(_jsx(CanvasHarness, {}));
105
- fireEvent.click(screen.getByRole('button'));
106
- await waitFor(() => {
107
- expect(screen.getByRole('button').textContent).toBe('https://cms.test/about?preview=tok-123');
108
- });
109
- });
110
- it('bumps reloadKey after a save completes while the preview is open', async () => {
111
- const { rerender } = render(_jsx(Harness, { saveState: "idle" }));
112
- fireEvent.click(screen.getByText('toggle'));
113
- await waitFor(() => expect(state().url).not.toBeNull());
114
- expect(state().reloadKey).toBe(0);
115
- rerender(_jsx(Harness, { saveState: "saving" }));
116
- rerender(_jsx(Harness, { saveState: "saved" }));
117
- await waitFor(() => expect(state().reloadKey).toBe(1));
118
- });
119
- });
120
- //# sourceMappingURL=use-site-preview.render.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-site-preview.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/use-site-preview.render.test.tsx"],"names":[],"mappings":";AAAA,gCAAgC;AAChC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAE3E;;;;;GAKG;AAEH,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC5C,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,sBAAsB;CAClC,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,2BAA2B,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1C,kBAAkB,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAI,IAAW,CAAC;IAC/E,qBAAqB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAO,EAAE,EAAE;QACxE,MAAM,CAAC,GACL,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAA;QAC3F,OAAO,CAAC,KAAK,GAAG;YACd,CAAC,CAAC,GAAG,OAAO,aAAa,KAAK,EAAE;YAChC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,YAAY,KAAK,EAAE,CAAA;IACrE,CAAC;IACD,cAAc,EAAE,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,uBAAuB;CACpE,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACvB,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;CAC5C,CAAC,CAAC,CAAA;AAEH,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,2CAA2C,CAAC,CAAA;AACpF,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;AAIxC,SAAS,OAAO,CAAC,EACf,UAAU,GAAG,OAAO,EACpB,IAAI,GAAG,OAAO,EACd,KAAK,GAAG,KAAK,EACb,SAAS,GAAG,MAAmB,EAC/B,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,EACnC,aAAa,GAAG,KAAK,GAQtB;IACC,MAAM,EAAE,GAAG,cAAc,CAAC;QACxB,UAAU,EAAE,OAAO;QACnB,UAAU;QACV,IAAI;QACJ,SAAS,EAAE,EAAE;QACb,uEAAuE;QACvE,KAAK;QACL,SAAS;QACT,SAAS;QACT,aAAa;KACd,CAAC,CAAA;IACF,OAAO,CACL,0BACE,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,EAAE,CAAC,MAAM,uBAE/B,EACT,gCAAoB,OAAO,YACxB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,GACrE,IACL,CACP,CAAA;AACH,CAAC;AAED,SAAS,KAAK;IACZ,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,CAAA;AACpE,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,kBAAkB,CAAC,SAAS,EAAE,CAAA;IAC9B,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,CAAA;AACpC,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,CAAC,KAAC,OAAO,KAAG,CAAC,CAAA;QACnB,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,wBAAwB,CAAC,CAAA;QAC7E,CAAC,CAAC,CAAA;QACF,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAA;QAC1C,MAAM,CAAC,KAAC,OAAO,IAAC,KAAK,QAAC,SAAS,EAAE,SAAS,GAAI,CAAC,CAAA;QAC/C,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAA;QACzD,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QACvD,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,KAAC,OAAO,IAAC,UAAU,EAAE,IAAI,GAAI,CAAC,CAAA;QACrC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,CAAC,KAAC,OAAO,KAAG,CAAC,CAAA;QACnB,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;QACvD,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,CAAC,KAAC,OAAO,IAAC,aAAa,SAAG,CAAC,CAAA;QACjC,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACjC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,wBAAwB,CAAC,CAAA;QAC7E,CAAC,CAAC,CAAA;QACF,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,SAAS,aAAa;YACpB,MAAM,EAAE,GAAG,cAAc,CAAC;gBACxB,UAAU,EAAE,OAAO;gBACnB,UAAU,EAAE,OAAO;gBACnB,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,kBAAkB;gBAC7B,KAAK,EAAE,KAAK;gBACZ,SAAS,EAAE,MAAM;gBACjB,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC;aACnC,CAAC,CAAA;YACF,OAAO,CACL,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,EAAE,CAAC,MAAM,YACrC,EAAE,CAAC,GAAG,IAAI,MAAM,GACV,CACV,CAAA;QACH,CAAC;QACD,MAAM,CAAC,KAAC,aAAa,KAAG,CAAC,CAAA;QACzB,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;QAC/F,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAC,OAAO,IAAC,SAAS,EAAC,MAAM,GAAG,CAAC,CAAA;QACzD,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC3C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;QACvD,MAAM,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAEjC,QAAQ,CAAC,KAAC,OAAO,IAAC,SAAS,EAAC,QAAQ,GAAG,CAAC,CAAA;QACxC,QAAQ,CAAC,KAAC,OAAO,IAAC,SAAS,EAAC,OAAO,GAAG,CAAC,CAAA;QACvC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,13 +0,0 @@
1
- interface PagePreviewProps {
2
- documentId: string;
3
- onNavigate: (path: string) => void;
4
- }
5
- /**
6
- * Clean, chrome-free render of a page using the SAME section renderers as
7
- * the editor canvas — so the preview reflects what will actually ship.
8
- * Only visible sections are rendered (hidden sections are omitted, exactly
9
- * as the public page would behave).
10
- */
11
- export declare function PagePreview({ documentId, onNavigate }: PagePreviewProps): import("react/jsx-runtime").JSX.Element;
12
- export {};
13
- //# sourceMappingURL=PagePreview.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PagePreview.d.ts","sourceRoot":"","sources":["../../../src/views/page-editor/PagePreview.tsx"],"names":[],"mappings":"AAOA,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,gBAAgB,2CAsFvE"}