@prenta/admin 1.1.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.
- package/CHANGELOG.md +6 -0
- package/dist/__tests__/lib/canvas-edit-chrome.test.js +1 -22
- package/dist/__tests__/lib/canvas-edit-chrome.test.js.map +1 -1
- package/dist/__tests__/lib/preview-bridge.test.js +19 -79
- package/dist/__tests__/lib/preview-bridge.test.js.map +1 -1
- package/dist/__tests__/lib/view-site-chrome.test.js +11 -1
- package/dist/__tests__/lib/view-site-chrome.test.js.map +1 -1
- package/dist/__tests__/views/canvas-review-mode.render.test.js +11 -1
- package/dist/__tests__/views/canvas-review-mode.render.test.js.map +1 -1
- package/dist/__tests__/views/editor-top-bar.render.test.js +8 -0
- package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
- package/dist/__tests__/views/page-section-editor.test.js +23 -9
- package/dist/__tests__/views/page-section-editor.test.js.map +1 -1
- package/dist/lib/canvas-edit-chrome.d.ts +0 -17
- package/dist/lib/canvas-edit-chrome.d.ts.map +1 -1
- package/dist/lib/canvas-edit-chrome.js +0 -62
- package/dist/lib/canvas-edit-chrome.js.map +1 -1
- package/dist/lib/preview-bridge.d.ts +7 -74
- package/dist/lib/preview-bridge.d.ts.map +1 -1
- package/dist/lib/preview-bridge.js +12 -73
- package/dist/lib/preview-bridge.js.map +1 -1
- package/dist/lib/view-site-chrome.d.ts +3 -0
- package/dist/lib/view-site-chrome.d.ts.map +1 -1
- package/dist/lib/view-site-chrome.js +11 -2
- package/dist/lib/view-site-chrome.js.map +1 -1
- package/dist/views/page-editor/EditorCanvas.d.ts +1 -1
- package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
- package/dist/views/page-editor/EditorTopBar.d.ts +3 -1
- package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
- package/dist/views/page-editor/EditorTopBar.js +2 -1
- package/dist/views/page-editor/EditorTopBar.js.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.js +8 -47
- package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
- package/dist/views/page-editor/sections/SectionRenderer.d.ts +1 -1
- package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
- package/dist/views/page-editor/sections/SectionRenderer.js +2 -1
- package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
- package/dist/views/post-editor/PostEditorCanvas.d.ts +1 -1
- package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.js +7 -41
- package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
- package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/SeoSettingsTab.js +2 -1
- package/dist/views/settings/SeoSettingsTab.js.map +1 -1
- package/dist/views/settings/SiteInformationCard.d.ts.map +1 -1
- package/dist/views/settings/SiteInformationCard.js +3 -1
- package/dist/views/settings/SiteInformationCard.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/lib/canvas-edit-chrome.test.ts +0 -27
- package/src/__tests__/lib/preview-bridge.test.ts +21 -110
- package/src/__tests__/lib/view-site-chrome.test.ts +16 -1
- package/src/__tests__/views/canvas-review-mode.render.test.tsx +14 -1
- package/src/__tests__/views/editor-top-bar.render.test.tsx +19 -0
- package/src/__tests__/views/page-section-editor.test.tsx +23 -13
- package/src/lib/canvas-edit-chrome.ts +0 -64
- package/src/lib/preview-bridge.ts +11 -157
- package/src/lib/view-site-chrome.ts +15 -3
- package/src/views/page-editor/EditorCanvas.tsx +1 -1
- package/src/views/page-editor/EditorTopBar.tsx +4 -0
- package/src/views/page-editor/PageSectionEditor.tsx +6 -63
- package/src/views/page-editor/sections/SectionRenderer.tsx +5 -2
- package/src/views/post-editor/PostEditorCanvas.tsx +1 -1
- package/src/views/post-editor/PostSectionEditor.tsx +5 -57
- package/src/views/settings/SeoSettingsTab.tsx +21 -0
- package/src/views/settings/SiteInformationCard.tsx +7 -0
|
@@ -27,13 +27,11 @@ import {
|
|
|
27
27
|
savePageDraft,
|
|
28
28
|
toggleSectionVisibility,
|
|
29
29
|
updateSectionContent,
|
|
30
|
-
updateSectionContentAtPath,
|
|
31
30
|
updateSectionMeta,
|
|
32
31
|
validatePage,
|
|
33
32
|
type EditorPage,
|
|
34
33
|
type ValidationResult,
|
|
35
34
|
} from '../../lib/page-editor-service.js'
|
|
36
|
-
import { MediaPickerModal } from '../../components/MediaPickerModal.js'
|
|
37
35
|
import { SharePreviewLinkDialog } from '../../components/SharePreviewLinkDialog.js'
|
|
38
36
|
import { openPublicSiteTab } from '../../lib/open-public-site-tab.js'
|
|
39
37
|
import type { ViewSiteIntent } from '../../lib/view-site-chrome.js'
|
|
@@ -61,7 +59,7 @@ import { SectionEditForm } from './SectionEditForm.js'
|
|
|
61
59
|
import { PageSettingsModal } from './PageSettingsModal.js'
|
|
62
60
|
import { ValidationSummary } from './ValidationSummary.js'
|
|
63
61
|
import { buildEditorContentHtml } from '../../lib/editor-seo-content.js'
|
|
64
|
-
import {
|
|
62
|
+
import { inspectorIdFromFieldPath } from '../../lib/preview-bridge.js'
|
|
65
63
|
|
|
66
64
|
interface PageSectionEditorProps {
|
|
67
65
|
/** undefined when creating a new page (`/pages/new`) */
|
|
@@ -134,13 +132,6 @@ export function PageSectionEditor({
|
|
|
134
132
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
|
135
133
|
/** Canvas field click — focused after the inspector mounts for `selectedId`. */
|
|
136
134
|
const [pendingFocusPath, setPendingFocusPath] = useState<string | null>(null)
|
|
137
|
-
/** Bump to skip the next `prenta-preview:sections` echo after a canvas text edit. */
|
|
138
|
-
const [suppressSectionsEcho, setSuppressSectionsEcho] = useState(0)
|
|
139
|
-
/** Canvas image Replace — opens MediaPickerModal for this field path. */
|
|
140
|
-
const [canvasMediaTarget, setCanvasMediaTarget] = useState<{
|
|
141
|
-
sectionId: string
|
|
142
|
-
fieldPath: string
|
|
143
|
-
} | null>(null)
|
|
144
135
|
const [viewport, setViewport] = useState<ViewportId>(DEFAULT_VIEWPORT)
|
|
145
136
|
const [zoom, setZoom] = useState<Zoom>('fit')
|
|
146
137
|
/**
|
|
@@ -227,7 +218,7 @@ export function PageSectionEditor({
|
|
|
227
218
|
|
|
228
219
|
const { canEdit, canPublish, canCreateRedirect } = useMemo(() => deriveCan(session), [session])
|
|
229
220
|
const customRenderers = useAdminSectionRenderers()
|
|
230
|
-
const { siteUrl: publicSiteUrl } = usePublicSiteUrl(config?.seo?.siteUrl)
|
|
221
|
+
const { siteUrl: publicSiteUrl, matchesAdminOrigin } = usePublicSiteUrl(config?.seo?.siteUrl)
|
|
231
222
|
|
|
232
223
|
// A misconfigured `pages` collection (missing the fields the editor
|
|
233
224
|
// writes) would silently drop content on save — detect it up front.
|
|
@@ -716,39 +707,14 @@ export function PageSectionEditor({
|
|
|
716
707
|
// rail has no close affordance at all — the chevron and the row both
|
|
717
708
|
// re-select what is already selected and nothing happens.
|
|
718
709
|
//
|
|
719
|
-
// Except when a fieldPath came with it:
|
|
720
|
-
//
|
|
721
|
-
//
|
|
722
|
-
// user is trying to edit.
|
|
710
|
+
// Except when a fieldPath came with it: a canvas field click must open
|
|
711
|
+
// and focus that input. Toggling would close the form on the second
|
|
712
|
+
// click of a field the user is trying to inspect.
|
|
723
713
|
if (fieldPath) return id
|
|
724
714
|
return current === id ? null : id
|
|
725
715
|
})
|
|
726
716
|
}, [])
|
|
727
717
|
|
|
728
|
-
// `effectiveCanEdit`, not `canEdit`: the site preview is a second editing
|
|
729
|
-
// surface, so a role check alone let it write through both the version-review
|
|
730
|
-
// lock and the builder-owned lock the rest of the editor honours.
|
|
731
|
-
const handleCanvasEdit = useCallback(
|
|
732
|
-
(edit: { sectionId: string; fieldPath: string; value: string }) => {
|
|
733
|
-
if (!effectiveCanEdit) return
|
|
734
|
-
setSuppressSectionsEcho((n) => n + 1)
|
|
735
|
-
mutateSections((s) =>
|
|
736
|
-
updateSectionContentAtPath(s, edit.sectionId, edit.fieldPath, edit.value),
|
|
737
|
-
)
|
|
738
|
-
setSelectedId(edit.sectionId)
|
|
739
|
-
},
|
|
740
|
-
[effectiveCanEdit, mutateSections],
|
|
741
|
-
)
|
|
742
|
-
|
|
743
|
-
const handleCanvasRequestMedia = useCallback(
|
|
744
|
-
(request: { sectionId: string; fieldPath: string }) => {
|
|
745
|
-
if (!effectiveCanEdit) return
|
|
746
|
-
setSelectedId(request.sectionId)
|
|
747
|
-
setCanvasMediaTarget(request)
|
|
748
|
-
},
|
|
749
|
-
[effectiveCanEdit],
|
|
750
|
-
)
|
|
751
|
-
|
|
752
718
|
// After a canvas field click, focus the matching inspector input once painted.
|
|
753
719
|
useEffect(() => {
|
|
754
720
|
if (!pendingFocusPath || !selectedId) return
|
|
@@ -878,6 +844,7 @@ export function PageSectionEditor({
|
|
|
878
844
|
onViewOnSite={page.id && page.slug ? handleViewOnSite : undefined}
|
|
879
845
|
onShare={page.id ? handleShare : undefined}
|
|
880
846
|
hasPublicSiteUrl={Boolean(publicSiteUrl)}
|
|
847
|
+
matchesAdminOrigin={matchesAdminOrigin}
|
|
881
848
|
historyOpen={historyOpen}
|
|
882
849
|
onHistory={page.id ? () => (historyOpen ? closeHistory() : openHistory()) : undefined}
|
|
883
850
|
onOpenSettings={() => setSettingsOpen(true)}
|
|
@@ -1114,30 +1081,6 @@ export function PageSectionEditor({
|
|
|
1114
1081
|
cancelLabel="Stay"
|
|
1115
1082
|
destructive
|
|
1116
1083
|
/>
|
|
1117
|
-
|
|
1118
|
-
<MediaPickerModal
|
|
1119
|
-
open={canvasMediaTarget !== null}
|
|
1120
|
-
onClose={() => setCanvasMediaTarget(null)}
|
|
1121
|
-
accept="image/*"
|
|
1122
|
-
onSelectItem={(item) => {
|
|
1123
|
-
if (!canvasMediaTarget) return
|
|
1124
|
-
const { sectionId, fieldPath } = canvasMediaTarget
|
|
1125
|
-
const { widthPath, heightPath } = companionDimensionPaths(fieldPath)
|
|
1126
|
-
// Media Replace must echo sections so the canvas image updates.
|
|
1127
|
-
mutateSections((s) => {
|
|
1128
|
-
let next = updateSectionContentAtPath(s, sectionId, fieldPath, item.url)
|
|
1129
|
-
if (typeof item.width === 'number') {
|
|
1130
|
-
next = updateSectionContentAtPath(next, sectionId, widthPath, item.width)
|
|
1131
|
-
}
|
|
1132
|
-
if (typeof item.height === 'number') {
|
|
1133
|
-
next = updateSectionContentAtPath(next, sectionId, heightPath, item.height)
|
|
1134
|
-
}
|
|
1135
|
-
return next
|
|
1136
|
-
})
|
|
1137
|
-
setCanvasMediaTarget(null)
|
|
1138
|
-
}}
|
|
1139
|
-
onSelect={() => setCanvasMediaTarget(null)}
|
|
1140
|
-
/>
|
|
1141
1084
|
</ErrorBoundary>
|
|
1142
1085
|
)
|
|
1143
1086
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { Puzzle } from 'lucide-react'
|
|
4
|
+
import { fieldPathFromEventTarget } from '../../../lib/preview-bridge.js'
|
|
4
5
|
import type { PageSection } from '../../../lib/page-editor-service.js'
|
|
5
6
|
import { ErrorBoundary } from '../../../components/ErrorBoundary.js'
|
|
6
7
|
import { getSectionType } from '../section-types.js'
|
|
@@ -163,7 +164,7 @@ export interface SectionRendererProps {
|
|
|
163
164
|
* renders hidden sections muted instead of removing them. */
|
|
164
165
|
editable?: boolean
|
|
165
166
|
selected?: boolean
|
|
166
|
-
onSelect?: (id: string) => void
|
|
167
|
+
onSelect?: (id: string, fieldPath?: string) => void
|
|
167
168
|
/** Lets the canvas register the DOM node for scroll-to-section. */
|
|
168
169
|
registerRef?: (id: string, el: HTMLElement | null) => void
|
|
169
170
|
/** Live post data for post-oriented section renderers (pages omit this). */
|
|
@@ -234,7 +235,9 @@ export function SectionRenderer({
|
|
|
234
235
|
? 'outline-transparent hover:outline hover:outline-[color-mix(in_oklab,var(--acc)_40%,transparent)]'
|
|
235
236
|
: 'outline-transparent'
|
|
236
237
|
}`}
|
|
237
|
-
onClick={
|
|
238
|
+
onClick={
|
|
239
|
+
interactive ? (e) => onSelect?.(section.id, fieldPathFromEventTarget(e.target)) : undefined
|
|
240
|
+
}
|
|
238
241
|
// Selection is a convenience in the editor; the section list is the
|
|
239
242
|
// primary, fully-accessible control surface, so this stays a region.
|
|
240
243
|
aria-label={
|
|
@@ -17,7 +17,7 @@ interface PostEditorCanvasProps {
|
|
|
17
17
|
selectedId: string | null
|
|
18
18
|
viewport: ViewportId
|
|
19
19
|
zoom?: Zoom
|
|
20
|
-
onSelect: (id: string) => void
|
|
20
|
+
onSelect: (id: string, fieldPath?: string) => void
|
|
21
21
|
onScaleChange?: (scale: number) => void
|
|
22
22
|
onCanvasElement?: (el: HTMLElement | null) => void
|
|
23
23
|
/** Add-section CTA on the empty canvas. Omitted by design-owned editors. */
|
|
@@ -20,14 +20,12 @@ 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'
|
|
31
29
|
import { SharePreviewLinkDialog } from '../../components/SharePreviewLinkDialog.js'
|
|
32
30
|
import { defaultPostHeader } from '@prenta/core/page-sections'
|
|
33
31
|
import { openPublicSiteTab } from '../../lib/open-public-site-tab.js'
|
|
@@ -47,7 +45,7 @@ import { buildEditorContentHtml, computeLiveSeoScore } from '../../lib/editor-se
|
|
|
47
45
|
import { snapshotBaseline, type ReflowBaseline } from '../../lib/reflow-baseline.js'
|
|
48
46
|
import { ReflowContext } from '../page-editor/reflow-context.js'
|
|
49
47
|
import type { Zoom } from '../../lib/breakpoints.js'
|
|
50
|
-
import {
|
|
48
|
+
import { inspectorIdFromFieldPath } from '../../lib/preview-bridge.js'
|
|
51
49
|
import { PostEditorCanvas } from './PostEditorCanvas.js'
|
|
52
50
|
import { PostFieldsModal, type PostFieldConfig } from './PostFieldsModal.js'
|
|
53
51
|
|
|
@@ -108,13 +106,6 @@ export function PostSectionEditor({
|
|
|
108
106
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
|
109
107
|
/** Canvas field click — focused after the inspector mounts for `selectedId`. */
|
|
110
108
|
const [pendingFocusPath, setPendingFocusPath] = useState<string | null>(null)
|
|
111
|
-
/** Bump to skip the next `prenta-preview:sections` echo after a canvas text edit. */
|
|
112
|
-
const [suppressSectionsEcho, setSuppressSectionsEcho] = useState(0)
|
|
113
|
-
/** Canvas image Replace — opens MediaPickerModal for this field path. */
|
|
114
|
-
const [canvasMediaTarget, setCanvasMediaTarget] = useState<{
|
|
115
|
-
sectionId: string
|
|
116
|
-
fieldPath: string
|
|
117
|
-
} | null>(null)
|
|
118
109
|
const [viewport, setViewport] = useState<ViewportId>(DEFAULT_VIEWPORT)
|
|
119
110
|
const [zoom, setZoom] = useState<Zoom>('fit')
|
|
120
111
|
/** Scale the canvas measured — reported upward so the zoom chip shows a real %. */
|
|
@@ -158,7 +149,7 @@ export function PostSectionEditor({
|
|
|
158
149
|
|
|
159
150
|
const { canEdit, canPublish } = useMemo(() => deriveCan(session), [session])
|
|
160
151
|
const customRenderers = useAdminSectionRenderers()
|
|
161
|
-
const { siteUrl: publicSiteUrl } = usePublicSiteUrl(config?.seo?.siteUrl)
|
|
152
|
+
const { siteUrl: publicSiteUrl, matchesAdminOrigin } = usePublicSiteUrl(config?.seo?.siteUrl)
|
|
162
153
|
|
|
163
154
|
const typeLabel = useMemo(() => {
|
|
164
155
|
const col = config?.collections?.[postType]
|
|
@@ -485,32 +476,11 @@ export function PostSectionEditor({
|
|
|
485
476
|
setRailTab('sections')
|
|
486
477
|
setPendingFocusPath(fieldPath ?? null)
|
|
487
478
|
// Toggles, because selection is now disclosure — see the note on the page
|
|
488
|
-
// editor's copy. A `fieldPath` means
|
|
489
|
-
//
|
|
479
|
+
// editor's copy. A `fieldPath` means a canvas field click, which must
|
|
480
|
+
// open rather than toggle.
|
|
490
481
|
setSelectedId((current) => (fieldPath ? id : current === id ? null : id))
|
|
491
482
|
}, [])
|
|
492
483
|
|
|
493
|
-
const handleCanvasEdit = useCallback(
|
|
494
|
-
(edit: { sectionId: string; fieldPath: string; value: string }) => {
|
|
495
|
-
if (!canEdit) return
|
|
496
|
-
setSuppressSectionsEcho((n) => n + 1)
|
|
497
|
-
mutateSections((s) =>
|
|
498
|
-
updateSectionContentAtPath(s, edit.sectionId, edit.fieldPath, edit.value),
|
|
499
|
-
)
|
|
500
|
-
setSelectedId(edit.sectionId)
|
|
501
|
-
},
|
|
502
|
-
[canEdit, mutateSections],
|
|
503
|
-
)
|
|
504
|
-
|
|
505
|
-
const handleCanvasRequestMedia = useCallback(
|
|
506
|
-
(request: { sectionId: string; fieldPath: string }) => {
|
|
507
|
-
if (!canEdit) return
|
|
508
|
-
setSelectedId(request.sectionId)
|
|
509
|
-
setCanvasMediaTarget(request)
|
|
510
|
-
},
|
|
511
|
-
[canEdit],
|
|
512
|
-
)
|
|
513
|
-
|
|
514
484
|
// After a canvas field click, focus the matching inspector input once painted.
|
|
515
485
|
useEffect(() => {
|
|
516
486
|
if (!pendingFocusPath || !selectedId) return
|
|
@@ -634,6 +604,7 @@ export function PostSectionEditor({
|
|
|
634
604
|
onViewOnSite={post.id && post.slug ? handleViewOnSite : undefined}
|
|
635
605
|
onShare={post.id ? handleShare : undefined}
|
|
636
606
|
hasPublicSiteUrl={Boolean(publicSiteUrl)}
|
|
607
|
+
matchesAdminOrigin={matchesAdminOrigin}
|
|
637
608
|
onHistory={post.id ? () => setHistoryOpen(true) : undefined}
|
|
638
609
|
onOpenSettings={() => setFieldsOpen(true)}
|
|
639
610
|
onOpenSeo={handleToggleSeo}
|
|
@@ -817,29 +788,6 @@ export function PostSectionEditor({
|
|
|
817
788
|
cancelLabel="Stay"
|
|
818
789
|
destructive
|
|
819
790
|
/>
|
|
820
|
-
|
|
821
|
-
<MediaPickerModal
|
|
822
|
-
open={canvasMediaTarget !== null}
|
|
823
|
-
onClose={() => setCanvasMediaTarget(null)}
|
|
824
|
-
accept="image/*"
|
|
825
|
-
onSelectItem={(item) => {
|
|
826
|
-
if (!canvasMediaTarget) return
|
|
827
|
-
const { sectionId, fieldPath } = canvasMediaTarget
|
|
828
|
-
const { widthPath, heightPath } = companionDimensionPaths(fieldPath)
|
|
829
|
-
mutateSections((s) => {
|
|
830
|
-
let next = updateSectionContentAtPath(s, sectionId, fieldPath, item.url)
|
|
831
|
-
if (typeof item.width === 'number') {
|
|
832
|
-
next = updateSectionContentAtPath(next, sectionId, widthPath, item.width)
|
|
833
|
-
}
|
|
834
|
-
if (typeof item.height === 'number') {
|
|
835
|
-
next = updateSectionContentAtPath(next, sectionId, heightPath, item.height)
|
|
836
|
-
}
|
|
837
|
-
return next
|
|
838
|
-
})
|
|
839
|
-
setCanvasMediaTarget(null)
|
|
840
|
-
}}
|
|
841
|
-
onSelect={() => setCanvasMediaTarget(null)}
|
|
842
|
-
/>
|
|
843
791
|
</ErrorBoundary>
|
|
844
792
|
)
|
|
845
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" />
|