2023-08-28 01:28:05 +00:00
|
|
|
// Reference: https://github.com/WordPress/gutenberg/tree/v16.4.0/packages/edit-site/src/components/layout/index.js
|
|
|
|
/* eslint-disable @woocommerce/dependency-group */
|
|
|
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2024-05-31 03:49:36 +00:00
|
|
|
import clsx from 'clsx';
|
2023-08-28 01:28:05 +00:00
|
|
|
import {
|
|
|
|
useReducedMotion,
|
|
|
|
useResizeObserver,
|
|
|
|
useViewportMatch,
|
|
|
|
} from '@wordpress/compose';
|
|
|
|
import { __ } from '@wordpress/i18n';
|
2023-12-21 15:56:22 +00:00
|
|
|
import { useState, useContext, useEffect } from '@wordpress/element';
|
2023-08-28 01:28:05 +00:00
|
|
|
import {
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
__unstableMotion as motion,
|
|
|
|
} from '@wordpress/components';
|
|
|
|
import {
|
|
|
|
privateApis as blockEditorPrivateApis,
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
} from '@wordpress/block-editor';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import useInitEditedEntityFromURL from '@wordpress/edit-site/build-module/components/sync-state-with-url/use-init-edited-entity-from-url';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { useIsSiteEditorLoading } from '@wordpress/edit-site/build-module/components/layout/hooks';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import ErrorBoundary from '@wordpress/edit-site/build-module/components/error-boundary';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { unlock } from '@wordpress/edit-site/build-module/lock-unlock';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { NavigableRegion } from '@wordpress/interface';
|
2023-09-14 08:24:46 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { EntityProvider } from '@wordpress/core-data';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import useEditedEntityRecord from '@wordpress/edit-site/build-module/components/use-edited-entity-record';
|
2023-09-05 06:21:19 +00:00
|
|
|
|
2023-08-28 01:28:05 +00:00
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { Editor } from './editor';
|
|
|
|
import Sidebar from './sidebar';
|
|
|
|
import { SiteHub } from './site-hub';
|
2023-09-05 06:21:19 +00:00
|
|
|
import { LogoBlockContext } from './logo-block-context';
|
|
|
|
import ResizableFrame from './resizable-frame';
|
2023-09-05 07:12:04 +00:00
|
|
|
import { OnboardingTour, useOnboardingTour } from './onboarding-tour';
|
2023-09-14 08:24:46 +00:00
|
|
|
import { HighlightedBlockContextProvider } from './context/highlighted-block-context';
|
2023-10-05 12:36:08 +00:00
|
|
|
import { Transitional } from '../transitional';
|
|
|
|
import { CustomizeStoreContext } from './';
|
2023-12-21 15:56:22 +00:00
|
|
|
import { AiOfflineModal } from '~/customize-store/assembler-hub/onboarding-tour/ai-offline-modal';
|
|
|
|
import { useQuery } from '@woocommerce/navigation';
|
2024-01-09 14:49:59 +00:00
|
|
|
import { FlowType } from '../types';
|
2024-01-11 15:12:41 +00:00
|
|
|
import { isOfflineAIFlow } from '../guards';
|
2024-01-30 08:58:05 +00:00
|
|
|
import { isWooExpress } from '~/utils/is-woo-express';
|
2024-04-23 17:38:06 +00:00
|
|
|
import { trackEvent } from '../tracking';
|
2024-06-18 12:16:16 +00:00
|
|
|
import { SidebarNavigationExtraScreen } from './sidebar/navigation-extra-screen/sidebar-navigation-extra-screen';
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
const { useGlobalStyle } = unlock( blockEditorPrivateApis );
|
|
|
|
|
2024-08-09 15:15:06 +00:00
|
|
|
const ANIMATION_DURATION = 0.5;
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
export const Layout = () => {
|
2023-10-25 04:20:42 +00:00
|
|
|
const [ logoBlockIds, setLogoBlockIds ] = useState< Array< string > >( [] );
|
2023-12-21 15:56:22 +00:00
|
|
|
|
|
|
|
const { sendEvent, currentState, context } = useContext(
|
|
|
|
CustomizeStoreContext
|
|
|
|
);
|
|
|
|
|
|
|
|
const { customizing } = useQuery();
|
|
|
|
|
|
|
|
const [ showAiOfflineModal, setShowAiOfflineModal ] = useState(
|
2024-01-11 15:12:41 +00:00
|
|
|
isOfflineAIFlow( context.flowType ) && customizing !== 'true'
|
2023-12-21 15:56:22 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
useEffect( () => {
|
2024-01-11 15:12:41 +00:00
|
|
|
setShowAiOfflineModal(
|
|
|
|
isOfflineAIFlow( context.flowType ) && customizing !== 'true'
|
|
|
|
);
|
|
|
|
}, [ context.flowType, customizing ] );
|
2023-12-21 15:56:22 +00:00
|
|
|
|
2023-08-28 01:28:05 +00:00
|
|
|
// This ensures the edited entity id and type are initialized properly.
|
|
|
|
useInitEditedEntityFromURL();
|
2023-12-21 15:56:22 +00:00
|
|
|
const {
|
|
|
|
shouldTourBeShown,
|
|
|
|
isResizeHandleVisible,
|
|
|
|
setShowWelcomeTour,
|
|
|
|
onClose,
|
|
|
|
...onboardingTourProps
|
|
|
|
} = useOnboardingTour();
|
|
|
|
|
|
|
|
const takeTour = () => {
|
|
|
|
// Click on "Take a tour" button
|
2024-04-23 17:38:06 +00:00
|
|
|
trackEvent( 'customize_your_store_assembler_hub_tour_start' );
|
2023-12-21 15:56:22 +00:00
|
|
|
setShowWelcomeTour( false );
|
|
|
|
setShowAiOfflineModal( false );
|
|
|
|
};
|
|
|
|
|
|
|
|
const skipTour = () => {
|
2024-04-23 17:38:06 +00:00
|
|
|
trackEvent( 'customize_your_store_assembler_hub_tour_skip' );
|
2023-12-21 15:56:22 +00:00
|
|
|
onClose();
|
|
|
|
setShowAiOfflineModal( false );
|
|
|
|
};
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
const isMobileViewport = useViewportMatch( 'medium', '<' );
|
|
|
|
const disableMotion = useReducedMotion();
|
|
|
|
const [ canvasResizer, canvasSize ] = useResizeObserver();
|
|
|
|
const isEditorLoading = useIsSiteEditorLoading();
|
2023-09-05 06:21:19 +00:00
|
|
|
const [ isResizableFrameOversized, setIsResizableFrameOversized ] =
|
|
|
|
useState( false );
|
2023-08-28 01:28:05 +00:00
|
|
|
const [ backgroundColor ] = useGlobalStyle( 'color.background' );
|
|
|
|
const [ gradientValue ] = useGlobalStyle( 'color.gradient' );
|
|
|
|
|
2023-09-14 08:24:46 +00:00
|
|
|
const { record: template } = useEditedEntityRecord();
|
|
|
|
const { id: templateId, type: templateType } = template;
|
|
|
|
|
2023-11-07 09:34:20 +00:00
|
|
|
const [ isSurveyOpen, setSurveyOpen ] = useState( false );
|
2023-10-05 12:36:08 +00:00
|
|
|
const editor = <Editor isLoading={ isEditorLoading } />;
|
|
|
|
|
2023-11-10 08:35:46 +00:00
|
|
|
if (
|
|
|
|
typeof currentState === 'object' &&
|
|
|
|
currentState.transitionalScreen === 'transitional'
|
|
|
|
) {
|
2023-10-05 12:36:08 +00:00
|
|
|
return (
|
|
|
|
<EntityProvider kind="root" type="site">
|
|
|
|
<EntityProvider
|
|
|
|
kind="postType"
|
|
|
|
type={ templateType }
|
|
|
|
id={ templateId }
|
|
|
|
>
|
2023-11-07 09:34:20 +00:00
|
|
|
<Transitional
|
|
|
|
sendEvent={ sendEvent }
|
2024-01-30 08:58:05 +00:00
|
|
|
isWooExpress={ isWooExpress() }
|
2023-11-07 09:34:20 +00:00
|
|
|
isSurveyOpen={ isSurveyOpen }
|
|
|
|
setSurveyOpen={ setSurveyOpen }
|
2023-11-10 08:35:46 +00:00
|
|
|
hasCompleteSurvey={
|
|
|
|
!! context?.transitionalScreen?.hasCompleteSurvey
|
|
|
|
}
|
2024-01-09 14:49:59 +00:00
|
|
|
aiOnline={ context?.flowType === FlowType.AIOnline }
|
2023-11-07 09:34:20 +00:00
|
|
|
/>
|
2023-10-05 12:36:08 +00:00
|
|
|
</EntityProvider>
|
|
|
|
</EntityProvider>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-08-28 01:28:05 +00:00
|
|
|
return (
|
2024-03-12 14:05:12 +00:00
|
|
|
// This causes the editor to re-render when the logo block ids change. Maybe we can find a better way to do this.
|
2023-09-05 06:21:19 +00:00
|
|
|
<LogoBlockContext.Provider
|
|
|
|
value={ {
|
2023-10-25 04:20:42 +00:00
|
|
|
logoBlockIds,
|
|
|
|
setLogoBlockIds,
|
2023-09-05 06:21:19 +00:00
|
|
|
} }
|
|
|
|
>
|
2023-09-14 08:24:46 +00:00
|
|
|
<HighlightedBlockContextProvider>
|
|
|
|
<EntityProvider kind="root" type="site">
|
|
|
|
<EntityProvider
|
|
|
|
kind="postType"
|
|
|
|
type={ templateType }
|
|
|
|
id={ templateId }
|
2023-08-28 01:28:05 +00:00
|
|
|
>
|
2024-05-31 03:49:36 +00:00
|
|
|
<div className={ clsx( 'edit-site-layout' ) }>
|
2023-09-14 08:24:46 +00:00
|
|
|
<motion.div
|
|
|
|
className="edit-site-layout__header-container"
|
|
|
|
animate={ 'view' }
|
|
|
|
>
|
|
|
|
<SiteHub
|
|
|
|
as={ motion.div }
|
|
|
|
variants={ {
|
|
|
|
view: { x: 0 },
|
2023-09-05 06:21:19 +00:00
|
|
|
} }
|
2023-09-14 08:24:46 +00:00
|
|
|
isTransparent={ false }
|
|
|
|
className="edit-site-layout__hub"
|
|
|
|
/>
|
|
|
|
</motion.div>
|
|
|
|
|
|
|
|
<div className="edit-site-layout__content">
|
2024-06-18 12:16:16 +00:00
|
|
|
<div className="edit-site-layout__sidebar">
|
|
|
|
<NavigableRegion
|
|
|
|
ariaLabel={ __(
|
|
|
|
'Navigation',
|
|
|
|
'woocommerce'
|
|
|
|
) }
|
|
|
|
className="edit-site-layout__sidebar-region"
|
2023-09-14 08:24:46 +00:00
|
|
|
>
|
2024-06-18 12:16:16 +00:00
|
|
|
<motion.div
|
|
|
|
animate={ { opacity: 1 } }
|
|
|
|
transition={ {
|
|
|
|
type: 'tween',
|
|
|
|
duration:
|
|
|
|
// Disable transitiont in mobile to emulate a full page transition.
|
|
|
|
disableMotion ||
|
|
|
|
isMobileViewport
|
|
|
|
? 0
|
|
|
|
: ANIMATION_DURATION,
|
|
|
|
ease: 'easeOut',
|
|
|
|
} }
|
|
|
|
className="edit-site-layout__sidebar"
|
|
|
|
>
|
|
|
|
<Sidebar />
|
|
|
|
</motion.div>
|
|
|
|
</NavigableRegion>
|
|
|
|
<SidebarNavigationExtraScreen />
|
|
|
|
</div>
|
2023-09-14 08:24:46 +00:00
|
|
|
|
|
|
|
{ ! isMobileViewport && (
|
2023-11-03 05:57:41 +00:00
|
|
|
<div className="edit-site-layout__canvas-container">
|
2023-09-14 08:24:46 +00:00
|
|
|
{ canvasResizer }
|
|
|
|
{ !! canvasSize.width && (
|
|
|
|
<motion.div
|
|
|
|
initial={ false }
|
|
|
|
layout="position"
|
2024-05-31 03:49:36 +00:00
|
|
|
className={ clsx(
|
2023-09-14 08:24:46 +00:00
|
|
|
'edit-site-layout__canvas'
|
|
|
|
) }
|
|
|
|
>
|
|
|
|
<ErrorBoundary>
|
|
|
|
<ResizableFrame
|
|
|
|
isReady={
|
|
|
|
! isEditorLoading
|
|
|
|
}
|
2023-10-26 10:15:30 +00:00
|
|
|
isHandleVisibleByDefault={
|
|
|
|
! onboardingTourProps.showWelcomeTour &&
|
|
|
|
isResizeHandleVisible
|
2023-09-14 08:24:46 +00:00
|
|
|
}
|
|
|
|
isFullWidth={ false }
|
|
|
|
defaultSize={ {
|
|
|
|
width:
|
|
|
|
canvasSize.width -
|
|
|
|
24 /* $canvas-padding */,
|
|
|
|
height: canvasSize.height,
|
|
|
|
} }
|
|
|
|
isOversized={
|
|
|
|
isResizableFrameOversized
|
|
|
|
}
|
|
|
|
setIsOversized={
|
|
|
|
setIsResizableFrameOversized
|
|
|
|
}
|
|
|
|
innerContentStyle={ {
|
|
|
|
background:
|
|
|
|
gradientValue ??
|
|
|
|
backgroundColor,
|
|
|
|
} }
|
|
|
|
>
|
2023-10-05 12:36:08 +00:00
|
|
|
{ editor }
|
2023-09-14 08:24:46 +00:00
|
|
|
</ResizableFrame>
|
|
|
|
</ErrorBoundary>
|
|
|
|
</motion.div>
|
|
|
|
) }
|
|
|
|
</div>
|
|
|
|
) }
|
|
|
|
</div>
|
2023-09-05 06:21:19 +00:00
|
|
|
</div>
|
2023-12-21 15:56:22 +00:00
|
|
|
{ ! isEditorLoading &&
|
|
|
|
shouldTourBeShown &&
|
2024-01-11 14:32:16 +00:00
|
|
|
( FlowType.AIOnline === context.flowType ||
|
|
|
|
FlowType.noAI === context.flowType ) && (
|
2023-12-21 15:56:22 +00:00
|
|
|
<OnboardingTour
|
|
|
|
skipTour={ skipTour }
|
|
|
|
takeTour={ takeTour }
|
|
|
|
onClose={ onClose }
|
2024-01-11 14:32:16 +00:00
|
|
|
flowType={ context.flowType }
|
2023-12-21 15:56:22 +00:00
|
|
|
{ ...onboardingTourProps }
|
|
|
|
/>
|
|
|
|
) }
|
|
|
|
|
|
|
|
{ ! isEditorLoading && showAiOfflineModal && (
|
|
|
|
<AiOfflineModal
|
|
|
|
shouldTourBeShown={ shouldTourBeShown }
|
|
|
|
skipTour={ skipTour }
|
|
|
|
takeTour={ takeTour }
|
|
|
|
/>
|
2023-09-14 08:24:46 +00:00
|
|
|
) }
|
|
|
|
</EntityProvider>
|
|
|
|
</EntityProvider>
|
|
|
|
</HighlightedBlockContextProvider>
|
2023-09-05 06:21:19 +00:00
|
|
|
</LogoBlockContext.Provider>
|
2023-08-28 01:28:05 +00:00
|
|
|
);
|
|
|
|
};
|