diff --git a/src/app/components/AppBody/AppBody.js b/src/app/components/AppBody/AppBody.js index ace104476..19a2a30d3 100644 --- a/src/app/components/AppBody/AppBody.js +++ b/src/app/components/AppBody/AppBody.js @@ -69,7 +69,7 @@ const AppBody = () => { }, [ location ] ); return ( -
+
{ boot() }
diff --git a/src/app/components/BackButton/BackButton.js b/src/app/components/BackButton/BackButton.js new file mode 100644 index 000000000..63991e9d8 --- /dev/null +++ b/src/app/components/BackButton/BackButton.js @@ -0,0 +1,30 @@ +import { ArrowLeftIcon } from '@heroicons/react/24/outline'; +import Navigate from '../Navigate/Navigate'; + +/** + * BackButton component for header navigation. + * + * @param {Object} props - Component props + * @param {string} props.toRoute - The route to navigate back to + * @param {boolean} props.disabled - Whether the button is disabled + * @return {JSX.Element} A back button with icon and optional text + */ +const BackButton = ( { toRoute = '/', disabled = false } ) => { + return ( + + + + { __( 'Back', 'wp-module-onboarding' ) } + + + ); +}; + +export default BackButton; + diff --git a/src/app/components/BackButton/index.js b/src/app/components/BackButton/index.js new file mode 100644 index 000000000..9c149b3e5 --- /dev/null +++ b/src/app/components/BackButton/index.js @@ -0,0 +1,2 @@ +export { default as BackButton } from './BackButton'; + diff --git a/src/app/components/BrandLoader/BrandLoader.js b/src/app/components/BrandLoader/BrandLoader.js new file mode 100644 index 000000000..5593ae778 --- /dev/null +++ b/src/app/components/BrandLoader/BrandLoader.js @@ -0,0 +1,58 @@ +import { useSelect } from '@wordpress/data'; +import { nfdOnboardingStore } from '@/data/store'; +import bluehostLogo from '../../../Brands/bluehost/step-loader-logo.svg'; +import hostgatorLogo from '../../../Brands/hostgator/step-loader-logo.svg'; +import crazyDomainsLogo from '../../../Brands/crazy-domains/step-loader-logo.svg'; +import webcomLogo from '../../../Brands/webcom/logo.svg'; +import wordpressLogo from '../../../Brands/wordpress/step-loader-logo.svg'; +import './BrandLoader.scss'; + +/** + * BrandLoader component - displays brand-specific loading animation + * + * @param {Object} props Component props + * @param {string} props.width Width of the loader (default: '120px') + * @param {string} props.height Height of the loader (default: '120px') + * @param {string} props.alt Alt text for the loader image + * @return {JSX.Element} Brand loader component + */ +const BrandLoader = ( { width = '120px', height = '120px', alt = 'Loading animation' } ) => { + const brandName = useSelect( ( select ) => { + return select( nfdOnboardingStore ).getBrandName(); + }, [] ); + + if ( ! brandName ) { + return null; + } + + const normalizedBrand = brandName.toLowerCase().replace( / /g, '-' ); + + // Map brand names to their imported logos + const brandLogoMap = { + bluehost: bluehostLogo, + 'bluehost-india': bluehostLogo, + hostgator: hostgatorLogo, + 'hostgator-us': hostgatorLogo, + 'hostgator-br': hostgatorLogo, + 'crazy-domains': crazyDomainsLogo, + webcom: webcomLogo, + wordpress: wordpressLogo, + }; + + const logoUrl = brandLogoMap[ normalizedBrand ] || wordpressLogo; + + return ( +
+ ); +}; + +export default BrandLoader; diff --git a/src/app/components/BrandLoader/BrandLoader.scss b/src/app/components/BrandLoader/BrandLoader.scss new file mode 100644 index 000000000..b85d68f47 --- /dev/null +++ b/src/app/components/BrandLoader/BrandLoader.scss @@ -0,0 +1,6 @@ +.brand-loader { + display: inline-block; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} diff --git a/src/app/components/BrandLoader/index.js b/src/app/components/BrandLoader/index.js new file mode 100644 index 000000000..b76a0dd4a --- /dev/null +++ b/src/app/components/BrandLoader/index.js @@ -0,0 +1 @@ +export { default as BrandLoader } from './BrandLoader'; diff --git a/src/app/components/Header/Header.js b/src/app/components/Header/Header.js index 3322db59d..dcd8e9de3 100644 --- a/src/app/components/Header/Header.js +++ b/src/app/components/Header/Header.js @@ -3,6 +3,16 @@ import { useLocation } from 'react-router-dom'; import { ReactComponent as BluehostLogo } from '@/assets/bluehost-logo.svg'; import { HeaderActions as CanvasStepHeaderActions } from '@/steps/Canvas'; import { HeaderActions as BlueprintCanvasStepHeaderActions } from '@/steps/BlueprintCanvas'; +import { BackButton } from '@/components'; + +// Map of routes that should show a back button in the header +const BACK_NAVIGATION_MAP = { + '/intake': '/', + '/logo': '/intake', + '/generating': '/logo', + '/previews': '/logo', + '/blueprints': '/', +}; const Header = () => { const [ isCanvasStep, setIsCanvasStep ] = useState( false ); @@ -23,6 +33,10 @@ const Header = () => { } }, [ location ] ); + // Determine if the current route should show a back button + const backRoute = BACK_NAVIGATION_MAP[ location.pathname ]; + const showBackButton = !! backRoute; + return (
{ ) } >
-
diff --git a/src/app/components/Iframe/Iframe.js b/src/app/components/Iframe/Iframe.js index 5e3a32385..79c6cad46 100644 --- a/src/app/components/Iframe/Iframe.js +++ b/src/app/components/Iframe/Iframe.js @@ -4,7 +4,7 @@ import { forwardRef } from '@wordpress/element'; const Iframe = forwardRef( ( { title, src, - width = 400, + width = 400, // eslint-disable-line no-unused-vars height = 400, viewportScale = 1, viewportWidth = 1440, @@ -18,8 +18,7 @@ const Iframe = forwardRef( ( { 'nfd-onboarding-iframe nfd-relative nfd-flex nfd-flex-col nfd-overflow-hidden', ) } style={ { - minWidth: width, - maxWidth: width, + width: '100%', minHeight: height, maxHeight: height, } } diff --git a/src/app/components/InteractionBlockingOverlay/InteractionBlockingOverlay.js b/src/app/components/InteractionBlockingOverlay/InteractionBlockingOverlay.js index 38dc3972d..890dd5884 100644 --- a/src/app/components/InteractionBlockingOverlay/InteractionBlockingOverlay.js +++ b/src/app/components/InteractionBlockingOverlay/InteractionBlockingOverlay.js @@ -1,4 +1,4 @@ -import { Spinner } from '@newfold/ui-component-library'; +import { BrandLoader } from '@/components'; const InteractionBlockingOverlay = ( { hasLoadingSpinner = false, @@ -8,11 +8,9 @@ const InteractionBlockingOverlay = ( { return (
{ hasLoadingSpinner && ( - +
+ +
) } { hasBackground && (
diff --git a/src/app/components/SiteGenPreviewCard/SiteGenPreviewCard.js b/src/app/components/SiteGenPreviewCard/SiteGenPreviewCard.js index bc474e18f..bec2debd3 100644 --- a/src/app/components/SiteGenPreviewCard/SiteGenPreviewCard.js +++ b/src/app/components/SiteGenPreviewCard/SiteGenPreviewCard.js @@ -2,14 +2,15 @@ import { Button, Spinner } from '@newfold/ui-component-library'; import classNames from 'classnames'; import { Iframe } from '@/components'; import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'; +import { useState } from '@wordpress/element'; const SiteGenPreviewCard = ( { screenshot, frameName, frameSrc, onFrameLoad = () => {}, - width = '300px', - height = '360px', + width = '280px', + height = '350px', viewportScale = 0.2, viewportWidth = 1500, viewportHeight = 2500, @@ -19,6 +20,8 @@ const SiteGenPreviewCard = ( { tabIndex = 0, onPreview, className, + title = '', + isNew = false, ...props } ) => { const handleOnPreview = () => { @@ -40,12 +43,7 @@ const SiteGenPreviewCard = ( {
) } - { isLoading && ( - - ) } + { isLoading && }
); }; @@ -63,7 +61,7 @@ const SiteGenPreviewCard = ( { variant="primary" className={ classNames( 'nfd-z-20 nfd-transition-opacity', - isHovered ? 'nfd-opacity-100' : 'nfd-opacity-0', + isHovered ? 'nfd-opacity-100' : 'nfd-opacity-0' ) } tabIndex="-1" > @@ -74,47 +72,59 @@ const SiteGenPreviewCard = ( { }; return ( -
{ - if ( event.key === 'Enter' ) { - handleOnPreview(); - } - } } - role="button" - tabIndex={ tabIndex } - { ...props } - > - { ( isLoading || isError ) && } - { overlay && ! isLoading && ! isError && } - { ! screenshot && frameSrc && ( -