diff --git a/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/ContentPreviewConfig.tsx b/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/ContentPreviewConfig.tsx index 4654de3ff43..ca61eae7a8f 100644 --- a/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/ContentPreviewConfig.tsx +++ b/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/ContentPreviewConfig.tsx @@ -4,6 +4,7 @@ import { Breadcrumbs } from "./Breadcrumbs/index.js"; import { DocumentPreview } from "./Preview/DocumentPreview.js"; import { AddressBar } from "./AddressBar/AddressBar.js"; import { BreakpointSelector } from "./AddressBar/BreakpointSelector.js"; +import { SampleFrontendBanner } from "./SampleFrontendBanner.js"; export const ContentPreviewConfig = () => { const { Ui } = EditorConfig; @@ -16,6 +17,11 @@ export const ContentPreviewConfig = () => { element={} /> } /> + } + /> } /> void; + /** + * Rendered on top of the preview instead of the loader. Used to explain why the preview is + * empty, while keeping the iframe mounted so that a late connection still resolves on its own. + */ + overlay?: React.ReactNode; } export const Iframe = observer(({ url, timestamp, ...props }: IframeProps) => { @@ -49,14 +54,15 @@ export const Iframe = observer(({ url, timestamp, ...props }: IframeProps) => { return ( - {props.showLoading ? ( - - ) : null} + {props.overlay ?? + (props.showLoading ? ( + + ) : null)} {/* Content wrapper - sized by iframe content */}
void; +} + +const COPY: Record = { + unreachable: { + title: "No frontend detected", + description: + "The editor renders your pages inside your own frontend, and nothing is currently running at" + }, + unresponsive: { + title: "Frontend didn't connect", + description: + "Something is running, but it never connected to the editor. Make sure the Website Builder SDK is set up in the app running at" + } +}; + +export const NoFrontendConnected = ({ origin, status, onRetry }: NoFrontendConnectedProps) => { + const { previewDomain, setPreviewDomain } = usePreviewDomain(); + + const loadSampleFrontend = useCallback(() => { + setPreviewDomain(SAMPLE_FRONTEND_DOMAIN); + }, [setPreviewDomain]); + + const openInstructions = useCallback(() => { + window.open(FRONTEND_SETUP_DOCS_URL, "_blank", "noopener,noreferrer"); + }, []); + + const copy = COPY[status]; + + // No point in offering the sample frontend when it's the domain that just failed to connect. + const canLoadSampleFrontend = previewDomain !== SAMPLE_FRONTEND_DOMAIN; + + return ( +
+ + {copy.description} {origin}. + + } + actions={ + <> +
+ ); +}; diff --git a/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/Preview/Preview.tsx b/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/Preview/Preview.tsx index 2ae468ddafd..903e5c97df0 100644 --- a/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/Preview/Preview.tsx +++ b/packages/app-website-builder/src/BaseEditor/defaultConfig/Content/Preview/Preview.tsx @@ -1,9 +1,8 @@ -import React, { useCallback, useEffect, useMemo, useState } from "react"; -import type { Messenger } from "@webiny/website-builder-sdk"; +import React, { useEffect, useMemo, useState } from "react"; import { ViewportManager } from "@webiny/website-builder-sdk"; import { mouseTracker } from "@webiny/website-builder-sdk"; import { useDocumentEditor } from "~/DocumentEditor/index.js"; -import { Iframe } from "./Iframe.js"; +import { PreviewFrame } from "./PreviewFrame.js"; import { DropZoneManager } from "./DropZoneManager.js"; import { DropZoneManagerProvider } from "./DropZoneManagerProvider.js"; import { KeyboardShortcuts } from "./KeyboardShortcuts.js"; @@ -82,21 +81,20 @@ export const Preview = () => { }; }, []); - const onConnected = useCallback((messenger: Messenger) => { - previewEvents.onConnected(messenger); - }, []); - return ( <> {({ url }) => ( -