diff --git a/client/landing/gutenboarding/available-designs.ts b/client/landing/gutenboarding/available-designs.ts index 9bf50a3f2d95b..8f58d7bd52649 100644 --- a/client/landing/gutenboarding/available-designs.ts +++ b/client/landing/gutenboarding/available-designs.ts @@ -7,6 +7,7 @@ import { addQueryArgs } from '@wordpress/url'; * Internal dependencies */ import { isEnabled } from '../../config'; +import { mshotsUrl } from './components/mshots-image'; import type { Design } from './stores/onboard/types'; const availableDesignsConfig = require( './available-designs-config.json' ); @@ -26,45 +27,40 @@ function getCanUseWebP() { return false; } -const canUseWebP = getCanUseWebP(); - -export const getDesignImageUrl = ( design: Design ) => { - // We temporarily show pre-generated screenshots until we can generate tall versions dynamically using mshots. - // See `bin/generate-gutenboarding-design-thumbnails.js` for generating screenshots. - // https://github.com/Automattic/mShots/issues/16 - // https://github.com/Automattic/wp-calypso/issues/40564 - if ( ! isEnabled( 'gutenboarding/mshot-preview' ) ) { - // When we update the static images, bump the version for cache busting - return `/calypso/images/design-screenshots/${ design.slug }_${ design.template }_${ - design.theme - }.${ canUseWebP ? 'webp' : 'jpg' }?v=3`; - } +export const getDesignUrl = ( design: Design, locale: string ): string => { + const theme = encodeURIComponent( design.theme ); + const template = encodeURIComponent( design.template ); - const mshotsUrl = 'https://s.wordpress.com/mshots/v1/'; - const designsEndpoint = 'https://public-api.wordpress.com/rest/v1/template/demo/'; - const previewUrl = addQueryArgs( - `${ designsEndpoint }${ encodeURIComponent( design.theme ) }/${ encodeURIComponent( - design.template - ) }`, + return addQueryArgs( + `https://public-api.wordpress.com/rest/v1/template/demo/${ theme }/${ template }`, { font_headings: design.fonts.headings, font_base: design.fonts.base, + site_title: design.title, + viewport_height: 700, // todo: this is part of the issue with rockfield, a value of 3072 here fixes the background image + language: locale, } ); - return mshotsUrl + encodeURIComponent( previewUrl ); }; -/** - * Asynchronously load available design images - */ -export function prefetchDesignThumbs() { +const canUseWebP = getCanUseWebP(); + +export const getDesignImageUrl = ( design: Design ): string => { + return `/calypso/images/design-screenshots/${ design.slug }_${ design.template }_${ + design.theme + }.${ canUseWebP ? 'webp' : 'jpg' }?v=3`; +}; + +// Asynchronously load available design images +export function prefetchDesignThumbs( locale: string ): void { if ( typeof window !== 'undefined' ) { getAvailableDesigns().featured.forEach( ( design: Design ) => { - const href = getDesignImageUrl( design ); + const href = mshotsUrl( getDesignUrl( design, locale ) ); const link = document.createElement( 'link' ); link.rel = 'prefetch'; link.as = 'image'; link.href = href; + link.crossOrigin = 'anonymous'; document.head.appendChild( link ); } ); } @@ -73,7 +69,7 @@ export function prefetchDesignThumbs() { export function getAvailableDesigns( includeAlphaDesigns: boolean = isEnabled( 'gutenboarding/alpha-templates' ), useFseDesigns: boolean = isEnabled( 'gutenboarding/site-editor' ) -) { +): AvailableDesigns { let designs = availableDesigns; if ( ! includeAlphaDesigns ) { diff --git a/client/landing/gutenboarding/components/mshots-image/index.tsx b/client/landing/gutenboarding/components/mshots-image/index.tsx new file mode 100644 index 0000000000000..6a4cd26b4c536 --- /dev/null +++ b/client/landing/gutenboarding/components/mshots-image/index.tsx @@ -0,0 +1,72 @@ +/** + * External dependencies + */ +import React, { useState } from 'react'; +import classnames from 'classnames'; +import { addQueryArgs } from '@wordpress/url'; + +/** + * Style dependencies + */ +import './style.scss'; + +interface MShotsImageProps { + url: string; + alt: string; + 'aria-labelledby': string; +} + +const mShotsParams = { + // viewport size (how much of the source page to capture) + vpw: 1200, + vph: 3072, + // size of the resulting image + w: 700, + h: 1800, +}; + +export function mshotsUrl( url: string, count = 0 ): string { + const mshotsUrl = 'https://s0.wp.com/mshots/v1/'; + const mshotsRequest = addQueryArgs( mshotsUrl + encodeURIComponent( url ), { + ...mShotsParams, + // this doesn't seem to work: + // requeue: true, // Uncomment this line to force the screenshots to be regenerated + count, + } ); + return mshotsRequest; +} + +const MShotsImage = ( { + url, + 'aria-labelledby': labelledby, + alt, +}: MShotsImageProps ): JSX.Element => { + const [ count, setCount ] = React.useState( 0 ); + const [ visible, setVisible ] = useState( false ); + return ( +
+ { ! visible &&
} + { { + // Test against mshots h value + if ( e.currentTarget.naturalHeight !== mShotsParams.h ) { + // Only refresh 10 times. + if ( count < 10 ) { + // Triggers a target.src change + setTimeout( () => setCount( count + 1 ), 1000 ); + } + } else { + setVisible( true ); + } + } } + /> +
+ ); +}; + +export default MShotsImage; diff --git a/client/landing/gutenboarding/components/mshots-image/style.scss b/client/landing/gutenboarding/components/mshots-image/style.scss new file mode 100644 index 0000000000000..31804b49312b5 --- /dev/null +++ b/client/landing/gutenboarding/components/mshots-image/style.scss @@ -0,0 +1,19 @@ +@import '../../mixins.scss'; + +.mshots-image { + opacity: 0; + transition: 0.3s opacity; +} + +.mshots-image__loader { + @include onboarding-placeholder(); + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; +} + +.mshots-image-visible { + opacity: 1; +} diff --git a/client/landing/gutenboarding/onboarding-block/design-selector/index.tsx b/client/landing/gutenboarding/onboarding-block/design-selector/index.tsx index ff556dd2499c1..925e6393a536b 100644 --- a/client/landing/gutenboarding/onboarding-block/design-selector/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/design-selector/index.tsx @@ -4,6 +4,7 @@ import { Tooltip } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { useI18n } from '@automattic/react-i18n'; +import { useLocale } from '@automattic/i18n-utils'; import React from 'react'; import { Title, SubTitle, ActionButtons, BackButton } from '@automattic/onboarding'; @@ -15,10 +16,12 @@ import { STORE_KEY as ONBOARD_STORE } from '../../stores/onboard'; import { useTrackStep } from '../../hooks/use-track-step'; import useStepNavigation from '../../hooks/use-step-navigation'; import Badge from '../../components/badge'; -import { getDesignImageUrl } from '../../available-designs'; +import MShotsImage from '../../components/mshots-image'; +import { getDesignImageUrl, getDesignUrl } from '../../available-designs'; import JetpackLogo from 'calypso/components/jetpack-logo'; // @TODO: extract to @automattic package import type { Design } from '../../stores/onboard/types'; import { useIsAnchorFm } from '../../path'; +import { isEnabled } from 'calypso/config'; /** * Style dependencies @@ -29,6 +32,7 @@ const makeOptionId = ( { slug }: Design ): string => `design-selector__option-na const DesignSelector: React.FunctionComponent = () => { const { __ } = useI18n(); + const locale = useLocale(); const { goBack, goNext } = useStepNavigation(); const { setSelectedDesign, setFonts } = useDispatch( ONBOARD_STORE ); @@ -85,11 +89,19 @@ const DesignSelector: React.FunctionComponent = () => { } } > - + { isEnabled( 'gutenboarding/mshot-preview' ) ? ( + + ) : ( + + ) }