From 7b86f1bb3f5c18378d89a7060b0a43d04482e6dd Mon Sep 17 00:00:00 2001 From: Griffith Chen Date: Wed, 11 Dec 2024 19:17:38 +0800 Subject: [PATCH 1/4] Delete Pattern Assembler --- .../shared/functions/_z-index.scss | 1 - .../stepper/declarative-flow/ai-assembler.ts | 12 - .../declarative-flow/assembler-first-flow.ts | 12 - .../stepper/declarative-flow/import-flow.ts | 19 - .../steps-repository/ai-site-prompt/index.tsx | 108 --- .../ai-site-prompt/style.scss | 46 - .../steps-repository/design-choices/index.tsx | 5 +- .../pattern-assembler/constants.ts | 99 --- .../pattern-assembler/events.ts | 72 -- .../pattern-assembler/hooks/index.ts | 14 - .../hooks/use-ai-assembler.ts | 83 -- .../hooks/use-assembler-patterns.ts | 47 - .../hooks/use-categories-order.ts | 27 - .../hooks/use-category-patterns-map.ts | 67 -- .../hooks/use-current-screen.tsx | 14 - .../hooks/use-custom-styles.tsx | 19 - .../hooks/use-global-styles-upgrade-props.tsx | 55 -- .../hooks/use-initial-path.ts | 22 - .../hooks/use-is-new-site.ts | 12 - .../hooks/use-pattern-categories.ts | 28 - .../use-pattern-count-map-by-category.ts | 22 - .../hooks/use-pattern-pages.ts | 133 --- .../pattern-assembler/hooks/use-recipe.ts | 208 ----- .../pattern-assembler/hooks/use-screen.tsx | 120 --- .../hooks/use-sync-navigator-screen.ts | 30 - .../html-transformers/index.tsx | 2 - .../inject-titles-to-page-list-block.ts | 26 - .../prepend-title-block-to-page-pattern.ts | 14 - .../pattern-assembler/index.tsx | 821 ------------------ .../pattern-assembler/keyframes.scss | 28 - .../navigator-title/index.tsx | 14 - .../pattern-assembler/notices/notices.scss | 11 - .../pattern-assembler/notices/notices.tsx | 89 -- .../pattern-assembler/pages/page-list.scss | 58 -- .../pattern-assembler/pages/page-list.tsx | 86 -- .../pages/page-preview-list.scss | 53 -- .../pages/page-preview-list.tsx | 106 --- .../pattern-assembler/pages/page-preview.scss | 137 --- .../pattern-assembler/pages/page-preview.tsx | 183 ---- .../pattern-assembler/panel.tsx | 21 - .../pattern-assembler/pattern-action-bar.scss | 91 -- .../pattern-assembler/pattern-action-bar.tsx | 125 --- .../pattern-assembler-container.tsx | 62 -- .../pattern-category-list.scss | 26 - .../pattern-category-list.stories.tsx | 137 --- .../pattern-category-list.tsx | 78 -- .../pattern-assembler/pattern-count/index.tsx | 15 - .../pattern-count/style.scss | 13 - .../pattern-large-preview.scss | 141 --- .../pattern-large-preview.tsx | 336 ------- .../pattern-assembler/pattern-list-panel.scss | 57 -- .../pattern-assembler/pattern-list-panel.tsx | 103 --- .../pattern-list-renderer.scss | 20 - .../pattern-list-renderer.tsx | 132 --- .../pattern-assembler/pattern-selector.tsx | 57 -- .../pattern-tooltip-dead-click.scss | 25 - .../pattern-tooltip-dead-click.tsx | 83 -- .../screen-color-palettes.tsx | 41 - .../screen-confirmation.scss | 35 - .../pattern-assembler/screen-confirmation.tsx | 106 --- .../screen-font-pairings.tsx | 39 - .../pattern-assembler/screen-main.tsx | 176 ---- .../pattern-assembler/screen-pages.tsx | 70 -- .../screen-pattern-list-panel.tsx | 89 -- .../pattern-assembler/screen-styles.tsx | 116 --- .../pattern-assembler/screen-upsell.scss | 74 -- .../pattern-assembler/screen-upsell.tsx | 108 --- .../pattern-assembler/style.scss | 263 ------ .../pattern-assembler/survey/index.tsx | 50 -- .../pattern-assembler/survey/survey.scss | 40 - .../pattern-assembler/types.ts | 50 -- .../pattern-assembler/utils.ts | 54 -- .../pattern-assembler/variables.scss | 2 - .../with-global-styles-provider.tsx | 41 - .../declarative-flow/internals/steps.tsx | 10 - .../declarative-flow/site-setup-flow.ts | 45 +- .../stepper/declarative-flow/update-design.ts | 34 +- .../with-theme-assembler-flow.ts | 96 +- .../components/category-gallery/client.tsx | 2 +- .../components/pattern-preview/index.tsx | 2 +- client/my-sites/patterns/constants.ts | 1 + .../patterns/lib/encode-pattern-id.ts | 4 + 82 files changed, 72 insertions(+), 5901 deletions(-) delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/index.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/style.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/constants.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/events.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/index.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-ai-assembler.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-assembler-patterns.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-categories-order.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-category-patterns-map.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-current-screen.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-custom-styles.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-global-styles-upgrade-props.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-initial-path.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-is-new-site.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-categories.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-count-map-by-category.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-pages.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-recipe.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-screen.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-sync-navigator-screen.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/index.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/inject-titles-to-page-list-block.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/prepend-title-block-to-page-pattern.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/keyframes.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/navigator-title/index.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/panel.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-assembler-container.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.stories.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/index.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/style.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-selector.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-color-palettes.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-font-pairings.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-main.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pages.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pattern-list-panel.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-styles.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/style.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/index.tsx delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/survey.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/types.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/utils.ts delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/variables.scss delete mode 100644 client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx create mode 100644 client/my-sites/patterns/lib/encode-pattern-id.ts diff --git a/client/assets/stylesheets/shared/functions/_z-index.scss b/client/assets/stylesheets/shared/functions/_z-index.scss index 615d92b0df41c..30d865d9775d7 100644 --- a/client/assets/stylesheets/shared/functions/_z-index.scss +++ b/client/assets/stylesheets/shared/functions/_z-index.scss @@ -111,7 +111,6 @@ $z-layers: ( ".billing-history-page .filter-popover-content": 23, ".reader-mobile-sidebar": 23, ".checkout-modal": 30, - ".pattern-assembler__preview-list--fullscreen-preview": 30, ".community-translator": 99, ".author-selector__popover.popover": 100, ".feature-example__gradient": 170, diff --git a/client/landing/stepper/declarative-flow/ai-assembler.ts b/client/landing/stepper/declarative-flow/ai-assembler.ts index b60c10faccc67..309e14b463551 100644 --- a/client/landing/stepper/declarative-flow/ai-assembler.ts +++ b/client/landing/stepper/declarative-flow/ai-assembler.ts @@ -225,10 +225,6 @@ const withAIAssemblerFlow: Flow = { return exitFlow( selectedSiteId, selectedSiteSlug ); } - case 'pattern-assembler': { - return navigate( 'processing' ); - } - case 'launchpad': { return navigate( 'processing' ); } @@ -273,19 +269,11 @@ const withAIAssemblerFlow: Flow = { case 'domain': { return navigate( 'launchpad' ); } - - case 'pattern-assembler': { - return navigate( 'site-prompt' ); - } } }; const goNext = () => { switch ( _currentStep ) { - case 'site-prompt': { - return navigate( 'pattern-assembler' ); - } - case 'launchpad': skipLaunchpad( { checklistSlug: AI_ASSEMBLER_FLOW, diff --git a/client/landing/stepper/declarative-flow/assembler-first-flow.ts b/client/landing/stepper/declarative-flow/assembler-first-flow.ts index b09bae2910bd0..849cdcd69cfad 100644 --- a/client/landing/stepper/declarative-flow/assembler-first-flow.ts +++ b/client/landing/stepper/declarative-flow/assembler-first-flow.ts @@ -167,10 +167,6 @@ const assemblerFirstFlow: Flow = { return; } - case 'pattern-assembler': { - return navigate( 'processing' ); - } - case 'launchpad': { return navigate( 'processing' ); } @@ -214,14 +210,6 @@ const assemblerFirstFlow: Flow = { case 'domains': { return navigate( 'launchpad' ); } - - case 'pattern-assembler': { - const params = new URLSearchParams( window.location.search ); - params.delete( 'siteSlug' ); - params.delete( 'siteId' ); - setSelectedSite( null ); - return navigate( `site-picker?${ params }` ); - } } }; diff --git a/client/landing/stepper/declarative-flow/import-flow.ts b/client/landing/stepper/declarative-flow/import-flow.ts index cc12d75b33ced..3937dd6086b44 100644 --- a/client/landing/stepper/declarative-flow/import-flow.ts +++ b/client/landing/stepper/declarative-flow/import-flow.ts @@ -1,4 +1,3 @@ -import { Design, isAssemblerDesign, isAssemblerSupported } from '@automattic/design-picker'; import { IMPORT_FOCUSED_FLOW } from '@automattic/onboarding'; import { useDispatch, useSelect } from '@wordpress/data'; import { useEffect } from 'react'; @@ -41,7 +40,6 @@ const importFlow: Flow = { STEPS.IMPORTER_SQUARESPACE, STEPS.IMPORTER_WORDPRESS, STEPS.DESIGN_SETUP, - STEPS.PATTERN_ASSEMBLER, STEPS.PROCESSING, STEPS.SITE_CREATION_STEP, STEPS.MIGRATION_HANDLER, @@ -80,10 +78,6 @@ const importFlow: Flow = { const fromParam = urlQueryParams.get( 'from' ); const { data: migrationStatus } = useSourceMigrationStatusQuery( fromParam ); const siteSlugParam = useSiteSlugParam(); - const selectedDesign = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), - [] - ); const isMigrateFromWp = useSelect( ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIsMigrateFromWp(), [] @@ -176,17 +170,9 @@ const importFlow: Flow = { } case 'designSetup': { - const { selectedDesign: _selectedDesign } = providedDependencies; - if ( isAssemblerDesign( _selectedDesign as Design ) && isAssemblerSupported() ) { - return navigate( 'pattern-assembler' ); - } - return navigate( 'processing' ); } - case 'pattern-assembler': - return navigate( 'processing' ); - case 'createSite': return navigate( 'processing' ); @@ -209,11 +195,6 @@ const importFlow: Flow = { return navigate( `import?siteSlug=${ providedDependencies?.siteSlug }` ); } - // End of Pattern Assembler flow - if ( isAssemblerDesign( selectedDesign ) ) { - return exitFlow( `/site-editor/${ siteSlugParam }` ); - } - return exitFlow( `/home/${ siteSlugParam }` ); } diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/index.tsx deleted file mode 100644 index 8bb5d9a5ce4b8..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/index.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { StepContainer, NextButton } from '@automattic/onboarding'; -import styled from '@emotion/styled'; -import { TextareaControl } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; -import { useI18n } from '@wordpress/react-i18n'; -import { FormEvent } from 'react'; -import FormattedHeader from 'calypso/components/formatted-header'; -import { LoadingEllipsis } from 'calypso/components/loading-ellipsis'; -import { ONBOARD_STORE } from 'calypso/landing/stepper/stores'; -import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; -import useAIAssembler from '../pattern-assembler/hooks/use-ai-assembler'; -import type { Step } from '../../types'; -import type { OnboardSelect } from '@automattic/data-stores'; - -import './style.scss'; - -const ActionSection = styled.div` - display: flex; - justify-content: space-between; - align-items: baseline; - flex-wrap: wrap; - margin-top: 40px; - - @media ( max-width: 320px ) { - align-items: center; - } -`; - -const StyledNextButton = styled( NextButton )` - @media ( max-width: 320px ) { - width: 100%; - margin-bottom: 20px; - } -`; - -const AISitePrompt: Step = function ( props ) { - const { goNext, goBack, submit } = props.navigation; // eslint-disable-line @typescript-eslint/no-unused-vars - - const { __ } = useI18n(); - const intent = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), - [] - ); - - const [ callAIAssembler, setPrompt, prompt, loading ] = useAIAssembler(); - - const onSubmit = async ( event: FormEvent ) => { - event.preventDefault(); - callAIAssembler() - ?.then( () => submit?.( { aiSitePrompt: prompt } ) ) - ?.catch( () => goNext?.() ); - }; - - function getContent() { - return ( - <> -
-
- setPrompt( value ) } - disabled={ loading } - /> - - - { loading && } - { ! loading && ( - - { __( 'Continue' ) } - - ) } - - -
- - ); - } - - return ( -
-
- - } - stepContent={ getContent() } - recordTracksEvent={ recordTracksEvent } - /> -
-
- ); -}; - -export default AISitePrompt; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/style.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/style.scss deleted file mode 100644 index 40d04a82fde64..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/ai-site-prompt/style.scss +++ /dev/null @@ -1,46 +0,0 @@ -@import "calypso/signup/style"; - -.site-prompt__instructions-container { - width: 60%; - .components-base-control { - margin-bottom: 24px; - } - - .components-base-control__field .components-input-control__label { - font-size: $editor-font-size; - margin-bottom: $grid-unit; - padding: 0; - } - - .components-base-control__field - .components-input-control__container - .components-select-control__input { - box-sizing: initial; - height: auto; - line-height: 20px; - min-height: auto; - padding: 12px 16px; - } - - .components-textarea-control__input { - width: 40em; - height: 15em; - } - - .site-prompt__components-group .components-checkbox-control:not(:last-child) { - margin-bottom: $grid-unit; - } -} - -.site-prompt__components-group-label { - box-sizing: border-box; - color: currentColor; - display: block; - max-width: 100%; - z-index: 1; - font-size: $editor-font-size; - margin-bottom: $grid-unit; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/design-choices/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/design-choices/index.tsx index 42191506d233d..e8c8efae2c0ff 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/design-choices/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/design-choices/index.tsx @@ -50,11 +50,8 @@ const DesignChoicesStep: Step = ( { navigation, flow, stepName } ) => { destination: kebabCase( destination ), } ); - if ( destination === 'pattern-assembler' || destination === 'launch-big-sky' ) { - setSelectedDesign( getAssemblerDesign() ); - } - if ( destination === 'launch-big-sky' ) { + setSelectedDesign( getAssemblerDesign() ); return; } diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/constants.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/constants.ts deleted file mode 100644 index 40673a914df92..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/constants.ts +++ /dev/null @@ -1,99 +0,0 @@ -export const getPatternSourceSiteID = () => '174455321'; // dotcompatterns - -export const PUBLIC_API_URL = 'https://public-api.wordpress.com'; -export const SITE_TAGLINE = 'Site Tagline'; - -export const NAVIGATOR_PATHS = { - MAIN: '/main', - MAIN_HEADER: '/main/header', - MAIN_FOOTER: '/main/footer', - MAIN_PATTERNS: '/main/:categorySlug', - STYLES: '/styles', - STYLES_COLORS: '/styles/colors', - STYLES_FONTS: '/styles/fonts', - ACTIVATION: '/activation', - CONFIRMATION: '/confirmation', - UPSELL: '/upsell', - PAGES: '/pages', -}; - -export const INITIAL_PATH = NAVIGATOR_PATHS.MAIN; - -export const INITIAL_SCREEN = 'main'; - -export const INITIAL_CATEGORY = 'intro'; - -/* Category list of the patterns fetched via PTK API from Dotcompatterns - * - * The categories that are commented are not fetched because they - * - are hidden intentionaly in the Assembler only - * - don't exist in Dotcompatterns source site - */ -export const PATTERN_CATEGORIES = [ - //'featured', // -- Not exists - 'intro', - 'about', - //'buttons', -- Not exist - //'banner', -- Not exist - //'query', -- Not exist - 'blog', - 'posts', // Reused as "Blog Posts" - //'call-to-action', -- Hidden - //'columns', -- Not exist - //'coming-soon', -- Hidden - 'contact', - 'footer', - 'forms', - 'gallery', - 'header', - //'link-in-bio', -- Hidden - //'media', -- Not exist - 'newsletter', - //'podcast', -- Hidden - 'portfolio', // For page patterns only in v1 - //'quotes', -- Not exist - 'services', - 'store', - //'team', -- Not exist - 'testimonials', // Reused as "Quotes" - //'text', -- Hidden -]; - -export const ORDERED_PATTERN_CATEGORIES = [ - 'intro', - 'about', - 'services', - 'store', - 'testimonials', - 'posts', - 'newsletter', - 'gallery', - 'contact', -]; - -export const INITIAL_PAGES = [ 'about' ]; - -export const PATTERN_PAGES_CATEGORIES = [ - 'about', - 'contact', - 'portfolio', // only in v1 - 'gallery', // only in v2 - 'posts', - 'services', - 'store', -]; - -export const ORDERED_PATTERN_PAGES_CATEGORIES = [ - 'about', - 'services', - 'portfolio', // only in v1 - 'gallery', // only in v2 - 'store', - 'posts', - 'contact', -]; - -// Pattern rendering -export const DEFAULT_VIEWPORT_HEIGHT = 500; -export const DEFAULT_VIEWPORT_WIDTH = 1200; -export const PLACEHOLDER_HEIGHT = 150; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/events.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/events.ts deleted file mode 100644 index 7b47932fa1023..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/events.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * See PekYwv-WG-p2 - */ -export const PATTERN_ASSEMBLER_EVENTS = { - /** - * Common for screens - */ - SCREEN_BACK_CLICK: 'calypso_signup_pattern_assembler_screen_back_click', - SCREEN_CONTINUE_CLICK: 'calypso_signup_pattern_assembler_screen_continue_click', - - /** - * Screen Main - */ - MAIN_ITEM_SELECT: 'calypso_signup_pattern_assembler_main_item_select', - BACK_CLICK: 'calypso_signup_pattern_assembler_back_click', - PAGE_FINAL_SELECT: 'calypso_signup_pattern_assembler_page_final_select', - PATTERN_FINAL_SELECT: 'calypso_signup_pattern_assembler_pattern_final_select', - CATEGORY_LIST_CATEGORY_CLICK: 'calypso_signup_pattern_assembler_category_click', - - /** - * Screen Styles - */ - SCREEN_COLORS_PREVIEW_CLICK: 'calypso_signup_pattern_assembler_screen_colors_preview_click', - SCREEN_FONTS_PREVIEW_CLICK: 'calypso_signup_pattern_assembler_screen_fonts_preview_click', - CONTINUE_TO_EDITOR_CLICK: 'calypso_signup_pattern_assembler_continue_click', - CONTINUE_MISCLICK: 'calypso_signup_pattern_assembler_continue_misclick', - - /** - * Screen Confirmation - */ - SCREEN_CONFIRMATION_CONFIRM_CLICK: - 'calypso_signup_pattern_assembler_screen_confirmation_confirm_click', - - /* - * Screen Upsell - */ - SCREEN_UPSELL_CHECKOUT_BUTTON_CLICK: - 'calypso_signup_pattern_assembler_screen_upsell_checkout_button_click', - SCREEN_UPSELL_UPGRADE_LATER_BUTTON_CLICK: - 'calypso_signup_pattern_assembler_screen_upsell_upgrade_later_button_click', - - /* - * Screen Pages - */ - SCREEN_PAGES_PAGE_ADD: 'calypso_signup_pattern_assembler_screen_pages_page_add', - SCREEN_PAGES_PAGE_REMOVE: 'calypso_signup_pattern_assembler_screen_pages_page_remove', - SCREEN_PAGES_PAGE_PREVIEW_CLICK: - 'calypso_signup_pattern_assembler_screen_pages_page_preview_click', - - /** - * Pattern Panels - */ - PATTERN_SELECT_CLICK: 'calypso_signup_pattern_assembler_pattern_select_click', - PATTERN_SHOW_MORE_CLICK: 'calypso_signup_pattern_assembler_pattern_show_more_click', - - /** - * Pattern Actions - */ - PATTERN_MOVEUP_CLICK: 'calypso_signup_pattern_assembler_pattern_moveup_click', - PATTERN_MOVEDOWN_CLICK: 'calypso_signup_pattern_assembler_pattern_movedown_click', - PATTERN_REPLACE_CLICK: 'calypso_signup_pattern_assembler_pattern_replace_click', - PATTERN_DELETE_CLICK: 'calypso_signup_pattern_assembler_pattern_delete_click', - PATTERN_SHUFFLE_CLICK: 'calypso_signup_pattern_assembler_pattern_shuffle_click', - - PREVIEW_DEVICE_CLICK: 'calypso_signup_pattern_assembler_preview_device_click', - - /** - * Large Preview - */ - LARGE_PREVIEW_ZOOM_OUT_SCALE_CHANGE: - 'calypso_signup_pattern_assembler_large_preview_zoom_out_scale_change', -} as const; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/index.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/index.ts deleted file mode 100644 index 4467fd04dcabd..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -export { default as useAssemblerPatterns } from './use-assembler-patterns'; -export { default as useCategoriesOrder } from './use-categories-order'; -export { default as useCategoryPatternsMap } from './use-category-patterns-map'; -export { default as useCurrentScreen } from './use-current-screen'; -export { default as useCustomStyles } from './use-custom-styles'; -export { default as useGlobalStylesUpgradeProps } from './use-global-styles-upgrade-props'; -export { default as useInitialPath } from './use-initial-path'; -export { default as usePatternCategories } from './use-pattern-categories'; -export { default as usePatternCountMapByCategory } from './use-pattern-count-map-by-category'; -export { default as usePatternPages } from './use-pattern-pages'; -export { default as useRecipe } from './use-recipe'; -export { default as useScreen } from './use-screen'; -export { default as useSyncNavigatorScreen } from './use-sync-navigator-screen'; -export { default as useIsNewSite } from './use-is-new-site'; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-ai-assembler.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-ai-assembler.ts deleted file mode 100644 index d00895dd00a6a..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-ai-assembler.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { isEnabled } from '@automattic/calypso-config'; -import { useState } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import wpcomRequest from 'wpcom-proxy-request'; - -// eslint-disable-next-line @typescript-eslint/ban-types -export default function useAIAssembler(): [ Function, Function, string, boolean ] { - const [ searchParams, setSearchParams ] = useSearchParams(); - const [ prompt, setPrompt ] = useState( searchParams.get( 'ai_description' ) || '' ); - const [ loading, setLoading ] = useState( false ); - - function callAIAssembler() { - setSearchParams( ( currentSearchParams: any ) => { - currentSearchParams.set( 'ai_description', prompt ); - return currentSearchParams; - } ); - setLoading( true ); - return wpcomRequest( { - path: '/pattern-assembler/ai/latest/generate', - method: 'POST', - apiNamespace: 'wpcom/v2', - body: { - description: prompt, - patterns_version: isEnabled( 'pattern-assembler/v2' ) ? '2' : '1', - }, - } ) - .catch( ( err ) => { - setLoading( false ); - console.log( 'Patterns AI error', err ); /* eslint-disable-line no-console */ - return Promise.reject( err ); - } ) - .then( ( response: any ) => { - setLoading( false ); - console.log( 'Patterns AI response', response ); /* eslint-disable-line no-console */ - // This actually passes the patterns to the pattern assembler. - setSearchParams( - ( currentSearchParams: any ) => { - currentSearchParams.set( 'header_pattern_id', response.header_pattern ); - currentSearchParams.set( 'footer_pattern_id', response.footer_pattern ); - currentSearchParams.set( 'pattern_ids', response.pages[ 0 ].patterns.join( ',' ) ); - // These 2 params were introduced in the V5 of the AI endpoint. - // TODO: Remove the checks once we settle on the endpoint. - if ( response?.site?.site_title ) { - currentSearchParams.set( 'site_title', response.site.site_title ); - } - if ( response?.site?.site_tagline ) { - currentSearchParams.set( 'site_tagline', response.site.site_tagline ); - } - - // In case we are sending the list of slugs to the assembler - const pageSlugs = response.pages.map( ( page: any ) => page?.slug ).filter( Boolean ); - if ( pageSlugs.length ) { - currentSearchParams.set( 'page_slugs', pageSlugs.join( ',' ) ); - } - - // In case we are sending the list of title / pattern pairs to the assembler - // This will also filter out the "home" since it has a different format. - const pageTitles = response.pages.filter( ( page: any ) => page?.title && page?.ID ); - if ( pageTitles.length ) { - currentSearchParams.set( 'custom_pages', JSON.stringify( pageTitles ) ); - } - - if ( response.style ) { - currentSearchParams.set( 'color_variation_title', response.style ); - } - - if ( response.font ) { - currentSearchParams.set( 'font_variation_title', response.font ); - } - - // So that we close the drawer with patterns when moving to the assembler: - currentSearchParams.set( 'screen', 'main' ); - currentSearchParams.delete( 'screen_parameter' ); - - return currentSearchParams; - }, - { replace: true } - ); - return Promise.resolve( response ); - } ); - } - return [ callAIAssembler, setPrompt, prompt, loading ]; -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-assembler-patterns.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-assembler-patterns.ts deleted file mode 100644 index bd8937b8cc6d5..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-assembler-patterns.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { isEnabled } from '@automattic/calypso-config'; -import { useQuery, UseQueryOptions } from '@tanstack/react-query'; -import wpcomRequest from 'wpcom-proxy-request'; -import { PATTERN_CATEGORIES, getPatternSourceSiteID } from '../constants'; -import type { Pattern } from '../types'; - -const useAssemblerPatterns = ( - lang?: string, - queryOptions: Omit< UseQueryOptions< any, unknown, Pattern[] >, 'queryKey' > = {} -): Pattern[] => { - const { data } = useQuery< any, unknown, Pattern[] >( { - queryKey: [ 'pattern-assembler', lang ], - queryFn: () => { - return wpcomRequest( { - path: `/ptk/patterns/${ lang }`, - method: 'GET', - apiVersion: '1.1', - query: new URLSearchParams( - isEnabled( 'pattern-assembler/v2' ) - ? { - site: getPatternSourceSiteID(), - post_type: 'wp_block', - } - : { - tags: - // Pages are fetched with assembler_priority. - // There are more pages tagged with assembler_page that still aren't offered in Assembler. - 'assembler,assembler_priority', - categories: PATTERN_CATEGORIES.join( ',' ), - post_type: 'post', - } - ).toString(), - } ); - }, - ...queryOptions, - staleTime: Infinity, - enabled: !! lang, - meta: { - persist: false, - ...queryOptions.meta, - }, - } ); - - return data ?? []; -}; - -export default useAssemblerPatterns; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-categories-order.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-categories-order.ts deleted file mode 100644 index ca687714f4c38..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-categories-order.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useMemo } from 'react'; -import type { Category } from '../types'; - -const useCategoriesOrder = ( categories: Category[], orderList: string[] ) => { - return useMemo( - () => - categories.sort( ( { name: aName }, { name: bName } ) => { - if ( aName && bName ) { - // Sort categories according to the orderList. - let aIndex = orderList.indexOf( aName ); - let bIndex = orderList.indexOf( bName ); - // All other categories should come after that. - if ( aIndex < 0 ) { - aIndex = orderList.length; - } - if ( bIndex < 0 ) { - bIndex = orderList.length; - } - return aIndex - bIndex; - } - return 0; - } ), - [ categories, orderList ] - ); -}; - -export default useCategoriesOrder; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-category-patterns-map.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-category-patterns-map.ts deleted file mode 100644 index f411f681d71f6..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-category-patterns-map.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { useMemo } from 'react'; -import { PATTERN_CATEGORIES, PATTERN_PAGES_CATEGORIES } from '../constants'; -import { isPriorityPattern, isPagePattern } from '../utils'; -import type { Pattern } from '../types'; - -type CategoryPatternsMap = Record< string, Pattern[] >; - -const createCategoryPatternsMap = ( initialCategories: string[] = [] ): CategoryPatternsMap => - initialCategories.reduce( - ( acc, cur ) => ( { - ...acc, - [ cur ]: [], - } ), - {} - ); - -const useCategoryPatternsMap = ( patterns: Pattern[] ) => { - return useMemo( () => { - const allCategoryPatternsMap = createCategoryPatternsMap(); - const layoutCategoryPatternsMap = createCategoryPatternsMap( PATTERN_CATEGORIES ); - const pageCategoryPatternsMap = createCategoryPatternsMap( PATTERN_PAGES_CATEGORIES ); - const insert = ( - categoryPatternsMap: CategoryPatternsMap, - category: string, - pattern: Pattern - ) => { - if ( ! categoryPatternsMap[ category ] ) { - categoryPatternsMap[ category ] = []; - } - - if ( isPriorityPattern( pattern ) ) { - categoryPatternsMap[ category ].unshift( pattern ); - } else { - categoryPatternsMap[ category ].push( pattern ); - } - }; - - [ ...patterns ].reverse().forEach( ( pattern ) => { - Object.keys( pattern.categories ).forEach( ( category ) => { - const isPage = isPagePattern( pattern ); - - insert( allCategoryPatternsMap, category, pattern ); - // @TODO: For the future feature to shuffle pages will have to remove isPriorityPattern( pattern ) from this condition. - // It's only being used here just to help testing priority pages as the rest are excluded. - if ( - isPage && - pageCategoryPatternsMap.hasOwnProperty( category ) && - isPriorityPattern( pattern ) - ) { - insert( pageCategoryPatternsMap, category, pattern ); - } - - if ( ! isPage && layoutCategoryPatternsMap.hasOwnProperty( category ) ) { - insert( layoutCategoryPatternsMap, category, pattern ); - } - } ); - } ); - - return { - allCategoryPatternsMap, - layoutCategoryPatternsMap, - pageCategoryPatternsMap, - }; - }, [ patterns ] ); -}; - -export default useCategoryPatternsMap; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-current-screen.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-current-screen.tsx deleted file mode 100644 index ec30e2bef9901..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-current-screen.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useSearchParams } from 'react-router-dom'; -import { INITIAL_SCREEN } from '../constants'; -import useScreen, { UseScreenOptions } from './use-screen'; -import type { ScreenName } from '../types'; - -const useCurrentScreen = ( options: UseScreenOptions ) => { - const [ searchParams ] = useSearchParams(); - const currentScreenName = ( searchParams.get( 'screen' ) ?? INITIAL_SCREEN ) as ScreenName; - const currentScreen = useScreen( currentScreenName, options ); - - return currentScreen; -}; - -export default useCurrentScreen; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-custom-styles.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-custom-styles.tsx deleted file mode 100644 index 6f4d7f722fdf5..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-custom-styles.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useSiteGlobalStylesStatus } from 'calypso/state/sites/hooks/use-site-global-styles-status'; - -interface Props { - siteID?: number | string; - hasColor: boolean; - hasFont: boolean; -} - -const useCustomStyles = ( { siteID = 0, hasColor, hasFont }: Props ) => { - const { shouldLimitGlobalStyles } = useSiteGlobalStylesStatus( siteID ); - const numOfSelectedGlobalStyles = [ hasColor, hasFont ].filter( Boolean ).length; - - return { - shouldUnlockGlobalStyles: numOfSelectedGlobalStyles > 0 && shouldLimitGlobalStyles, - numOfSelectedGlobalStyles, - }; -}; - -export default useCustomStyles; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-global-styles-upgrade-props.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-global-styles-upgrade-props.tsx deleted file mode 100644 index 6d531f541b31d..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-global-styles-upgrade-props.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { urlToSlug } from 'calypso/lib/url'; -import { useSite } from '../../../../../hooks/use-site'; -import { useSiteSlugParam } from '../../../../../hooks/use-site-slug-param'; -import { goToCheckout } from '../../../../../utils/checkout'; -import { PATTERN_ASSEMBLER_EVENTS } from '../events'; -import type { ScreenName } from '../types'; - -interface Props { - flowName: string; - stepName: string; - nextScreenName: ScreenName; - onUpgradeLater?: () => void; - recordTracksEvent: ( eventName: string, eventProps?: { [ key: string ]: unknown } ) => void; -} - -const useGlobalStylesUpgradeProps = ( { - flowName, - stepName, - nextScreenName, - onUpgradeLater, - recordTracksEvent, -}: Props ) => { - const site = useSite(); - const siteSlug = useSiteSlugParam(); - const siteUrl = siteSlug || urlToSlug( site?.URL || '' ) || ''; - - const handleCheckout = () => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_UPSELL_CHECKOUT_BUTTON_CLICK ); - - // When the user is done with checkout, send them back to the next screen - const searchParams = new URLSearchParams( window.location.search ); - searchParams.set( 'screen', nextScreenName ); - const redirectUrl = `${ window.location.pathname }?${ searchParams }`; - - goToCheckout( { - flowName, - stepName, - siteSlug: siteUrl, - destination: redirectUrl, - plan: 'premium', - } ); - }; - - const handleTryStyle = () => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_UPSELL_UPGRADE_LATER_BUTTON_CLICK ); - onUpgradeLater?.(); - }; - - return { - onCheckout: handleCheckout, - onTryStyle: handleTryStyle, - }; -}; - -export default useGlobalStylesUpgradeProps; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-initial-path.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-initial-path.ts deleted file mode 100644 index 671232f083b6c..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-initial-path.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useMemo } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import { INITIAL_PATH } from '../constants'; - -const useInitialPath = () => { - const [ searchParams ] = useSearchParams(); - - return useMemo( () => { - const screen = searchParams.get( 'screen' ); - const screenParameter = searchParams.get( 'screen_parameter' ); - if ( ! screen ) { - return INITIAL_PATH; - } - - return [ screen, screenParameter ] - .filter( Boolean ) - .map( ( path ) => `/${ path }` ) - .join( '' ); - }, [] ); -}; - -export default useInitialPath; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-is-new-site.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-is-new-site.ts deleted file mode 100644 index 00fa96769de92..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-is-new-site.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { isSiteSetupFlow, isFreeFlow } from '@automattic/onboarding'; -import { useQuery } from '../../../../../hooks/use-query'; - -const useIsNewSite = ( flow: string ) => { - // New sites are created from: - // - 'free' flow - // - 'site-setup' flow - // - 'with-theme-assembler' from LoTS, which has isNewSite: true - return !! useQuery().get( 'isNewSite' ) || isFreeFlow( flow ) || isSiteSetupFlow( flow ); -}; - -export default useIsNewSite; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-categories.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-categories.ts deleted file mode 100644 index 8039051f28f5b..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-categories.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query'; -import wpcom from 'calypso/lib/wp'; -import type { Category } from '../types'; - -const usePatternCategories = ( - siteId: undefined | number = 0, - queryOptions: Omit< UseQueryOptions< any, unknown, Category[] >, 'queryKey' > = {} -): Category[] => { - const { data } = useQuery< any, unknown, Category[] >( { - queryKey: [ siteId, 'block-patterns', 'categories' ], - queryFn: () => { - return wpcom.req.get( { - path: `/sites/${ encodeURIComponent( siteId ) }/block-patterns/categories`, - apiNamespace: 'wp/v2', - } ); - }, - ...queryOptions, - staleTime: Infinity, - enabled: !! siteId, - meta: { - persist: false, - ...queryOptions.meta, - }, - } ); - return data ?? []; -}; - -export default usePatternCategories; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-count-map-by-category.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-count-map-by-category.ts deleted file mode 100644 index a9dc5a3057b2b..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-count-map-by-category.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useMemo } from 'react'; -import type { Pattern } from '../types'; - -const usePatternCountMapByCategory = ( patterns: Pattern[] ) => { - return useMemo( - () => - patterns.reduce( ( acc: Record< string, number >, pattern ) => { - const categoryName = pattern.category?.name; - if ( ! categoryName ) { - return acc; - } - - return { - ...acc, - [ categoryName ]: ( acc[ categoryName ] || 0 ) + 1, - }; - }, {} ), - [ patterns ] - ); -}; - -export default usePatternCountMapByCategory; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-pages.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-pages.ts deleted file mode 100644 index 9f99b28c24ae2..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-pattern-pages.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { useSearchParams } from 'react-router-dom'; -import { INITIAL_PAGES, ORDERED_PATTERN_PAGES_CATEGORIES } from '../constants'; -import { useCategoriesOrder } from '../hooks'; -import { getPagePatternTitle, isPriorityPattern } from '../utils'; -import type { Pattern, Category, CustomPageTitle } from '../types'; - -const usePatternPages = ( - pageCategoryPatternsMap: Record< string, Pattern[] >, - categories: Category[], - assemblerPatterns: Pattern[] -): { - pages: Pattern[]; - pageSlugs: string[]; - setPageSlugs: ( slugs: string[] ) => void; - pagesToShow: any[]; -} => { - const [ searchParams, setSearchParams ] = useSearchParams(); - let pageCategoriesInOrder; - let pageSlugs: string[] = []; - let pages: Pattern[] = []; - let pagesToShow: any[] = []; - let mockedPages: CustomPageTitle[] = []; - const page_slugs = searchParams.get( 'page_slugs' ); - const custom_pages = searchParams.get( 'custom_pages' ); - - if ( page_slugs !== null ) { - pageSlugs = page_slugs.split( ',' ).filter( Boolean ); - } - - // eslint-disable-next-line prefer-const - pageCategoriesInOrder = useCategoriesOrder( categories, ORDERED_PATTERN_PAGES_CATEGORIES ); - - if ( custom_pages !== null ) { - try { - mockedPages = JSON.parse( custom_pages ); - } catch ( e ) {} - } - - // Pairs of page title and pattern id can be passed in the URL from AI flow. - if ( mockedPages.length > 0 ) { - mockedPages.forEach( ( { ID, title, selected }: CustomPageTitle ) => { - const patterns = assemblerPatterns.filter( ( pattern: Pattern ) => pattern.ID === ID ); - if ( patterns.length === 0 ) { - return; - } - const pattern = patterns[ 0 ]; - pattern.title = title; - - if ( selected ) { - pageSlugs.push( pattern?.name || '' ); - pages.push( pattern ); - } - pagesToShow.push( { - name: pattern?.name || '', - title: title, - isSelected: !! selected, - } ); - } ); - - const setPageSlugs = ( slugs: string[] ) => { - setSearchParams( - ( currentSearchParams ) => { - const newMockedPages = mockedPages.map( ( page: CustomPageTitle ) => { - const patterns = assemblerPatterns.filter( - ( pattern: Pattern ) => pattern.ID === page.ID - ); - page.selected = slugs.includes( patterns[ 0 ].name ); - return page; - } ); - currentSearchParams.set( 'custom_pages', JSON.stringify( newMockedPages ) ); - - return currentSearchParams; - }, - { replace: true } - ); - }; - - return { pages, pageSlugs, setPageSlugs, pagesToShow }; - } - - if ( page_slugs === null ) { - pageSlugs = INITIAL_PAGES; - } - - const getFeaturedPageOrFirstInCategory = ( name: string ) => - pageCategoryPatternsMap[ name ]?.find( isPriorityPattern ) || - pageCategoryPatternsMap[ name ]?.[ 0 ]; - - pages = pageSlugs - .map( ( name ) => { - const page = getFeaturedPageOrFirstInCategory( name ); - if ( page ) { - return { - ...page, - title: getPagePatternTitle( page ), - }; - } - } ) - .filter( Boolean ) as Pattern[]; - - pagesToShow = pageCategoriesInOrder - .map( ( category: Category ) => { - const { name = '' } = category; - const page = getFeaturedPageOrFirstInCategory( name ); - if ( page ) { - return { - name, - title: getPagePatternTitle( page ), - isSelected: pageSlugs.includes( name ), - }; - } - } ) - .filter( Boolean ); - - const setPageSlugs = ( slugs: string[] ) => { - setSearchParams( - ( currentSearchParams ) => { - if ( slugs.length === 0 ) { - currentSearchParams.set( 'page_slugs', '' ); - } else { - currentSearchParams.set( 'page_slugs', slugs.join( ',' ) ); - } - - return currentSearchParams; - }, - { replace: true } - ); - }; - - return { pages, pageSlugs, setPageSlugs, pagesToShow }; -}; - -export default usePatternPages; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-recipe.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-recipe.ts deleted file mode 100644 index bbebcb81a7bb5..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-recipe.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { useColorPaletteVariations, useFontPairingVariations } from '@automattic/global-styles'; -import { keyBy } from '@automattic/js-utils'; -import { useSelect } from '@wordpress/data'; -import { useState, useEffect, useMemo, useRef } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import { ONBOARD_STORE } from '../../../../../stores'; -import { PATTERN_CATEGORIES } from '../constants'; -import { decodePatternId } from '../utils'; -import type { Pattern, Category } from '../types'; -import type { OnboardSelect } from '@automattic/data-stores'; -import type { GlobalStylesObject } from '@automattic/global-styles'; - -const useRecipe = ( siteId = 0, patterns: Pattern[], categories: Category[] ) => { - const [ searchParams, setSearchParams ] = useSearchParams(); - - const header_pattern_id = searchParams.get( 'header_pattern_id' ); - const footer_pattern_id = searchParams.get( 'footer_pattern_id' ); - - const section_pattern_ids = ( searchParams.get( 'pattern_ids' ) || '' ) - .split( ',' ) - .filter( Boolean ); - - const color_variation_title = searchParams.get( 'color_variation_title' ); - const font_variation_title = searchParams.get( 'font_variation_title' ); - - // Initialize the mappings once, when the patterns and categories are finally loaded - const patternsById = useMemo( () => keyBy( patterns, 'ID' ), [ patterns.length ] ); // eslint-disable-line react-hooks/exhaustive-deps - const categoriesByName = useMemo( () => keyBy( categories, 'name' ), [ categories.length ] ); // eslint-disable-line react-hooks/exhaustive-deps - - const header = header_pattern_id ? patternsById[ decodePatternId( header_pattern_id ) ] : null; - const footer = footer_pattern_id ? patternsById[ decodePatternId( footer_pattern_id ) ] : null; - - /* Adds a unique "key" prop to each section pattern, - so that when the patterns are rendered in a list, - they are not re-rendered unnecessarily when the list - is manipulated (some elements get appended / removed). - */ - const [ keyedSections, setKeyedSections ] = useState< Pattern[] >( [] ); - - /* To sync the keyed sections with the search params, - we first initialize the sections from the search params. - */ - const initialSections = useMemo( - () => { - const categoriesSet = new Set( PATTERN_CATEGORIES ); - return section_pattern_ids - .map( ( patternId ) => patternsById[ decodePatternId( patternId ) ] ) - .filter( Boolean ) - .map( ( pattern: Pattern ) => { - const availableCategory = Object.keys( pattern.categories ).find( ( category ) => - categoriesSet.has( category ) - ); - const category = availableCategory ? categoriesByName[ availableCategory ] : undefined; - return { - ...pattern, - category, - }; - } ); - }, - /* We are ignoring the changes from the search params (section_pattern_ids), - since after this point, the changes will be handled by setSections(). - */ - [ patternsById, categoriesByName, PATTERN_CATEGORIES ] // eslint-disable-line react-hooks/exhaustive-deps - ); - - const uniqueSectionPatternKeyRef = useRef( 0 ); - const generateSectionPatternKey = ( pattern: Pattern ) => { - uniqueSectionPatternKeyRef.current++; - return `${ uniqueSectionPatternKeyRef.current }-${ pattern.ID }`; - }; - - /* Generates the keys to the initial sections and set them as the initial value of keyedSections. - After this point, the changes will be handled by setSections(). - */ - useEffect( () => { - const initialKeyedSections = initialSections.map( ( pattern ) => ( { - ...pattern, - key: generateSectionPatternKey( pattern ), - } ) ); - - setKeyedSections( initialKeyedSections ); - }, [ initialSections ] ); - - const selectedDesign = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), - [] - ); - const { stylesheet = '' } = selectedDesign?.recipe || {}; - - const colorVariations = useColorPaletteVariations( siteId, stylesheet, { - enabled: !! color_variation_title, - } ); - - const fontVariations = useFontPairingVariations( siteId, stylesheet, { - enabled: !! font_variation_title, - } ); - - const colorVariation = - ( colorVariations || [] ).find( ( { title } ) => title === color_variation_title ) || null; - - const fontVariation = - ( fontVariations || [] ).find( ( { title } ) => title === font_variation_title ) || null; - - const setHeader = ( pattern: Pattern | null ) => { - setSearchParams( - ( currentSearchParams ) => { - if ( pattern === null ) { - currentSearchParams.delete( 'header_pattern_id' ); - } else { - currentSearchParams.set( 'header_pattern_id', '' + pattern.ID ); - } - return currentSearchParams; - }, - { replace: true } - ); - }; - - const setFooter = ( pattern: Pattern | null ) => { - setSearchParams( - ( currentSearchParams ) => { - if ( pattern === null ) { - currentSearchParams.delete( 'footer_pattern_id' ); - } else { - currentSearchParams.set( 'footer_pattern_id', '' + pattern.ID ); - } - return currentSearchParams; - }, - { replace: true } - ); - }; - - const setSections = ( patterns: Pattern[] ) => { - setSearchParams( - ( currentSearchParams ) => { - if ( patterns.length === 0 ) { - currentSearchParams.delete( 'pattern_ids' ); - } else { - currentSearchParams.set( 'pattern_ids', patterns.map( ( p ) => p.ID ).join( ',' ) ); - } - return currentSearchParams; - }, - { replace: true } - ); - - setKeyedSections( - patterns.map( ( pattern ) => - pattern.key - ? pattern - : { - ...pattern, - key: generateSectionPatternKey( pattern ), - } - ) - ); - }; - - const setColorVariation = ( variation: GlobalStylesObject | null ) => { - setSearchParams( - ( currentSearchParams ) => { - if ( variation?.title ) { - currentSearchParams.set( 'color_variation_title', variation?.title ); - } else { - currentSearchParams.delete( 'color_variation_title' ); - } - return currentSearchParams; - }, - { replace: true } - ); - }; - - const setFontVariation = ( variation: GlobalStylesObject | null ) => { - setSearchParams( - ( currentSearchParams ) => { - if ( variation?.title ) { - currentSearchParams.set( 'font_variation_title', variation?.title ); - } else { - currentSearchParams.delete( 'font_variation_title' ); - } - return currentSearchParams; - }, - { replace: true } - ); - }; - - const resetRecipe = () => { - setHeader( null ); - setSections( [] ); - setFooter( null ); - setColorVariation( null ); - setFontVariation( null ); - }; - - return { - header, - footer, - sections: keyedSections, - colorVariation, - fontVariation, - setHeader, - setFooter, - setSections, - setColorVariation, - setFontVariation, - resetRecipe, - }; -}; - -export default useRecipe; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-screen.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-screen.tsx deleted file mode 100644 index 7aa932450887f..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-screen.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { PLAN_PREMIUM } from '@automattic/calypso-products'; -import { Plans } from '@automattic/data-stores'; -import { useHasEnTranslation } from '@automattic/i18n-utils'; -import { useTranslate, TranslateResult } from 'i18n-calypso'; -import { NAVIGATOR_PATHS } from '../constants'; -import type { ScreenName } from '../types'; - -export type UseScreenOptions = { - shouldUnlockGlobalStyles?: boolean; -}; - -export type Screen = { - name: string; - title: string; - description?: TranslateResult; - continueLabel: string; - /** The label for going back from the next screen */ - backLabel?: string; - initialPath: string; - previousScreen?: Screen | null; - nextScreen?: Screen | null; -}; - -const useScreen = ( screenName: ScreenName, options: UseScreenOptions = {} ): Screen => { - const translate = useTranslate(); - const hasEnTranslation = useHasEnTranslation(); - const plans = Plans.usePlans( { coupon: undefined } ); - const screens: Record< ScreenName, Screen > = { - main: { - name: 'main', - title: hasEnTranslation( 'Select patterns' ) - ? translate( 'Select patterns' ) - : translate( 'Select your patterns' ), - description: translate( 'Create your homepage from our library of patterns.' ) - ? translate( 'Create your homepage from our library of patterns.' ) - : translate( - 'Create your homepage by first adding patterns and then choosing a color palette and font style.' - ), - continueLabel: hasEnTranslation( 'Select styles' ) - ? translate( 'Select styles' ) - : translate( 'Pick your styles' ), - backLabel: hasEnTranslation( 'patterns' ) ? translate( 'patterns' ) : undefined, - initialPath: NAVIGATOR_PATHS.MAIN_HEADER, - }, - styles: { - name: 'styles', - title: hasEnTranslation( 'Select styles' ) - ? translate( 'Select styles' ) - : translate( 'Pick your styles' ), - description: hasEnTranslation( - 'Add style to your page with our expertly curated color palettes and font pairings.' - ) - ? translate( - 'Add style to your page with our expertly curated color palettes and font pairings.' - ) - : translate( - 'Create your homepage by first adding patterns and then choosing a color palette and font style.' - ), - continueLabel: translate( 'Select pages' ), - backLabel: hasEnTranslation( 'styles' ) ? translate( 'styles' ) : undefined, - initialPath: NAVIGATOR_PATHS.STYLES_COLORS, - }, - pages: { - name: 'pages', - title: translate( 'Add more pages' ), - description: translate( - "We've pre-selected common pages for your site. You can add more pages or unselect the current ones.{{br/}}{{br/}}Page content can be edited later, in the Site Editor.", - { - components: { - br:
, - }, - } - ), - continueLabel: translate( 'Save and continue' ), - backLabel: translate( 'pages' ), - initialPath: NAVIGATOR_PATHS.PAGES, - }, - upsell: { - name: 'upsell', - title: translate( 'Premium styles' ), - description: translate( - "You've chosen premium styles which are exclusive to the %(premiumPlanName)s plan or higher.", - { args: { premiumPlanName: plans?.data?.[ PLAN_PREMIUM ]?.productNameShort || '' } } - ), - continueLabel: translate( 'Continue' ), - backLabel: hasEnTranslation( 'premium styles' ) ? translate( 'premium styles' ) : undefined, - initialPath: NAVIGATOR_PATHS.UPSELL, - }, - confirmation: { - name: 'confirmation', - title: translate( 'Great job!' ), - continueLabel: translate( 'Start adding content' ), - initialPath: NAVIGATOR_PATHS.CONFIRMATION, - }, - }; - - const previousScreens = { - main: null, - styles: screens.main, - pages: screens.styles, - upsell: screens.pages, - confirmation: options.shouldUnlockGlobalStyles ? screens.upsell : screens.pages, - }; - - const nextScreens = { - main: screens.styles, - styles: screens.pages, - pages: options.shouldUnlockGlobalStyles ? screens.upsell : screens.confirmation, - upsell: screens.confirmation, - confirmation: null, - }; - - return { - ...screens[ screenName ], - previousScreen: previousScreens[ screenName ], - nextScreen: nextScreens[ screenName ], - }; -}; - -export default useScreen; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-sync-navigator-screen.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-sync-navigator-screen.ts deleted file mode 100644 index 4db235931540c..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/hooks/use-sync-navigator-screen.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { useNavigatorListener } from '@automattic/onboarding'; -import { useCallback } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import { INITIAL_SCREEN } from '../constants'; - -const useSyncNavigatorScreen = () => { - const [ , setSearchParams ] = useSearchParams(); - const handleNavigatorPathChange = useCallback( - ( path = '' ) => { - setSearchParams( - ( currentSearchParams ) => { - const [ screen, screenParameter ] = path.split( '/' ).slice( 1 ); - currentSearchParams.set( 'screen', screen ?? INITIAL_SCREEN ); - if ( screenParameter ) { - currentSearchParams.set( 'screen_parameter', screenParameter ); - } else { - currentSearchParams.delete( 'screen_parameter' ); - } - return currentSearchParams; - }, - { replace: true } - ); - }, - [ setSearchParams ] - ); - - useNavigatorListener( handleNavigatorPathChange ); -}; - -export default useSyncNavigatorScreen; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/index.tsx deleted file mode 100644 index 212cb8a91d59c..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export { default as injectTitlesToPageListBlock } from './inject-titles-to-page-list-block'; -export { default as prependTitleBlockToPagePattern } from './prepend-title-block-to-page-pattern'; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/inject-titles-to-page-list-block.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/inject-titles-to-page-list-block.ts deleted file mode 100644 index 29fbcb9cb4dae..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/inject-titles-to-page-list-block.ts +++ /dev/null @@ -1,26 +0,0 @@ -export default function injectTitlesToPageListBlock( - patternHtml: string, - pageTitles: string[], - { replaceCurrentPages }: { replaceCurrentPages: boolean } -) { - return patternHtml.replace( - /(? - `; - } - ); -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/prepend-title-block-to-page-pattern.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/prepend-title-block-to-page-pattern.ts deleted file mode 100644 index ba13be82dcd77..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/html-transformers/prepend-title-block-to-page-pattern.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default function prependTitleBlockToPagePattern( patternHtml: string, pageTitle: string ) { - // A copy of the title block in Creatio 2's page.html. - const titleBlock = ` -
-

- ${ pageTitle } -

-
- `; - return titleBlock + patternHtml; -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx deleted file mode 100644 index b14289e8869f9..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx +++ /dev/null @@ -1,821 +0,0 @@ -import { getThemeIdFromStylesheet } from '@automattic/data-stores'; -import { - useSyncGlobalStylesUserConfig, - getVariationTitle, - getVariationType, -} from '@automattic/global-styles'; -import { useLocale } from '@automattic/i18n-utils'; -import { - AI_ASSEMBLER_FLOW, - StepContainer, - isSiteAssemblerFlow, - isWithThemeAssemblerFlow, - NavigatorScreen, -} from '@automattic/onboarding'; -import { - Button, - __experimentalNavigatorProvider as NavigatorProvider, - __experimentalUseNavigator as useNavigator, -} from '@wordpress/components'; -import { compose } from '@wordpress/compose'; -import { useDispatch, useSelect } from '@wordpress/data'; -import { Icon, rotateLeft } from '@wordpress/icons'; -import { useTranslate } from 'i18n-calypso'; -import { useState, useRef, useMemo } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import QueryActiveTheme from 'calypso/components/data/query-active-theme'; -import { createRecordTracksEvent } from 'calypso/lib/analytics/tracks'; -import { useDispatch as useReduxDispatch } from 'calypso/state'; -import { activateOrInstallThenActivate } from 'calypso/state/themes/actions'; -import { useSite } from '../../../../hooks/use-site'; -import { useSiteIdParam } from '../../../../hooks/use-site-id-param'; -import { useSiteSlugParam } from '../../../../hooks/use-site-slug-param'; -import { SITE_STORE, ONBOARD_STORE } from '../../../../stores'; -import { recordSelectedDesign, getAssemblerSource } from '../../analytics/record-design'; -import { SITE_TAGLINE, NAVIGATOR_PATHS, INITIAL_SCREEN } from './constants'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import { - useAssemblerPatterns, - useCategoryPatternsMap, - useCurrentScreen, - useCustomStyles, - useGlobalStylesUpgradeProps, - useInitialPath, - useIsNewSite, - usePatternCategories, - usePatternPages, - useRecipe, - useSyncNavigatorScreen, -} from './hooks'; -import useAIAssembler from './hooks/use-ai-assembler'; -import withNotices, { NoticesProps } from './notices/notices'; -import PagePreviewList from './pages/page-preview-list'; -import PatternAssemblerContainer from './pattern-assembler-container'; -import PatternLargePreview from './pattern-large-preview'; -import ScreenColorPalettes from './screen-color-palettes'; -import ScreenConfirmation from './screen-confirmation'; -import ScreenFontPairings from './screen-font-pairings'; -import ScreenMain from './screen-main'; -import ScreenPages from './screen-pages'; -import ScreenPatternListPanel from './screen-pattern-list-panel'; -import ScreenStyles from './screen-styles'; -import ScreenUpsell from './screen-upsell'; -import { encodePatternId, getShuffledPattern, injectCategoryToPattern } from './utils'; -import withGlobalStylesProvider from './with-global-styles-provider'; -import type { Pattern, PatternType } from './types'; -import type { StepProps } from '../../types'; -import type { OnboardSelect } from '@automattic/data-stores'; -import type { DesignRecipe, Design } from '@automattic/design-picker/src/types'; -import type { GlobalStylesObject } from '@automattic/global-styles'; -import type { FC } from 'react'; -import type { AnyAction } from 'redux'; -import type { ThunkAction } from 'redux-thunk'; -import './style.scss'; - -const PatternAssembler = ( props: StepProps & NoticesProps ) => { - const { navigation, flow, stepName, noticeOperations, noticeUI } = props; - - const translate = useTranslate(); - const navigator = useNavigator(); - const [ sectionPosition, setSectionPosition ] = useState< number | null >( null ); - const wrapperRef = useRef< HTMLDivElement | null >( null ); - const [ activePosition, setActivePosition ] = useState( -1 ); - const [ surveyDismissed, setSurveyDismissed ] = useState( false ); - const { goBack, goNext, submit } = navigation; - const { assembleSite, saveSiteSettings } = useDispatch( SITE_STORE ); - const reduxDispatch = useReduxDispatch(); - const { setPendingAction } = useDispatch( ONBOARD_STORE ); - const selectedDesign = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), - [] - ); - const intent = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), - [] - ); - const site = useSite(); - const siteSlug = useSiteSlugParam(); - const siteId = useSiteIdParam(); - const siteSlugOrId = siteSlug ? siteSlug : siteId; - const locale = useLocale(); - const isNewSite = useIsNewSite( flow ); - const [ searchParams ] = useSearchParams(); - const [ callAIAssembler, , aiAssemblerPrompt, aiAssemblerLoading ] = useAIAssembler(); - - // The categories api triggers the ETK plugin before the PTK api request - const categories = usePatternCategories( site?.ID ); - - // Fetching curated patterns and categories from PTK api - const assemblerPatterns = useAssemblerPatterns( locale ); - - const { allCategoryPatternsMap, layoutCategoryPatternsMap, pageCategoryPatternsMap } = - useCategoryPatternsMap( assemblerPatterns ); - - const { - header, - footer, - sections, - colorVariation, - fontVariation, - setHeader, - setFooter, - setSections, - setColorVariation, - setFontVariation, - resetRecipe, - } = useRecipe( site?.ID, assemblerPatterns, categories ); - - const { shouldUnlockGlobalStyles, numOfSelectedGlobalStyles } = useCustomStyles( { - siteID: site?.ID, - hasColor: !! colorVariation, - hasFont: !! fontVariation, - } ); - - const { pages, pageSlugs, setPageSlugs, pagesToShow } = usePatternPages( - pageCategoryPatternsMap, - categories, - assemblerPatterns - ); - - const currentScreen = useCurrentScreen( { shouldUnlockGlobalStyles } ); - - const stylesheet = selectedDesign?.recipe?.stylesheet || ''; - - const recordTracksEvent = useMemo( - () => - createRecordTracksEvent( { - flow, - step: stepName, - intent, - stylesheet, - color_variation_title: getVariationTitle( colorVariation ), - color_variation_type: getVariationType( colorVariation ), - font_variation_title: getVariationTitle( fontVariation ), - font_variation_type: getVariationType( fontVariation ), - assembler_source: getAssemblerSource( selectedDesign ), - has_global_styles_selected: numOfSelectedGlobalStyles > 0, - } ), - [ - flow, - stepName, - intent, - stylesheet, - colorVariation, - fontVariation, - numOfSelectedGlobalStyles, - pages, - ] - ); - - const selectedVariations = useMemo( - () => [ colorVariation, fontVariation ].filter( Boolean ) as GlobalStylesObject[], - [ colorVariation, fontVariation ] - ); - - const syncedGlobalStylesUserConfig = useSyncGlobalStylesUserConfig( selectedVariations ); - - useSyncNavigatorScreen(); - - const siteInfo = { - title: searchParams.get( 'site_title' ) || site?.name, - tagline: searchParams.get( 'site_tagline' ) || site?.description || SITE_TAGLINE, - }; - - const getPatterns = ( patternType?: string | null ) => { - let patterns = [ header, ...sections, footer ]; - - if ( 'header' === patternType ) { - patterns = [ header ]; - } - if ( 'footer' === patternType ) { - patterns = [ footer ]; - } - if ( 'section' === patternType ) { - patterns = sections; - } - - return patterns.filter( ( pattern ) => pattern ) as Pattern[]; - }; - - const trackEventPatternSelect = ( { - patternType, - patternId, - patternName, - patternTitle, - patternCategory, - }: { - patternType: string; - patternId: number; - patternName: string; - patternTitle: string; - patternCategory: string | undefined; - } ) => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_SELECT_CLICK, { - pattern_type: patternType, - pattern_id: patternId, - pattern_name: patternName, - pattern_title: patternTitle, - pattern_category: patternCategory, - } ); - }; - - const trackSubmit = () => { - const patterns = getPatterns(); - const categories = Array.from( new Set( patterns.map( ( { category } ) => category?.name ) ) ); - - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.CONTINUE_TO_EDITOR_CLICK, { - pattern_types: [ header && 'header', sections.length && 'section', footer && 'footer' ] - .filter( Boolean ) - .join( ',' ), - pattern_ids: patterns.map( ( { ID } ) => ID ).join( ',' ), - pattern_names: patterns.map( ( { name } ) => name ).join( ',' ), - pattern_categories: categories.join( ',' ), - category_count: categories.length, - pattern_count: patterns.length, - page_slugs: ( pageSlugs || [] ).join( ',' ), - } ); - - patterns.forEach( ( { ID, name, title, category } ) => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_FINAL_SELECT, { - pattern_id: ID, - pattern_name: name, - pattern_title: title, - pattern_category: category?.name, - } ); - } ); - - pages.forEach( ( pattern: Pattern ) => { - const category_slug = Object.keys( pattern.categories )[ 0 ]; - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PAGE_FINAL_SELECT, { - pattern_id: pattern.ID, - pattern_name: pattern.name, - pattern_title: pattern.title, - ...( category_slug && { pattern_category: category_slug } ), - } ); - } ); - }; - - const getDesign = () => ( { - ...selectedDesign, - recipe: { - ...selectedDesign?.recipe, - header_pattern_ids: header ? [ encodePatternId( header.ID ) ] : undefined, - pattern_ids: sections.filter( Boolean ).map( ( pattern ) => encodePatternId( pattern.ID ) ), - footer_pattern_ids: footer ? [ encodePatternId( footer.ID ) ] : undefined, - } as DesignRecipe, - } ); - - const updateActivePatternPosition = ( position: number ) => { - const patternPosition = header ? position + 1 : position; - setActivePosition( Math.max( patternPosition, 0 ) ); - }; - - const updateHeader = ( pattern: Pattern | null ) => { - setHeader( pattern ); - updateActivePatternPosition( -1 ); - if ( pattern ) { - noticeOperations.showPatternInsertedNotice( pattern ); - } else if ( header ) { - noticeOperations.showPatternRemovedNotice( header ); - } - }; - - const activateFooterPosition = ( hasFooter: boolean ) => { - const lastPosition = hasFooter ? sections.length : sections.length - 1; - updateActivePatternPosition( lastPosition ); - }; - - const updateFooter = ( pattern: Pattern | null ) => { - setFooter( pattern ); - activateFooterPosition( !! pattern ); - if ( pattern ) { - noticeOperations.showPatternInsertedNotice( pattern ); - } else if ( footer ) { - noticeOperations.showPatternRemovedNotice( footer ); - } - }; - - const replaceSection = ( pattern: Pattern, position: number | null = sectionPosition ) => { - if ( position !== null ) { - setSections( [ - ...sections.slice( 0, position ), - pattern, - ...sections.slice( position + 1 ), - ] ); - updateActivePatternPosition( position ); - noticeOperations.showPatternInsertedNotice( pattern ); - } - }; - - const addSection = ( pattern: Pattern ) => { - setSections( [ ...( sections as Pattern[] ), pattern ] ); - updateActivePatternPosition( sections.length ); - noticeOperations.showPatternInsertedNotice( pattern ); - }; - - const deleteSection = ( position: number ) => { - noticeOperations.showPatternRemovedNotice( sections[ position ] ); - setSections( [ ...sections.slice( 0, position ), ...sections.slice( position + 1 ) ] ); - updateActivePatternPosition( position ); - }; - - const moveDownSection = ( position: number ) => { - const section = sections[ position ]; - setSections( [ - ...sections.slice( 0, position ), - ...sections.slice( position + 1, position + 2 ), - section, - ...sections.slice( position + 2 ), - ] ); - updateActivePatternPosition( position + 1 ); - }; - - const moveUpSection = ( position: number ) => { - const section = sections[ position ]; - setSections( [ - ...sections.slice( 0, position - 1 ), - section, - ...sections.slice( position - 1, position ), - ...sections.slice( position + 1 ), - ] ); - updateActivePatternPosition( position - 1 ); - }; - - const onSelect = ( - type: PatternType, - selectedPattern: Pattern | null, - selectedCategory?: string | null - ) => { - if ( selectedPattern ) { - injectCategoryToPattern( selectedPattern, categories, selectedCategory ); - - trackEventPatternSelect( { - patternType: type, - patternId: selectedPattern.ID, - patternName: selectedPattern.name, - patternTitle: selectedPattern.title, - patternCategory: selectedPattern.category?.name, - } ); - - if ( 'section' === type ) { - if ( sectionPosition !== null ) { - replaceSection( selectedPattern ); - } else { - addSection( selectedPattern ); - } - } - } - - if ( 'header' === type ) { - updateHeader( selectedPattern ); - } - if ( 'footer' === type ) { - updateFooter( selectedPattern ); - } - }; - - const onPreselectPattern = ( type: PatternType, selectedPattern: Pattern ) => { - injectCategoryToPattern( selectedPattern, categories, type ); - - if ( 'header' === type ) { - setHeader( selectedPattern ); - } - if ( 'footer' === type ) { - setFooter( selectedPattern ); - } - }; - - const onSubmit = () => { - const design = getDesign() as Design; - const stylesheet = design.recipe?.stylesheet ?? ''; - const themeId = getThemeIdFromStylesheet( stylesheet ); - - if ( ! siteSlugOrId || ! site?.ID || ! themeId ) { - return; - } - - setPendingAction( () => - Promise.resolve() - .then( () => - reduxDispatch( - activateOrInstallThenActivate( themeId, site?.ID, { - source: 'assembler', - } ) as ThunkAction< PromiseLike< string >, any, any, AnyAction > - ) - ) - .then( ( activeThemeStylesheet: string ) => - assembleSite( siteSlugOrId, activeThemeStylesheet, { - homeHtml: sections.map( ( pattern ) => pattern.html ).join( '' ), - headerHtml: header?.html, - footerHtml: footer?.html, - pages: pages.map( ( page: Pattern ) => ( { - title: page.title, - content: page.html, - } ) ), - globalStyles: syncedGlobalStylesUserConfig, - // Newly created sites can have the content replaced when necessary, - // e.g. when the homepage has a blog pattern, we replace the posts with the content from theme demo site. - // TODO: Ask users whether they want that. - canReplaceContent: isNewSite, - // All sites using the assembler set the option wpcom_site_setup - siteSetupOption: design.is_virtual ? 'assembler-virtual-theme' : 'assembler', - } ) - ) - ); - - const siteTitleFromUrl = ( searchParams.get( 'site_title' ) || '' ).trim(); - const siteTaglineFromUrl = searchParams.get( 'site_tagline' ) || ''; - - // Save site title/description passed to the Assembler. - if ( siteTitleFromUrl || siteTaglineFromUrl ) { - saveSiteSettings( siteSlugOrId, { - ...( siteTitleFromUrl && { blogname: siteTitleFromUrl } ), - ...( siteTaglineFromUrl && { blogdescription: siteTaglineFromUrl } ), - } ); - } - - recordSelectedDesign( { flow, intent, design } ); - trackSubmit(); - submit?.(); - }; - - const onContinue = () => { - if ( ! currentScreen.nextScreen ) { - onSubmit(); - return; - } - - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_CONTINUE_CLICK, { - screen_from: currentScreen.name, - screen_to: currentScreen.nextScreen.name, - } ); - - navigator.goTo( currentScreen.nextScreen.initialPath, { - // We have to replace the path if the screens of previous and next are the same. - // Otherwise, the behavior of the Back button might be weird when you navigate - // to the current screen again. - replace: currentScreen.previousScreen?.name === currentScreen.nextScreen?.name, - } ); - }; - - const globalStylesUpgradeProps = useGlobalStylesUpgradeProps( { - flowName: flow, - stepName, - nextScreenName: 'confirmation', - onUpgradeLater: onContinue, - recordTracksEvent, - } ); - - const getBackLabel = () => { - // Exits the Assembler. - if ( isSiteAssemblerFlow( flow ) && ! currentScreen.previousScreen ) { - if ( flow === AI_ASSEMBLER_FLOW ) { - return translate( 'Back' ); - } - - return translate( 'Back to themes' ); - } - - if ( ! currentScreen.previousScreen ) { - // Go back to the Theme Showcase if people are from the with-theme-assembler flow. - if ( isWithThemeAssemblerFlow( flow ) ) { - return translate( 'Back to themes' ); - } - - return undefined; - } - - return translate( 'Back to %(pageTitle)s', { - args: { - pageTitle: currentScreen.previousScreen.backLabel || currentScreen.previousScreen.title, - }, - } ); - }; - - const shouldHideBack = () => { - // Back button goes to the previous Assembler navigation screen. - if ( currentScreen.previousScreen ) { - return false; - } - - // Back button goes to the Theme Showcase. - if ( ! isNewSite ) { - return false; - } - - // Back button goes to the AI prompt step. - if ( flow === AI_ASSEMBLER_FLOW ) { - return false; - } - - // Don't show the “Back” button if the site is being created by the site assembler flow. - // as the previous step is the site creation step that cannot be undone. - return isSiteAssemblerFlow( flow ); - }; - - const shouldIgnoreSelectedPagesInPreview = () => { - if ( flow === AI_ASSEMBLER_FLOW ) { - return false; - } - - return ! [ 'confirmation', 'upsell' ].includes( currentScreen.name ); - }; - - const customActionButtons = () => { - if ( - flow === AI_ASSEMBLER_FLOW && - currentScreen.name === INITIAL_SCREEN && - aiAssemblerPrompt !== '' - ) { - return ( - - ); - } - - return undefined; - }; - - const onBack = () => { - // Go back to the previous screen - if ( currentScreen.previousScreen ) { - if ( navigator.location.isInitial && currentScreen.name !== INITIAL_SCREEN ) { - navigator.goTo( currentScreen.previousScreen.initialPath, { replace: true } ); - } else { - navigator.goBack(); - } - - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_BACK_CLICK, { - screen_from: currentScreen.name, - screen_to: currentScreen.previousScreen.name, - } ); - return; - } - - // Go back to the previous step - const patterns = getPatterns(); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.BACK_CLICK, { - has_selected_patterns: patterns.length > 0, - pattern_count: patterns.length, - } ); - - resetRecipe(); - goBack?.(); - }; - - const onConfirm = () => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_CONFIRMATION_CONFIRM_CLICK ); - onContinue(); - }; - - const onMainItemSelect = ( name: string ) => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.MAIN_ITEM_SELECT, { name } ); - if ( 'header' === name ) { - return updateActivePatternPosition( -1 ); - } - if ( 'footer' === name ) { - return activateFooterPosition( !! footer ); - } - }; - - const onDeleteSection = ( position: number ) => { - deleteSection( position ); - setSectionPosition( null ); - }; - - const onMoveUpSection = ( position: number ) => { - moveUpSection( position ); - }; - - const onMoveDownSection = ( position: number ) => { - moveDownSection( position ); - }; - - const onDeleteHeader = () => onSelect( 'header', null ); - - const onDeleteFooter = () => onSelect( 'footer', null ); - - const onShuffle = ( type: string, pattern: Pattern, position?: number ) => { - const availableCategory = Object.keys( pattern.categories ).find( - ( category ) => layoutCategoryPatternsMap[ category ] - ); - const selectedCategory = pattern.category?.name || availableCategory || ''; - const patterns = layoutCategoryPatternsMap[ selectedCategory ]; - const shuffledPattern = getShuffledPattern( patterns, pattern ); - injectCategoryToPattern( shuffledPattern, categories, selectedCategory ); - - if ( type === 'header' ) { - updateHeader( shuffledPattern ); - } else if ( type === 'footer' ) { - updateFooter( shuffledPattern ); - } else { - replaceSection( shuffledPattern, position ); - } - }; - - const onScreenColorsSelect = ( variation: GlobalStylesObject | null ) => { - setColorVariation( variation ); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_COLORS_PREVIEW_CLICK, { - color_variation_title: getVariationTitle( variation ), - color_variation_type: getVariationType( variation ), - } ); - }; - - const onScreenFontsSelect = ( variation: GlobalStylesObject | null ) => { - setFontVariation( variation ); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_FONTS_PREVIEW_CLICK, { - font_variation_title: getVariationTitle( variation ), - font_variation_type: getVariationType( variation ), - } ); - }; - - const onScreenPagesSelect = ( pageSlug: string ) => { - if ( pageSlugs.includes( pageSlug ) ) { - setPageSlugs( pageSlugs.filter( ( item: string ) => item !== pageSlug ) ); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_PAGES_PAGE_REMOVE, { page: pageSlug } ); - } else { - setPageSlugs( [ ...pageSlugs, pageSlug ] ); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_PAGES_PAGE_ADD, { page: pageSlug } ); - } - }; - - if ( ! site?.ID || ! selectedDesign ) { - return null; - } - - const stepContent = ( -
- { noticeUI } -
- - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - -
- { currentScreen.name === 'pages' ? ( - - ) : ( - - ) } -
- ); - - return ( - - { stepContent } - - } - recordTracksEvent={ recordTracksEvent } - /> - ); -}; - -const PatternAssemblerStep = ( props: StepProps & NoticesProps ) => { - const initialPath = useInitialPath(); - - return ( - - - - ); -}; - -export default compose( - withGlobalStylesProvider, - withNotices -)( PatternAssemblerStep ) as FC< StepProps >; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/keyframes.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/keyframes.scss deleted file mode 100644 index c1fedcae3d2e4..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/keyframes.scss +++ /dev/null @@ -1,28 +0,0 @@ -@keyframes fadeIn { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@keyframes fadeInShort { - 0% { - opacity: 0.5; - } - - 100% { - opacity: 1; - } -} - -@keyframes slideInShort { - from { - transform: translateX(15%); - } - to { - transform: translateX(0%); - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/navigator-title/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/navigator-title/index.tsx deleted file mode 100644 index c9e1b92f7e5fb..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/navigator-title/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import DocumentHead from 'calypso/components/data/document-head'; - -interface Props { - title: string; -} - -const NavigatorTitle = ( { title }: Props ) => ( - <> - - { title } - -); - -export default NavigatorTitle; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.scss deleted file mode 100644 index b66331b174044..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.scss +++ /dev/null @@ -1,11 +0,0 @@ -.pattern-assembler { - .components-snackbar-list { - overflow: hidden; - bottom: 16px; - padding-inline-end: 16px; - } - - .components-snackbar { - margin-inline-start: auto; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx deleted file mode 100644 index a2e6bd1ce0fc7..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Notice, SnackbarList } from '@wordpress/components'; -import { createHigherOrderComponent } from '@wordpress/compose'; -import i18n from 'i18n-calypso'; -import { ComponentType, ReactNode, ReactElement, useState } from 'react'; -import type { Pattern } from '../types'; -import './notices.scss'; - -const NOTICE_TIMEOUT = 5000; - -type Notice = Omit< React.ComponentProps< typeof Notice >, 'children' > & { - timer?: ReturnType< typeof setTimeout >; - id: string; - content: string; -}; - -interface NoticeOperationsProps { - showPatternInsertedNotice: ( pattern: Pattern ) => void; - showPatternRemovedNotice: ( pattern: Pattern ) => void; -} - -export interface NoticesProps { - noticeOperations: NoticeOperationsProps; - noticeUI: ReactNode; -} - -const withNotices = createHigherOrderComponent( - < OuterProps, >( InnerComponent: ComponentType< OuterProps > ) => { - return ( props: OuterProps & NoticesProps ) => { - const [ noticeList, setNoticeList ] = useState< Notice[] >( [] ); - - const removeNotice = ( id: string ) => { - setNoticeList( ( current ) => current.filter( ( notice ) => notice.id !== id ) ); - }; - - const createNotice = ( id: string, content: ReactElement | string | number ) => { - const existingNoticeWithSameId = noticeList.find( ( notice ) => notice.id === id ); - if ( existingNoticeWithSameId?.timer ) { - clearTimeout( existingNoticeWithSameId.timer ); - delete existingNoticeWithSameId.timer; - } - - const newNotice = { - id, - content, - timer: setTimeout( () => { - removeNotice( id ); - }, NOTICE_TIMEOUT ), - }; - - setNoticeList( - ( current ) => - [ ...current.filter( ( notice ) => notice.id !== id ), newNotice ] as Notice[] - ); - }; - - const noticeOperations: NoticeOperationsProps = { - showPatternInsertedNotice: ( pattern: Pattern ) => { - createNotice( - 'pattern-inserted', - i18n.translate( 'Block pattern "%(patternName)s" inserted.', { - args: { patternName: pattern.title }, - } ) - ); - }, - showPatternRemovedNotice: ( pattern: Pattern ) => { - createNotice( - 'pattern-removed', - i18n.translate( 'Block pattern "%(patternName)s" removed.', { - args: { patternName: pattern.title }, - } ) - ); - }, - }; - - const noticeUI = ; - - const propsWithNotices = { - ...props, - noticeOperations, - noticeUI, - }; - - return ; - }; - }, - 'withNotices' -); - -export default withNotices; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.scss deleted file mode 100644 index 80f98fbaa8d0c..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.scss +++ /dev/null @@ -1,58 +0,0 @@ -.page-list { - button { - border-radius: 2px; - - &:focus-visible:not(:disabled) { - border-color: var(--color-primary-light); - box-shadow: 0 0 0 2px var(--color-primary-light); - } - } -} - -.page-list-item { - cursor: pointer; - padding: 10px 8px; - transition: background-color 0.2s; - - &:hover { - &__label { - color: var(--studio-blue-50); - } - } - - - &--selected &__icon { - background-color: var(--studio-blue-50); - border-color: var(--studio-blue-50); - } - - &--disabled { - cursor: default; - } - - &--disabled &__icon { - background-color: var(--studio-gray-20); - } - - &--disabled &__label { - color: var(--studio-gray-100); - } - - &__icon { - align-items: center; - border-radius: 16px; /* stylelint-disable-line scales/radii */ - border: 1px solid var(--studio-gray-20); - box-sizing: border-box; - color: #fff; - display: flex; - height: 16px; - justify-content: center; - width: 16px; - transition: background-color 0.2s; - } - - &__label { - color: var(--studio-gray-100); - text-transform: capitalize; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.tsx deleted file mode 100644 index d59062f557caf..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-list.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Gridicon } from '@automattic/components'; -import { - __experimentalHStack as HStack, - __experimentalVStack as VStack, - __unstableComposite as Composite, - __unstableUseCompositeState as useCompositeState, - __unstableCompositeItem as CompositeItem, - FlexItem, -} from '@wordpress/components'; -import clsx from 'clsx'; -import { useTranslate } from 'i18n-calypso'; -import './page-list.scss'; - -interface PageListItemProps { - label?: string; - isSelected?: boolean; - isDisabled?: boolean; -} - -const PageListItem = ( { label, isSelected, isDisabled }: PageListItemProps ) => { - return ( - - - { /* eslint-disable wpcalypso/jsx-gridicon-size */ } - - - { label } - - ); -}; - -interface PageListProps { - pagesToShow: any[]; - onSelectPage: ( selectedPage: string ) => void; -} - -const PageList = ( { pagesToShow, onSelectPage }: PageListProps ) => { - const translate = useTranslate(); - - const composite = useCompositeState( { orientation: 'vertical' } ); - - return ( - - - - - - { pagesToShow.map( ( page ) => { - return ( - onSelectPage( page.name ) } - > - - - ); - } ) } - - - ); -}; - -export default PageList; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.scss deleted file mode 100644 index 038dc6e6b866a..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.scss +++ /dev/null @@ -1,53 +0,0 @@ -@import "@wordpress/base-styles/breakpoints"; -@import "@wordpress/base-styles/mixins"; -@import "../variables"; - -.pattern-assembler__preview-list { - box-sizing: border-box; - display: grid; - flex: 1; - gap: 48px; - grid-template-columns: 1fr; - grid-template-rows: min-content; - height: 100vh; - overflow-y: scroll; - padding: 100px 12px; - z-index: z-index("root", ".pattern-assembler__preview-list--fullscreen-preview"); - - &--fullscreen-preview { - margin-left: -$pattern-assembler-sidebar-width; - overflow: hidden; - padding-left: calc($pattern-assembler-sidebar-width + 12px); - - @include break-wide { - margin-left: -$pattern-assembler-sidebar-width-wide; - padding-left: calc($pattern-assembler-sidebar-width-wide + 12px); - } - - .pattern-assembler__preview--fullscreen-leave { - z-index: z-index("root", ".pattern-assembler__preview-list--fullscreen-preview"); - } - } - - @include break-medium { - gap: 48px 24px; - grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); - } - - @include break-huge { - gap: 48px; - grid-template-columns: repeat(3, 1fr); - } - - @media (min-width: 1600px) { - grid-template-columns: repeat(4, 1fr); - } - - @media (min-width: 1920px) { - grid-template-columns: repeat(5, 1fr); - - } - @media (min-width: 2560px) { - grid-template-columns: repeat(6, 1fr); - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.tsx deleted file mode 100644 index bb34d0430c4be..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview-list.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { useGlobalStyle } from '@automattic/global-styles'; -import { - __unstableComposite as Composite, - __unstableUseCompositeState as useCompositeState, -} from '@wordpress/components'; -import clsx from 'clsx'; -import { useTranslate } from 'i18n-calypso'; -import { CSSProperties, useCallback, useMemo, useState } from 'react'; -import { injectTitlesToPageListBlock } from '../html-transformers'; -import PagePreview from './page-preview'; -import type { Pattern } from '../types'; -import './page-preview-list.scss'; - -interface Props { - selectedHeader: Pattern | null; - selectedSections: Pattern[]; - selectedFooter: Pattern | null; - selectedPages: Pattern[]; - selectedPageSlugs: string[]; - isNewSite: boolean; -} - -const PagePreviewList = ( { - selectedHeader, - selectedSections, - selectedFooter, - selectedPages, - selectedPageSlugs, - isNewSite, -}: Props ) => { - const translate = useTranslate(); - const composite = useCompositeState( { orientation: 'horizontal' } ); - const [ isFullscreenPreview, setIsFullscreenPreview ] = useState( false ); - - const [ backgroundColor ] = useGlobalStyle( 'color.background' ); - const pagePreviewStyle = useMemo( - () => ( { '--page-preview-background': backgroundColor } ) as CSSProperties, - [ backgroundColor ] - ); - - const homepage = useMemo( - () => [ selectedHeader, ...selectedSections, selectedFooter ].filter( Boolean ) as Pattern[], - [ selectedHeader, selectedSections, selectedFooter ] - ); - - const transformPatternHtml = useCallback( - ( patternHtml: string ) => { - const pageTitles = selectedPages.map( ( page ) => page.title ); - return injectTitlesToPageListBlock( patternHtml, pageTitles, { - replaceCurrentPages: isNewSite, - } ); - }, - [ isNewSite, selectedPages ] - ); - - const handleFullscreenEnter = () => { - setIsFullscreenPreview( true ); - }; - - const handleFullscreenLeave = () => { - // The timeout delay should match the CSS transition timing of the element. - setTimeout( () => setIsFullscreenPreview( false ), 200 ); - }; - - return ( - <> - - - { selectedPages.map( ( page, index ) => ( - - ) ) } - - - ); -}; - -export default PagePreviewList; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.scss deleted file mode 100644 index e8c443c55f6f4..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.scss +++ /dev/null @@ -1,137 +0,0 @@ -@import "@wordpress/base-styles/breakpoints"; -@import "@wordpress/base-styles/mixins"; -@import "@automattic/typography/styles/variables"; - -$font-family: "SF Pro Text", $sans; - -.pattern-assembler__preview { - aspect-ratio: 3/4; - display: flex; - flex-direction: column; - pointer-events: auto; - transition: all 0.2s; - user-select: none; - - &.pattern-assembler__preview--fullscreen { - cursor: pointer; - position: relative; - z-index: 1; - - &::before { - background-color: rgba(var(--color-neutral-70-rgb), 0.8); - bottom: 0; - content: ""; - left: 0; - position: fixed; - right: 0; - top: 0; - } - - &.pattern-assembler__preview--fullscreen-enter, - &.pattern-assembler__preview--fullscreen-leave { - .pattern-assembler__preview-frame { - transition: all 0.2s; - } - } - - .pattern-assembler__preview-frame { - --fullscreen-x-px: calc(50vw - calc(var(--fullscreen-x, 0) * 1px)); - --fullscreen-y-px: calc(50vh - calc(var(--fullscreen-y, 0) * 1px)); - --scale: 1.6; - - box-shadow: - 0 9.95778px 9.95778px 0 rgba(0, 0, 0, 0.02), - 0 21.57518px 16.59629px 0 rgba(0, 0, 0, 0.03); - cursor: default; - transform: translate(var(--fullscreen-x-px), var(--fullscreen-y-px)) scale(var(--scale)); - transition: none; - - @include break-medium { - --scale: var(--fullscreen-scale, 1.8); - } - - &:hover { - background-color: #f8f8f8; - border-color: #f8f8f8; - } - - &-content { - overflow-y: scroll; - - .scaled-block-renderer { - transform: scale(var(--scaled-block-renderer-scale, 1)) perspective(1px); - } - } - } - - .pattern-assembler__preview-title { - opacity: 0; - pointer-events: none; - } - } - - .pattern-assembler__preview-container { - display: flex; - flex: 1; - flex-direction: column; - } - - .pattern-assembler__preview-frame { - background-color: #f8f8f8; - border: 10px solid #f8f8f8; - border-radius: 13px; /* stylelint-disable-line scales/radii */ - box-shadow: - 0 5.25469px 5.25469px 0 rgba(0, 0, 0, 0.02), - 0 11.38516px 8.75781px 0 rgba(0, 0, 0, 0.03); - cursor: pointer; - flex: 1; - min-height: 350px; - overflow: hidden; - position: relative; - transition: all 0.2s ease; - - &:hover { - background-color: #ebebeb; - border-color: #ebebeb; - } - - &:focus-visible { - outline: 2px solid var(--color-primary-light); - } - - &-content { - background: var(--page-preview-background, #f8f8f8); - border-radius: 8.758px; /* stylelint-disable-line scales/radii */ - bottom: 0; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; - user-select: none; - - /** - * Hides the scrollbar to avoid the layout keeps changes forever - * See https://github.com/Automattic/wp-calypso/issues/78357. - */ - scrollbar-width: none; - &::-webkit-scrollbar { - display: none; - } - - @include break-huge { - overflow-y: scroll; - } - } - } - - .pattern-assembler__preview-title { - color: var(--studio-gray-100); - font-family: $font-family; - font-size: $font-body-large; - line-height: 26px; - margin-inline-end: 10px; - margin-inline-start: 10px; - margin-top: 16px; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.tsx deleted file mode 100644 index 18a1ed0428031..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pages/page-preview.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { PatternRenderer } from '@automattic/block-renderer'; -import { isEnabled } from '@automattic/calypso-config'; -import { __unstableCompositeItem as CompositeItem } from '@wordpress/components'; -import clsx from 'clsx'; -import { CSSProperties, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; -import useOutsideClickCallback from 'calypso/lib/use-outside-click-callback'; -import { DEFAULT_VIEWPORT_WIDTH, DEFAULT_VIEWPORT_HEIGHT } from '../constants'; -import { PATTERN_ASSEMBLER_EVENTS } from '../events'; -import prependTitleBlockToPagePattern from '../html-transformers/prepend-title-block-to-page-pattern'; -import PatternTooltipDeadClick from '../pattern-tooltip-dead-click'; -import { encodePatternId, isPagePattern } from '../utils'; -import type { Pattern } from '../types'; -import './page-preview.scss'; - -interface BasePageProps { - style: CSSProperties; - patterns: Pattern[]; - transformPatternHtml: ( patternHtml: string ) => string; -} - -interface PageProps extends BasePageProps { - className: string; -} - -interface PagePreviewProps extends BasePageProps { - composite: Record< string, unknown >; - slug: string; - title: string; - onFullscreenEnter: () => void; - onFullscreenLeave: () => void; -} - -const Page = ( { className, style, patterns, transformPatternHtml }: PageProps ) => { - const pageTitle = useMemo( () => { - return patterns.find( isPagePattern )?.title ?? ''; - }, [ patterns ] ); - - const transformPagePatternHtml = useCallback( - ( patternHtml: string ) => { - const transformedPatternHtml = transformPatternHtml( patternHtml ); - if ( isEnabled( 'pattern-assembler/v2' ) ) { - return transformedPatternHtml; - } - return prependTitleBlockToPagePattern( transformedPatternHtml, pageTitle ); - }, - [ transformPatternHtml, pageTitle ] - ); - - return ( -
- { patterns.map( ( pattern ) => ( - - ) ) } -
- ); -}; - -const PatternPagePreview = ( { - composite, - onFullscreenEnter, - onFullscreenLeave, - ...pageProps -}: PagePreviewProps ) => { - const { slug, title } = pageProps; - const [ isFullscreen, setIsFullscreen ] = useState( false ); - const [ isFullscreenEnter, setIsFullscreenEnter ] = useState( false ); - const [ isFullscreenLeave, setIsFullscreenLeave ] = useState( false ); - const [ shouldShowTooltip, setShouldShowTooltip ] = useState( false ); - - const [ frameStyles, setFrameStyles ] = useState( {} ); - const ref = useRef< HTMLDivElement >( null ); - const frameRef = useRef( null ); - - const calculateFrameStyles = useCallback( () => { - if ( ! ref.current ) { - return; - } - - const { height, width, x, y } = ref.current.getBoundingClientRect(); - setFrameStyles( { - '--fullscreen-scale': ( window.innerHeight * 0.8 ) / height, - '--fullscreen-x': x + width / 2, - '--fullscreen-y': y + height / 2, - } ); - }, [ ref ] ); - - const handleFullscreenEnter = () => { - if ( ! isFullscreen ) { - setIsFullscreen( true ); - onFullscreenEnter(); - - // The timeout delay should match the CSS transition timing of the element. - setIsFullscreenEnter( true ); - setTimeout( () => setIsFullscreenEnter( false ), 200 ); - - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_PAGES_PAGE_PREVIEW_CLICK, { - page_slug: slug, - } ); - } - }; - - // Use useCallback since useOutsideClickCallback memoizes the callback function. - const handleFullscreenLeave = useCallback( () => { - if ( isFullscreen ) { - setIsFullscreen( false ); - onFullscreenLeave(); - - // The timeout delay should match the CSS transition timing of the element. - setIsFullscreenLeave( true ); - setTimeout( () => setIsFullscreenLeave( false ), 200 ); - } - }, [ isFullscreen, onFullscreenLeave ] ); - - const handleMouseDown = () => { - if ( isFullscreen ) { - setShouldShowTooltip( true ); - } - }; - - const handleMouseLeave = () => { - if ( isFullscreen ) { - setShouldShowTooltip( false ); - } - }; - - useEffect( () => { - if ( isFullscreen ) { - calculateFrameStyles(); - } - }, [ isFullscreen, calculateFrameStyles ] ); - - useEffect( () => { - window.addEventListener( 'resize', calculateFrameStyles ); - return () => { - window.removeEventListener( 'resize', calculateFrameStyles ); - }; - }, [ calculateFrameStyles ] ); - - useOutsideClickCallback( ref, handleFullscreenLeave ); - - return ( -
-
- - - -
{ title }
-
- { isFullscreen && ( - - ) } -
- ); -}; - -export default PatternPagePreview; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/panel.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/panel.tsx deleted file mode 100644 index 72ed9b418317c..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/panel.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { ReactNode } from 'react'; - -const Panel = ( { - label, - description, - children, -}: { - children: ReactNode; - label?: string; - description?: string; -} ) => { - return ( -
-
{ label }
-
{ description }
- { children } -
- ); -}; - -export default Panel; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.scss deleted file mode 100644 index fcae8f79b7fa0..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.scss +++ /dev/null @@ -1,91 +0,0 @@ -.pattern-assembler__pattern-action-bar { - display: flex; - align-items: center; - gap: 0; - position: absolute; - top: 16px; - left: 16px; - height: 40px; - padding: 0; - border: 1px solid #1e1e1e; - border-radius: 2px; - box-sizing: border-box; - background-color: #fff; - z-index: 1; - - &.pattern-assembler__pattern-action-bar--overflow { - transform: translate(-16px, calc(-100% - 16px - 12px)); - - &::before { - display: block; - } - } - - .pattern-action-bar__block { - flex-direction: column; - display: flex; - align-items: center; - justify-content: center; - } - - .pattern-action-bar__action { - height: 40px; - white-space: nowrap; - - &.has-icon { - min-width: 40px; - max-width: 40px; - padding: 0; - } - - svg { - fill: var(--studio-gray-80); - } - - &:not(:disabled):hover { - color: var(--studio-blue-50); - - svg { - fill: var(--studio-blue-50); - } - } - - &--move-up, - &--move-down { - height: 13px; - display: flex; - align-items: center; - } - - &--shuffle { - &.has-icon { - flex-direction: row; - gap: 4px; - line-height: 40px; - max-width: none; - padding: 0 12px; - } - } - } - - > .pattern-action-bar__action:not(:first-child) { - border-left: 1px solid #1e1e1e; - } - - /** - * Increase the area of the action bar to keep the element active - * when hovering on the the action bar - */ - &::before { - content: ""; - display: none; - position: absolute; - top: -12px; - left: -12px; - width: 100%; - height: 100%; - padding: 12px 12px 20px 12px; - box-sizing: content-box; - z-index: -1; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.tsx deleted file mode 100644 index 233a053dd0a01..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-action-bar.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { Button } from '@wordpress/components'; -import { chevronUp, chevronDown, edit, shuffle, trash } from '@wordpress/icons'; -import clsx from 'clsx'; -import { useTranslate } from 'i18n-calypso'; -import React from 'react'; -import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import type { Category } from './types'; -import './pattern-action-bar.scss'; - -type PatternActionBarProps = { - onReplace?: () => void; - onDelete: () => void; - onMoveUp?: () => void; - onMoveDown?: () => void; - onShuffle: () => void; - onMouseLeave?: ( event: React.MouseEvent< HTMLElement > ) => void; - disableMoveUp?: boolean; - disableMoveDown?: boolean; - patternType: string; - category?: Category; - source: 'list' | 'large_preview'; - isOverflow?: boolean; -}; - -const PatternActionBar = ( { - onReplace, - onDelete, - onMoveUp, - onMoveDown, - onShuffle, - onMouseLeave, - disableMoveUp, - disableMoveDown, - patternType, - category, - source, - isOverflow, -}: PatternActionBarProps ) => { - const translate = useTranslate(); - const eventProps = { - pattern_type: patternType, - pattern_category: category?.name, - source, - }; - - return ( - // eslint-disable-next-line jsx-a11y/interactive-supports-focus -
- { onMoveUp && onMoveDown && ( -
-
- ) } -
- ); -}; - -export default PatternActionBar; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-assembler-container.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-assembler-container.tsx deleted file mode 100644 index 6bdb9e17cad63..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-assembler-container.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { BlockRendererProvider, PatternsRendererProvider } from '@automattic/block-renderer'; -import { getPlaceholderSiteID } from '@automattic/data-stores/src/site/constants'; -import { useMemo } from 'react'; -import StepperLoader from '../../components/stepper-loader'; -import { encodePatternId } from './utils'; -import type { Pattern } from './types'; -import type { SiteInfo } from '@automattic/block-renderer'; - -interface Props { - siteId: number | string; - stylesheet: string; - patternsMapByCategory: Record< string, Pattern[] >; - children: JSX.Element; - siteInfo: SiteInfo; - isNewSite: boolean; -} - -const PatternAssemblerContainer = ( { - siteId, - stylesheet, - patternsMapByCategory, - children, - siteInfo, - isNewSite, -}: Props ) => { - const patternIdsByCategory = useMemo( - () => - Object.fromEntries( - Object.entries( patternsMapByCategory ).map( ( [ category, patterns ] ) => [ - category, - patterns.map( ( pattern ) => encodePatternId( pattern.ID ) ), - ] ) - ), - [ patternsMapByCategory ] - ); - - return ( - } - > - - { children } - - - ); -}; - -export default PatternAssemblerContainer; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.scss deleted file mode 100644 index 5b4c9f6df58bf..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.scss +++ /dev/null @@ -1,26 +0,0 @@ -.pattern-category-list { - margin: 16px 0; - - button { - margin: 0 -5px 0 -8px; - border-radius: 2px; - - .navigator-item { - margin: 0; - width: auto; - - &.navigator-item--active { - border-radius: 2px; - } - } - - &:focus-visible { - border-color: var(--color-primary); - box-shadow: 0 0 0 2px var(--color-primary-light); - - .navigator-item { - color: var(--studio-blue-50); - } - } - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.stories.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.stories.tsx deleted file mode 100644 index e85e54c8ae83e..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.stories.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { action } from '@storybook/addon-actions'; -import { Story, Meta } from '@storybook/react'; -import { ComponentProps } from 'react'; -import { documentHeadStoreMock, ReduxDecorator } from 'calypso/__mocks__/storybook/redux'; -import PatternCategoryList from './pattern-category-list'; - -import './style.scss'; -import './pattern-category-list.scss'; - -export default { - title: 'client/landing/pattern-assembler/PatternCategoryList', - component: PatternCategoryList, - decorators: [ - ( Story ) => { - return ( - - - - ); - }, - ( Story ) => { - return ( -
- -
- ); - }, - ], -} as Meta; - -type PatternCategoryListStory = Story< ComponentProps< typeof PatternCategoryList > >; -const Template: PatternCategoryListStory = ( args ) => ; - -const defaultArgs = { - categories: [ - { name: 'about', label: 'About', description: 'Introduce yourself.' }, - { name: 'blog', label: 'Blog' }, - ], - patternCountMapByCategory: { - about: 2, - blog: 2, - }, - patternsMapByCategory: { - about: [ - { - ID: 7814, - site_id: 174455321, - title: 'Hero with Heading and Cover Image', - name: 'hero-with-heading-and-cover-image', - description: '', - html: '
test
', - categories: { about: { slug: 'about', title: 'About', description: '' } }, - virtual_theme_categories: [], - tags: { pattern: { slug: 'pattern', title: 'Pattern', description: '' } }, - pattern_meta: { is_web: true, is_mobile: false }, - source_url: 'https://dotcompatterns.wordpress.com/?p=7814', - modified_date: '2022-11-30 09:20:46', - }, - { - ID: 6306, - site_id: 174455321, - title: 'Team', - name: 'team-4', - description: '', - html: '
test
', - categories: { - about: { slug: 'about', title: 'About', description: '' }, - wireframe: { slug: 'wireframe', title: 'Wireframe', description: '' }, - }, - virtual_theme_categories: [], - tags: { pattern: { slug: 'pattern', title: 'Pattern', description: '' } }, - pattern_meta: { is_web: true, is_mobile: false }, - source_url: 'https://blockpatterns.mystagingwebsite.com/?p=64', - modified_date: '2023-03-29 07:25:38', - }, - ], - blog: [ - { - ID: 3681, - site_id: 174455321, - title: 'Blog', - name: 'blog-8', - description: '', - html: '
test
', - categories: { - blog: { slug: 'blog', title: 'Blog', description: '' }, - featured: { slug: 'featured', title: 'Featured', description: '' }, - }, - virtual_theme_categories: [], - tags: { - layout: { slug: 'layout', title: 'Layout', description: '' }, - pattern: { slug: 'pattern', title: 'Pattern', description: '' }, - }, - pattern_meta: { is_mobile: true, is_web: true }, - source_url: 'https://dotcompatterns.wordpress.com/?p=3681', - modified_date: '2023-02-10 13:55:09', - }, - { - ID: 1593, - site_id: 174455321, - title: 'Heading and Three Images', - name: 'heading-and-three-images', - description: '', - html: '
test
', - categories: { - blog: { slug: 'blog', title: 'Blog', description: '' }, - featured: { slug: 'featured', title: 'Featured', description: '' }, - }, - virtual_theme_categories: [], - tags: { pattern: { slug: 'pattern', title: 'Pattern', description: '' } }, - pattern_meta: { is_web: true, is_mobile: false }, - source_url: 'https://dotcompatterns.wordpress.com/?p=1593', - modified_date: '2022-10-04 16:38:31', - }, - ], - }, - selectedCategory: 'about', - onSelectCategory: action( 'onSelectCategory' ), -}; - -export const Default = Template.bind( {} ); -Default.args = { - ...defaultArgs, -}; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.tsx deleted file mode 100644 index 6243a62e122a9..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-category-list.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { NavigatorItem } from '@automattic/onboarding'; -import { - __experimentalVStack as VStack, - __unstableComposite as Composite, - __unstableUseCompositeState as useCompositeState, - __unstableCompositeItem as CompositeItem, -} from '@wordpress/components'; -import { file } from '@wordpress/icons'; -import { useTranslate } from 'i18n-calypso'; -import { ORDERED_PATTERN_CATEGORIES } from './constants'; -import { useCategoriesOrder } from './hooks'; -import PatternCount from './pattern-count'; -import type { Pattern, Category } from './types'; -import './pattern-category-list.scss'; - -interface Props { - categories: Category[]; - patternsMapByCategory: Record< string, Pattern[] >; - patternCountMapByCategory: Record< string, number >; - selectedCategory: string; - onSelectCategory: ( selectedCategory: string ) => void; -} - -const PatternCategoryList = ( { - categories, - patternsMapByCategory, - patternCountMapByCategory, - selectedCategory, - onSelectCategory, -}: Props ) => { - const translate = useTranslate(); - const categoriesInOrder = useCategoriesOrder( categories, ORDERED_PATTERN_CATEGORIES ); - const composite = useCompositeState( { orientation: 'vertical' } ); - - return ( - - - { categoriesInOrder.map( ( { name, label, description } ) => { - const isActive = selectedCategory === name; - const hasPatterns = name && patternsMapByCategory[ name ]?.length; - const isHeaderCategory = name === 'header'; - const isFooterCategory = name === 'footer'; - - if ( ! hasPatterns || isHeaderCategory || isFooterCategory ) { - return null; - } - - return ( - onSelectCategory( name ) } - > - - <> - { label } - - - - - ); - } ) } - - - ); -}; - -export default PatternCategoryList; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/index.tsx deleted file mode 100644 index ff7e503c50f3a..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import './style.scss'; - -interface Props { - count?: number; -} - -const PatternCount = ( { count = 0 }: Props ) => { - if ( ! count ) { - return null; - } - - return { count }; -}; - -export default PatternCount; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/style.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/style.scss deleted file mode 100644 index 38d21b85034e8..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-count/style.scss +++ /dev/null @@ -1,13 +0,0 @@ -@import "@automattic/typography/styles/variables"; - -.pattern-count { - margin-left: auto; - font-family: "SF Pro Text", $sans; - /* stylelint-disable-next-line declaration-property-unit-allowed-list */ - font-size: 12px; - color: var(--studio-gray-50); - - .navigator-item.navigator-item--active & { - color: inherit; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.scss deleted file mode 100644 index 0d936ecbb71f6..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.scss +++ /dev/null @@ -1,141 +0,0 @@ -@import "@wordpress/base-styles/breakpoints"; -@import "@wordpress/base-styles/mixins"; -@import "./keyframes"; - -.pattern-large-preview { - --viewport-scale: 1; - flex: 1; - position: relative; - height: 100vh; - padding: 32px 0; - margin-inline-end: 32px; - margin-inline-start: 10px; - box-sizing: border-box; - z-index: 1; - transition: margin-inline-start 0.2s ease-out; - - &.device-switcher__container--is-computer:has(.pattern-large-preview__placeholder) { - .device-switcher__frame { - max-width: 1080px; - } - } -} - -.pattern-large-preview__patterns { - position: relative; - flex-grow: 1; - margin: 0; - list-style-type: none; - overflow: auto; - background: var(--pattern-large-preview-background); - - &--has-placeholder { - display: flex; - flex-direction: column; - } - - /** - * Hides the scrollbar to avoid the layout keeps changes forever - * See https://github.com/Automattic/wp-calypso/issues/78357. - */ - scrollbar-width: none; - &::-webkit-scrollbar { - display: none; - } -} - -.pattern-large-preview__pattern { - $pattern-large-preview-outer-border-radius: calc(var(--device-switcher-border-radius) - var(--device-switcher-border-width)); - position: relative; - - &::after { - content: ""; - position: absolute; - left: 1px; - right: 1px; - top: 1px; - bottom: 1px; - border-radius: 2px; - } - - &:first-child::after { - border-top-left-radius: $pattern-large-preview-outer-border-radius; - border-top-right-radius: $pattern-large-preview-outer-border-radius; - } - - &:last-child::after { - border-bottom-left-radius: $pattern-large-preview-outer-border-radius; - border-bottom-right-radius: $pattern-large-preview-outer-border-radius; - } - - &--active, - &:hover, - &:focus, - &:focus-within { - &::after { - // Scale up the border of a active pattern - border: calc(2px * (1 / var(--viewport-scale) / var(--pattern-large-preview-zoom-out-scale))) solid var(--color-primary-light); - } - } -} - -.pattern-large-preview__placeholder { - display: flex; - flex-direction: column; - flex-grow: 1; - align-items: center; - justify-content: center; - width: 100%; - padding: 40px; - color: var(--studio-gray-60); - background: #f8f8f8; - - h2 { - color: #000; - margin-bottom: 16px; - font-size: $font-body-large; - font-weight: 400; - } - - > ul { - color: var(--studio-gray-80); - counter-reset: li; - display: flex; - flex-direction: column; - font-size: $font-body-small; - font-weight: 400; - gap: 10px; - line-height: 20px; - list-style-type: none; - margin: 0; - max-width: 300px; - - > li { - align-items: center; - display: flex; - padding-left: 28px; - position: relative; - - &::before { - align-items: center; - border: 0.909px solid var(--studio-gray-100); - border-radius: 50%; - box-sizing: border-box; - color: var(--studio-gray-100); - content: counter(li); - counter-increment: li; - display: flex; - font-size: 10.909px; /* stylelint-disable-line declaration-property-unit-allowed-list */ - font-weight: 400; - height: 16px; - justify-content: center; - left: 0; - letter-spacing: -0.061px; - line-height: 16px; - position: absolute; - top: 2px; - width: 16px; - } - } - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.tsx deleted file mode 100644 index eff2e9c40f06e..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-large-preview.tsx +++ /dev/null @@ -1,336 +0,0 @@ -import { PatternRenderer } from '@automattic/block-renderer'; -import { DeviceSwitcher } from '@automattic/components'; -import { useGlobalStyle } from '@automattic/global-styles'; -import { Popover } from '@wordpress/components'; -import clsx from 'clsx'; -import { useTranslate } from 'i18n-calypso'; -import React, { useRef, useEffect, useState, useMemo, CSSProperties, useCallback } from 'react'; -import { useDebouncedCallback } from 'use-debounce'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import { injectTitlesToPageListBlock } from './html-transformers'; -import PatternActionBar from './pattern-action-bar'; -import PatternTooltipDeadClick from './pattern-tooltip-dead-click'; -import { encodePatternId } from './utils'; -import type { Pattern } from './types'; -import './pattern-large-preview.scss'; - -interface Props { - header: Pattern | null; - sections: Pattern[]; - footer: Pattern | null; - activePosition: number; - pages?: Pattern[]; - onDeleteSection: ( position: number ) => void; - onMoveUpSection: ( position: number ) => void; - onMoveDownSection: ( position: number ) => void; - onDeleteHeader: () => void; - onDeleteFooter: () => void; - onShuffle: ( type: string, pattern: Pattern, position?: number ) => void; - recordTracksEvent: ( name: string, eventProperties?: any ) => void; - isNewSite: boolean; -} - -// The pattern renderer element has 1px min height before the pattern is loaded -const PATTERN_RENDERER_MIN_HEIGHT = 1; - -const LARGE_PREVIEW_OFFSET_TOP = 110; - -const PatternLargePreview = ( { - header, - sections, - footer, - activePosition, - pages, - onDeleteSection, - onMoveUpSection, - onMoveDownSection, - onDeleteHeader, - onDeleteFooter, - onShuffle, - recordTracksEvent, - isNewSite, -}: Props ) => { - const translate = useTranslate(); - const hasSelectedPattern = Boolean( header || sections.length || footer ); - const frameRef = useRef< HTMLDivElement | null >( null ); - const listRef = useRef< HTMLUListElement | null >( null ); - const [ viewportHeight, setViewportHeight ] = useState< number | undefined >( 0 ); - const [ device, setDevice ] = useState< string >( 'computer' ); - const [ zoomOutScale, setZoomOutScale ] = useState( 1 ); - const zoomOutScaleRef = useRef( zoomOutScale ); - const [ backgroundColor ] = useGlobalStyle( 'color.background' ); - const patternLargePreviewStyle = useMemo( - () => - ( { - '--pattern-large-preview-zoom-out-scale': zoomOutScale, - '--pattern-large-preview-background': backgroundColor, - } ) as CSSProperties, - [ zoomOutScale, backgroundColor ] - ); - - const [ debouncedRecordZoomOutScaleChange ] = useDebouncedCallback( ( value: number ) => { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.LARGE_PREVIEW_ZOOM_OUT_SCALE_CHANGE, { - from_scale: zoomOutScaleRef.current, - to_scale: value, - } ); - zoomOutScaleRef.current = value; - }, 300 ); - - const [ activeElement, setActiveElement ] = useState< HTMLElement | null >( null ); - const [ shouldShowTooltip, setShouldShowTooltip ] = useState( false ); - - const popoverAnchor = useMemo( () => { - if ( ! activeElement ) { - return undefined; - } - - return { - getBoundingClientRect() { - const { left, top, width, height } = activeElement.getBoundingClientRect(); - - return new window.DOMRect( - left, - // Stick to the top when the partial area of the active element is out of the viewport - Math.max( top, LARGE_PREVIEW_OFFSET_TOP ), - width, - height - ); - }, - }; - }, [ activeElement ] ); - - const transformPatternHtml = useCallback( - ( patternHtml: string ) => { - const pageTitles = pages?.map( ( page ) => page.title ); - if ( pageTitles ) { - return injectTitlesToPageListBlock( patternHtml, pageTitles, { - replaceCurrentPages: isNewSite, - } ); - } - return patternHtml; - }, - [ isNewSite, pages ] - ); - - const renderPattern = ( type: string, pattern: Pattern, position = -1 ) => { - const isSection = type === 'section'; - const clientId = isSection ? pattern.key : type; - const isActive = activeElement?.dataset?.clientId === clientId; - - const handleMouseDown = ( event: React.MouseEvent< HTMLElement > ) => { - const target = event.target as HTMLElement | null; - if ( target && target.closest?.( '.pattern-assembler__pattern-action-bar' ) ) { - return; - } - - setShouldShowTooltip( true ); - }; - - const handleMouseEnter = ( event: React.MouseEvent< HTMLElement > ) => { - setActiveElement( event.currentTarget ); - }; - - const handleMouseLeave = ( event: React.MouseEvent< HTMLElement > ) => { - const hasNextActiveElement = - event.relatedTarget instanceof Node && - ! frameRef.current?.contains( event.relatedTarget as Node ); - if ( ! hasNextActiveElement ) { - setActiveElement( null ); - } - }; - - const handleDelete = () => { - setActiveElement( null ); - if ( type === 'header' ) { - onDeleteHeader(); - } else if ( type === 'footer' ) { - onDeleteFooter(); - } else { - onDeleteSection( position ); - } - }; - - return ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -
  • - { !! viewportHeight && ( - - ) } - { isActive && ( - - onMoveUpSection( position ) : undefined } - onMoveDown={ isSection ? () => onMoveDownSection( position ) : undefined } - onShuffle={ () => onShuffle( type, pattern, position ) } - onDelete={ handleDelete } - onMouseLeave={ handleMouseLeave } - /> - - ) } -
  • - ); - }; - - const renderPlaceholder = () => { - return ( -
  • -

    { translate( 'Welcome to your homepage.' ) }

    -
      -
    • { translate( 'Select patterns for your homepage.' ) }
    • -
    • { translate( 'Choose your colors and fonts.' ) }
    • -
    • { translate( 'Pick additional site pages.' ) }
    • -
    • { translate( 'Add your own content in the Editor.' ) }
    • -
    -
  • - ); - }; - - const renderPatterns = () => { - const hasPlaceholder = sections.length === 0; - return ( -
      - { header && renderPattern( 'header', header ) } - { hasPlaceholder - ? renderPlaceholder() - : sections.map( ( pattern, i ) => renderPattern( 'section', pattern, i ) ) } - { footer && renderPattern( 'footer', footer ) } -
    - ); - }; - - const updateViewportHeight = ( height?: number ) => { - // Required for 100vh patterns - setViewportHeight( height ); - }; - - const handleZoomOutScale = ( value: number ) => { - setZoomOutScale( value ); - if ( zoomOutScale !== value ) { - debouncedRecordZoomOutScaleChange( value ); - } - }; - - // Scroll to newly added patterns - useEffect( () => { - let timerId: number; - const scrollIntoView = () => { - const element = listRef.current?.children[ activePosition ]; - if ( ! element ) { - return; - } - - const { height } = element.getBoundingClientRect(); - - // Use the height to determine whether the newly added pattern is loaded. - // If it's not loaded, try to delay the behavior of scrolling into view. - if ( height && height > PATTERN_RENDERER_MIN_HEIGHT ) { - // Note that Firefox has an issue related to "smooth" behavior, so we leave it as default - // See https://github.com/Automattic/wp-calypso/pull/71527#issuecomment-1370522634 - element.scrollIntoView(); - } else { - timerId = window.setTimeout( () => scrollIntoView(), 100 ); - } - }; - - // Only scroll when the pattern is added via the pattern list panel. - // This prevents auto-scrolling when the pattern is added via shuffle, which causes the pattern action bar to jump around. - const focusedElement = document.activeElement; - if ( - ! focusedElement || - focusedElement.classList.contains( 'pattern-list-renderer__pattern-list-item' ) - ) { - scrollIntoView(); - } - - return () => { - if ( timerId ) { - window.clearTimeout( timerId ); - } - }; - }, [ activePosition, header, sections, footer ] ); - - // Unset the hovered element when the mouse is leaving the large preview - useEffect( () => { - const handleMouseLeave = ( event: MouseEvent ) => { - const relatedTarget = event.relatedTarget as HTMLElement | null; - if ( ! relatedTarget?.closest?.( '.pattern-assembler__pattern-action-bar' ) ) { - setActiveElement( null ); - } - - setShouldShowTooltip( false ); - }; - - // When the value of the `hasSelectedPattern` changes, it will append/remove the - // frame to the DOM. Hence, we need to check the value to bind the event again - // after the frame is removed and then appended to the DOM. - if ( ! hasSelectedPattern ) { - return; - } - - frameRef.current?.addEventListener( 'mouseleave', handleMouseLeave ); - return () => { - frameRef.current?.removeEventListener( 'mouseleave', handleMouseLeave ); - }; - }, [ frameRef, hasSelectedPattern, setActiveElement, setShouldShowTooltip ] ); - - return ( - { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PREVIEW_DEVICE_CLICK, { device } ); - setDevice( device ); - } } - onViewportChange={ updateViewportHeight } - onZoomOutScaleChange={ handleZoomOutScale } - > - { renderPatterns() } - { activeElement && ( - - ) } - - ); -}; - -export default PatternLargePreview; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.scss deleted file mode 100644 index c55dd8f0e0a8e..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.scss +++ /dev/null @@ -1,57 +0,0 @@ -@import "@wordpress/base-styles/breakpoints"; -@import "@wordpress/base-styles/mixins"; -@import "@automattic/typography/styles/variables"; - -.pattern-list-panel__wrapper { - width: 340px; - padding: 20px; - background: var(--studio-gray-0); - border-left: 1px solid rgba(0, 0, 0, 0.03); - max-height: 100vh; - min-height: 100vh; - overflow-y: auto; - box-sizing: border-box; - transform: translateX(0); - // Preserve spaces for the scrollbar to prevent unwanted layout change - scrollbar-gutter: stable; - font-family: "SF Pro Text", $sans; - - @include break-wide { - width: 348px; - padding: 24px; - } - - .global-styles-variations__container { - display: flex; - flex-direction: column; - gap: 32px; - padding-top: 4px; - } -} - -.pattern-list-panel__title { - font-size: $font-body; - line-height: 24px; - font-weight: 500; - color: var(--studio-gray-100); - letter-spacing: -0.32px; -} - -.pattern-list-panel__description { - font-size: $font-body-small; - margin: 4px 0 16px; - line-height: 20px; - font-weight: 400; - color: var(--studio-gray-60); - letter-spacing: -0.15px; - text-wrap: pretty; -} - -.pattern-list-panel__show-more { - text-align: center; - padding-top: 10px; - - svg { - margin-inline-start: 10px; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.tsx deleted file mode 100644 index a94df35a28c18..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-panel.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { Button } from '@wordpress/components'; -import { chevronDown } from '@wordpress/icons'; -import { useTranslate } from 'i18n-calypso'; -import { useCallback, useMemo, useState } from 'react'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import { injectTitlesToPageListBlock } from './html-transformers'; -import PatternSelector from './pattern-selector'; -import { isPriorityPattern } from './utils'; -import type { Pattern, Category } from './types'; -import './pattern-list-panel.scss'; - -type PatternListPanelProps = { - onSelect: ( selectedPattern: Pattern | null ) => void; - selectedPattern: Pattern | null; - categories: Category[]; - selectedCategory: string | null; - patternsMapByCategory: { [ key: string ]: Pattern[] }; - selectedPatterns?: Pattern[]; - pages?: Pattern[]; - label?: string; - description?: string; - recordTracksEvent: ( name: string, eventProperties?: any ) => void; - isNewSite: boolean; -}; - -const PatternListPanel = ( { - selectedPattern, - selectedPatterns, - selectedCategory, - categories, - patternsMapByCategory, - pages, - label, - description, - onSelect, - recordTracksEvent, - isNewSite, -}: PatternListPanelProps ) => { - const translate = useTranslate(); - const [ isShowMorePatterns, setIsShowMorePatterns ] = useState( false ); - const categoryPatterns = selectedCategory ? patternsMapByCategory[ selectedCategory ] : []; - const category = useMemo( - () => selectedCategory && categories.find( ( { name } ) => name === selectedCategory ), - [ categories, selectedCategory ] - ); - - const hasNonPriorityPatterns = categoryPatterns?.find( - ( pattern ) => ! isPriorityPattern( pattern ) - ); - - const transformPatternHtml = useCallback( - ( patternHtml: string ) => { - const pageTitles = pages?.map( ( page ) => page.title ); - const isCategoryHeader = category && category.name === 'header'; - if ( isCategoryHeader && pageTitles ) { - return injectTitlesToPageListBlock( patternHtml, pageTitles, { - replaceCurrentPages: isNewSite, - } ); - } - return patternHtml; - }, - [ isNewSite, pages, category ] - ); - - if ( ! category ) { - return null; - } - - return ( -
    -
    { label ?? category?.label }
    -
    - { description ?? category?.description } -
    - - { ! isShowMorePatterns && hasNonPriorityPatterns && ( -
    -
    - ) } -
    - ); -}; - -export default PatternListPanel; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.scss deleted file mode 100644 index 11776a99ef745..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.scss +++ /dev/null @@ -1,20 +0,0 @@ -.pattern-list-renderer__pattern-list-item { - padding: 0; - - .components-popover__content { - white-space: normal; - width: auto; - max-width: 100%; - margin: 0 auto; - } - - // Force Tooltip from @wordpress/components to show on hover only, not on focus - .components-popover { - visibility: hidden; - } - - &:hover .components-popover { - visibility: visible; - } -} - diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.tsx deleted file mode 100644 index 0fb23f2022bb7..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-list-renderer.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { PatternRenderer } from '@automattic/block-renderer'; -import { Tooltip, __unstableCompositeItem as CompositeItem } from '@wordpress/components'; -import clsx from 'clsx'; -import { useEffect, useCallback, useRef } from 'react'; -import { useInView } from 'react-intersection-observer'; -import { DEFAULT_VIEWPORT_WIDTH, DEFAULT_VIEWPORT_HEIGHT, PLACEHOLDER_HEIGHT } from './constants'; -import { encodePatternId, isPriorityPattern } from './utils'; -import type { Pattern } from './types'; -import './pattern-list-renderer.scss'; - -interface PatternListItemProps { - pattern: Pattern; - className: string; - isFirst: boolean; - isShown: boolean; - isSelected?: boolean; - composite?: Record< string, unknown >; - transformPatternHtml?: ( patternHtml: string ) => string; - onSelect: ( selectedPattern: Pattern | null ) => void; -} - -interface PatternListRendererProps { - patterns: Pattern[]; - shownPatterns: Pattern[]; - selectedPattern: Pattern | null; - selectedPatterns?: Pattern[]; - activeClassName: string; - composite?: Record< string, unknown >; - transformPatternHtml?: ( patternHtml: string ) => string; - onSelect: ( selectedPattern: Pattern | null ) => void; - isShowMorePatterns?: boolean; -} - -const PatternListItem = ( { - pattern, - className, - isFirst, - isShown, - isSelected, - composite, - transformPatternHtml, - onSelect, -}: PatternListItemProps ) => { - const ref = useRef< HTMLButtonElement >(); - const { ref: inViewRef } = useInView( { - triggerOnce: true, - } ); - - const setRefs = useCallback( - ( node?: Element | null | undefined ) => { - if ( node ) { - ref.current = node as HTMLButtonElement; - inViewRef( node ); - } - }, - [ inViewRef ] - ); - - useEffect( () => { - if ( isShown && isFirst && ref.current ) { - ref.current.focus(); - } - }, [ isShown, isFirst, ref ] ); - - return ( - - onSelect( pattern ) } - > - { isShown ? ( - - ) : ( -
    - ) } - - - ); -}; - -const PatternListRenderer = ( { - patterns, - shownPatterns, - selectedPattern, - selectedPatterns, - activeClassName, - composite, - transformPatternHtml, - onSelect, - isShowMorePatterns, -}: PatternListRendererProps ) => { - const filterPriorityPatterns = ( pattern: Pattern ) => - isShowMorePatterns || isPriorityPattern( pattern ); - - return ( - <> - { patterns?.filter( filterPriorityPatterns ).map( ( pattern, index ) => ( - ID === pattern.ID ), - } ) } - isFirst={ index === 0 } - isShown={ shownPatterns.includes( pattern ) } - isSelected={ pattern.ID === selectedPattern?.ID } - composite={ composite } - transformPatternHtml={ transformPatternHtml } - onSelect={ onSelect } - /> - ) ) } - - ); -}; - -export default PatternListRenderer; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-selector.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-selector.tsx deleted file mode 100644 index 5e1042522047d..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-selector.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { - __unstableComposite as Composite, - __unstableUseCompositeState as useCompositeState, -} from '@wordpress/components'; -import { useAsyncList } from '@wordpress/compose'; -import { useTranslate } from 'i18n-calypso'; -import PatternListRenderer from './pattern-list-renderer'; -import type { Pattern } from './types'; - -type PatternSelectorProps = { - patterns: Pattern[]; - onSelect: ( selectedPattern: Pattern | null ) => void; - selectedPattern: Pattern | null; - selectedPatterns?: Pattern[]; - transformPatternHtml?: ( patternHtml: string ) => string; - isShowMorePatterns?: boolean; -}; - -const PatternSelector = ( { - patterns = [], - onSelect, - selectedPattern, - selectedPatterns, - transformPatternHtml, - isShowMorePatterns, -}: PatternSelectorProps ) => { - const translate = useTranslate(); - const shownPatterns = useAsyncList( patterns ); - const composite = useCompositeState( { orientation: 'vertical' } ); - - return ( -
    -
    - - - -
    -
    - ); -}; - -export default PatternSelector; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.scss deleted file mode 100644 index e729898d290b0..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.scss +++ /dev/null @@ -1,25 +0,0 @@ -@import "@automattic/typography/styles/variables"; - -.pattern-assembler__tooltip-dead-click { - pointer-events: none; - position: fixed !important; - - &-content { - background: var(--studio-gray-100); - border-radius: 4px; - box-sizing: border-box; - box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.1); - color: #fff; - font-size: $font-body-extra-small; - left: 16px; - opacity: 0; - padding: 8px 10px; - position: relative; - top: 16px; - white-space: nowrap; - - &--visible { - opacity: 1; - } - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.tsx deleted file mode 100644 index c6bedd12bf889..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/pattern-tooltip-dead-click.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { Popover } from '@wordpress/components'; -import clsx from 'clsx'; -import { useTranslate } from 'i18n-calypso'; -import { useEffect, useMemo, useRef } from 'react'; -import './pattern-tooltip-dead-click.scss'; - -interface Props { - targetRef: React.MutableRefObject< HTMLDivElement | null >; - isVisible: boolean; -} - -const PatternTooltipDeadClick = ( { targetRef, isVisible }: Props ) => { - const translate = useTranslate(); - const ref = useRef< HTMLDivElement | null >( null ); - - const anchor = useMemo( () => { - return { - getBoundingClientRect() { - if ( ! ref.current || ! isVisible ) { - return new window.DOMRect(); - } - - const { width, height } = ref.current.getBoundingClientRect(); - return new window.DOMRect( 0, 0, width, height ); - }, - }; - }, [] ); - - useEffect( () => { - const setXY = ( event: MouseEvent ) => { - if ( ! ref.current ) { - return; - } - - const { clientX, clientY } = event; - const { height, width } = ref.current.getBoundingClientRect(); - const x = Math.min( clientX, window.innerWidth - ( width + 32 ) ); - const y = Math.min( clientY, window.innerHeight - ( height + 32 ) ); - - ref.current.style.transform = `translate( ${ x }px, ${ y }px )`; - }; - - const handleMouseDown = ( event: MouseEvent ) => { - setXY( event ); - }; - - const handleMouseMove = ( event: MouseEvent ) => { - if ( isVisible ) { - setXY( event ); - } - }; - - targetRef.current?.addEventListener( 'mousedown', handleMouseDown ); - targetRef.current?.addEventListener( 'mousemove', handleMouseMove ); - return () => { - targetRef.current?.removeEventListener( 'mousedown', handleMouseDown ); - targetRef.current?.removeEventListener( 'mousemove', handleMouseMove ); - }; - }, [ targetRef, ref, isVisible ] ); - - return ( - -
    - { translate( 'You can edit your content later in the Site Editor' ) } -
    -
    - ); -}; - -export default PatternTooltipDeadClick; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-color-palettes.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-color-palettes.tsx deleted file mode 100644 index dedde7fa3a8f7..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-color-palettes.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { ColorPaletteVariations } from '@automattic/global-styles'; -import { useTranslate } from 'i18n-calypso'; -import { useSiteGlobalStylesStatus } from 'calypso/state/sites/hooks/use-site-global-styles-status'; -import Panel from './panel'; -import type { GlobalStylesObject } from '@automattic/global-styles'; - -interface Props { - siteId: number | string; - stylesheet: string; - selectedColorPaletteVariation: GlobalStylesObject | null; - onSelect: ( colorPaletteVariation: GlobalStylesObject | null ) => void; -} - -const ScreenColorPalettes = ( { - siteId, - stylesheet, - selectedColorPaletteVariation, - onSelect, -}: Props ) => { - const { shouldLimitGlobalStyles } = useSiteGlobalStylesStatus( siteId ); - const translate = useTranslate(); - - return ( - - - - ); -}; - -export default ScreenColorPalettes; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.scss deleted file mode 100644 index 490821f952f53..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.scss +++ /dev/null @@ -1,35 +0,0 @@ -@import "@automattic/typography/styles/fonts"; - -.screen-confirmation__list { - display: flex; - flex-direction: column; - gap: 18px; -} - -.screen-confirmation__list-item-icon { - fill: var(--studio-gray-60); - height: 24px; - min-width: 24px !important; - border-radius: 2px; - background: var(--studio-gray-0); - display: flex; - align-items: center; - justify-content: center; -} - -.screen-confirmation__list-item-wrapper { - display: flex; - padding-top: 2px; - flex-direction: column; - flex-grow: 1; - gap: 4px; - font-size: $font-body-small; - line-height: 20px; - letter-spacing: -0.15px; -} - -.screen-confirmation__list-item-description { - color: var(--studio-gray-60); - text-wrap: pretty; -} - diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.tsx deleted file mode 100644 index fa8da2ab0fc9b..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-confirmation.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { Button } from '@automattic/components'; -import { Design } from '@automattic/design-picker'; -import { NavigatorHeader } from '@automattic/onboarding'; -import { - __experimentalVStack as VStack, - __experimentalHStack as HStack, -} from '@wordpress/components'; -import { Icon, image, verse, layout } from '@wordpress/icons'; -import { getLocaleSlug, useTranslate } from 'i18n-calypso'; -import { useSelector } from 'react-redux'; -import { getActiveTheme } from 'calypso/state/themes/selectors'; -import { useScreen } from './hooks'; -import NavigatorTitle from './navigator-title'; -import Survey from './survey'; -import type { IAppState } from 'calypso/state/types'; -import './screen-confirmation.scss'; - -interface Props { - isNewSite: boolean; - siteId?: number; - selectedDesign?: Design; - surveyDismissed: boolean; - setSurveyDismissed: ( dismissed: boolean ) => void; - onConfirm: () => void; -} - -const ScreenConfirmation = ( { - isNewSite, - siteId = 0, - selectedDesign, - surveyDismissed, - setSurveyDismissed, - onConfirm, -}: Props ) => { - const translate = useTranslate(); - const { title, continueLabel } = useScreen( 'confirmation' ); - - const currentThemeId = useSelector( ( state: IAppState ) => getActiveTheme( state, siteId ) ); - const willThemeChange = currentThemeId !== selectedDesign?.slug; - const isEnglishLocale = getLocaleSlug()?.startsWith( 'en' ); - - const description = - currentThemeId && willThemeChange && ! isNewSite - ? translate( - 'Your new theme is %(newThemeName)s. Time to add some content and bring your site to life!', - { - args: { - newThemeName: selectedDesign?.title ?? '', - }, - } - ) - : translate( 'Time to add some content and bring your site to life!' ); - - const list = [ - { - icon: image, - title: translate( 'Upload images' ), - description: translate( 'Showcase your photos in their best light.' ), - }, - { - icon: verse, - title: translate( 'Start writing' ), - description: translate( 'Get things going and share your insights.' ), - }, - { - icon: layout, - title: translate( 'Customize every detail' ), - description: translate( 'Make your site even more unique.' ), - }, - ]; - - return ( - <> - } - description={ description } - hideBack - /> -
    - - { list.map( ( { icon, title, description } ) => ( - -
    - -
    - - { title } -

    { description }

    -
    -
    - ) ) } -
    - { ! surveyDismissed && isEnglishLocale && ( - - ) } -
    -
    - -
    - - ); -}; - -export default ScreenConfirmation; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-font-pairings.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-font-pairings.tsx deleted file mode 100644 index c171472ee5042..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-font-pairings.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { FontPairingVariations } from '@automattic/global-styles'; -import { useTranslate } from 'i18n-calypso'; -import { useSiteGlobalStylesStatus } from 'calypso/state/sites/hooks/use-site-global-styles-status'; -import Panel from './panel'; -import type { GlobalStylesObject } from '@automattic/global-styles'; - -interface Props { - siteId: number | string; - stylesheet: string; - selectedFontPairingVariation: GlobalStylesObject | null; - onSelect: ( fontPairingVariation: GlobalStylesObject | null ) => void; -} - -const ScreenFontPairings = ( { - siteId, - stylesheet, - selectedFontPairingVariation, - onSelect, -}: Props ) => { - const translate = useTranslate(); - const { shouldLimitGlobalStyles } = useSiteGlobalStylesStatus( siteId ); - - return ( - - - - ); -}; - -export default ScreenFontPairings; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-main.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-main.tsx deleted file mode 100644 index f8edd2ad6aab0..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-main.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import { NavigatorHeader, NavigatorItem, NavigatorItemGroup } from '@automattic/onboarding'; -import { - Button, - __experimentalVStack as VStack, - __experimentalUseNavigator as useNavigator, -} from '@wordpress/components'; -import { header, footer } from '@wordpress/icons'; -import { useTranslate } from 'i18n-calypso'; -import { useEffect } from 'react'; -import { INITIAL_CATEGORY, NAVIGATOR_PATHS } from './constants'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import { useScreen, usePatternCountMapByCategory } from './hooks'; -import NavigatorTitle from './navigator-title'; -import PatternCategoryList from './pattern-category-list'; -import PatternCount from './pattern-count'; -import { Category, Pattern, PatternType } from './types'; - -interface Props { - onMainItemSelect: ( name: string ) => void; - onPreselectPattern: ( type: PatternType, selectedPattern: Pattern ) => void; - hasHeader: boolean; - hasFooter: boolean; - sections: Pattern[]; - categories: Category[]; - patternsMapByCategory: Record< string, Pattern[] >; - onContinueClick: () => void; - recordTracksEvent: ( name: string, eventProperties?: any ) => void; -} - -const ScreenMain = ( { - onMainItemSelect, - onPreselectPattern, - hasHeader, - hasFooter, - sections, - categories, - patternsMapByCategory, - onContinueClick, - recordTracksEvent, -}: Props ) => { - const translate = useTranslate(); - const { title, description, continueLabel } = useScreen( 'main' ); - const { location, params, goTo } = useNavigator(); - const patternCountMapByCategory = usePatternCountMapByCategory( sections ); - const selectedCategory = params.categorySlug as string; - const totalPatternCount = Number( hasHeader ) + sections.length + Number( hasFooter ); - const isButtonDisabled = totalPatternCount === 0; - - const handlePreselectCategory = ( category: string ) => { - goTo( `${ NAVIGATOR_PATHS.MAIN }/${ category }`, { replace: true } ); - }; - - const handleSelectCategory = ( category: string, type: PatternType = 'section' ) => { - const basePath = NAVIGATOR_PATHS.MAIN; - const isBack = category === selectedCategory; - const nextPath = ! isBack ? `${ basePath }/${ category }` : basePath; - goTo( nextPath, { replace: true } ); - - if ( ! isBack ) { - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.CATEGORY_LIST_CATEGORY_CLICK, { - pattern_category: category, - } ); - - if ( type !== 'section' ) { - onMainItemSelect( type ); - } - } - }; - - // On the first Assembler flow load, instead of starting with a blank page, - // we insert a default header pattern and footer pattern, and then pre-select the first pattern category. - // - // This is done by doing all the above in a React effect when there is no selected pattern category, - // which happens on the first load of the Assembler flow. - useEffect( () => { - if ( ! selectedCategory ) { - if ( ! hasHeader && patternsMapByCategory.header?.length > 0 ) { - onPreselectPattern( 'header', patternsMapByCategory.header[ 0 ] ); - } - if ( ! hasFooter && patternsMapByCategory.footer?.length > 0 ) { - onPreselectPattern( 'footer', patternsMapByCategory.footer[ 0 ] ); - } - if ( hasHeader && hasFooter ) { - handlePreselectCategory( INITIAL_CATEGORY ); - } - } - }, [ - hasHeader, - hasFooter, - patternsMapByCategory.header?.length, - patternsMapByCategory.footer?.length, - ] ); - - return ( - <> - } - description={ description } - hideBack - /> -
    - - - handleSelectCategory( 'header', 'header' ) } - active={ location.path === NAVIGATOR_PATHS.MAIN_HEADER } - > - <> - { translate( 'Header' ) } - - - - - - - - - handleSelectCategory( 'footer', 'footer' ) } - active={ location.path === NAVIGATOR_PATHS.MAIN_FOOTER } - > - <> - { translate( 'Footer' ) } - - - - - -
    -
    - - { totalPatternCount > 0 && - translate( - 'You’ve selected {{strong}}%(count)s{{/strong}} pattern.', - 'You’ve selected {{strong}}%(count)s{{/strong}} patterns.', - { - count: totalPatternCount, - args: { - count: totalPatternCount, - }, - components: { - strong: , - }, - } - ) } - -
    - - ); -}; - -export default ScreenMain; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pages.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pages.tsx deleted file mode 100644 index 6f0ee9a0c5fdc..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pages.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { NavigatorHeader } from '@automattic/onboarding'; -import { Button, __experimentalVStack as VStack } from '@wordpress/components'; -import { useEffect, useState } from 'react'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import { useScreen } from './hooks'; -import NavigatorTitle from './navigator-title'; -import PageList from './pages/page-list'; - -interface Props { - pagesToShow: any[]; - onSelect: ( page: string ) => void; - onContinueClick: () => void; - recordTracksEvent: ( name: string, eventProperties?: any ) => void; -} - -const ScreenPages = ( { pagesToShow, onSelect, onContinueClick, recordTracksEvent }: Props ) => { - const [ disabled, setDisabled ] = useState( true ); - const { title, description, continueLabel } = useScreen( 'pages' ); - - const handleContinueClick = () => { - if ( ! disabled ) { - onContinueClick(); - } - }; - - // Use the mousedown event to prevent either the button focusing or text selection - const handleMouseDown = ( event: React.MouseEvent ) => { - if ( disabled ) { - event.preventDefault(); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.CONTINUE_MISCLICK ); - } - }; - - // Set a delay to enable the Continue button since the user might mis-click easily when they go back from another screen - useEffect( () => { - const timeoutId = window.setTimeout( () => setDisabled( false ), 300 ); - return () => { - window.clearTimeout( timeoutId ); - }; - }, [] ); - - return ( - <> - } - description={ description } - hideBack - /> -
    - - - -
    -
    - -
    - - ); -}; - -export default ScreenPages; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pattern-list-panel.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pattern-list-panel.tsx deleted file mode 100644 index 8c72f52393749..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-pattern-list-panel.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { useHasEnTranslation } from '@automattic/i18n-utils'; -import { __experimentalUseNavigator as useNavigator } from '@wordpress/components'; -import { useTranslate } from 'i18n-calypso'; -import PatternListPanel from './pattern-list-panel'; -import type { Pattern, PatternType, Category, PanelObject } from './types'; - -interface Props { - categories: Category[]; - selectedHeader: Pattern | null; - selectedFooter: Pattern | null; - selectedSections: Pattern[]; - patternsMapByCategory: { [ key: string ]: Pattern[] }; - pages?: Pattern[]; - onSelect: ( - type: PatternType, - selectedPattern: Pattern | null, - selectedCategory: string | null - ) => void; - recordTracksEvent: ( name: string, eventProperties?: any ) => void; - isNewSite: boolean; -} - -const ScreenPatternListPanel = ( { - selectedHeader, - selectedFooter, - selectedSections, - onSelect, - ...props -}: Props ) => { - const hasEnTranslation = useHasEnTranslation(); - const translate = useTranslate(); - const navigator = useNavigator(); - const selectedCategory = navigator.params.categorySlug as string; - const panels: Record< string, PanelObject > = { - header: { - type: 'header', - label: translate( 'Header' ), - description: hasEnTranslation( - 'The header pattern sits at the top of your site and typically shows your site logo, title, and navigation.' - ) - ? translate( - 'The header pattern sits at the top of your site and typically shows your site logo, title, and navigation.' - ) - : translate( - 'Pick the header that appears at the top of every page and shows your site logo, title and navigation.' - ), - category: 'header', - selectedPattern: selectedHeader, - }, - footer: { - type: 'footer', - label: translate( 'Footer' ), - description: hasEnTranslation( - 'The footer pattern sits at the bottom of your site and typically shows useful links and contact information.' - ) - ? translate( - 'The footer pattern sits at the bottom of your site and typically shows useful links and contact information.' - ) - : translate( - 'Pick the footer that appears at the bottom of every page and shows useful links and contact information.' - ), - category: 'footer', - selectedPattern: selectedFooter, - }, - default: { - type: 'section', - selectedPattern: null, - selectedPatterns: selectedSections, - }, - }; - - const currentPanel = panels[ selectedCategory ] || panels.default; - - const handleSelect = ( selectedPattern: Pattern | null ) => { - onSelect( currentPanel.type, selectedPattern, selectedCategory ); - }; - - return ( - - ); -}; - -export default ScreenPatternListPanel; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-styles.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-styles.tsx deleted file mode 100644 index a2ea1fa5b875b..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-styles.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { NavigatorItem, NavigatorHeader, NavigatorItemGroup } from '@automattic/onboarding'; -import { - Button, - __experimentalVStack as VStack, - __experimentalUseNavigator as useNavigator, -} from '@wordpress/components'; -import { color, typography } from '@wordpress/icons'; -import { useTranslate } from 'i18n-calypso'; -import { useEffect, useState } from 'react'; -import { NAVIGATOR_PATHS } from './constants'; -import { PATTERN_ASSEMBLER_EVENTS } from './events'; -import { useScreen } from './hooks'; -import NavigatorTitle from './navigator-title'; - -interface Props { - onMainItemSelect: ( name: string ) => void; - onContinueClick: () => void; - recordTracksEvent: ( name: string, eventProperties?: any ) => void; - hasColor: boolean; - hasFont: boolean; -} - -const ScreenStyles = ( { - onMainItemSelect, - onContinueClick, - recordTracksEvent, - hasColor, - hasFont, -}: Props ) => { - const translate = useTranslate(); - const [ disabled, setDisabled ] = useState( true ); - const { location, goTo } = useNavigator(); - const { title, description, continueLabel } = useScreen( 'styles' ); - - const handleNavigatorItemSelect = ( type: string, path: string ) => { - const nextPath = path !== location.path ? path : NAVIGATOR_PATHS.STYLES; - goTo( nextPath, { replace: true } ); - onMainItemSelect( type ); - }; - - const handleContinueClick = () => { - if ( ! disabled ) { - onContinueClick(); - } - }; - - // Use the mousedown event to prevent either the button focusing or text selection - const handleMouseDown = ( event: React.MouseEvent ) => { - if ( disabled ) { - event.preventDefault(); - recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.CONTINUE_MISCLICK ); - } - }; - - // Set a delay to enable the Continue button since the user might mis-click easily when they go back from another screen - useEffect( () => { - const timeoutId = window.setTimeout( () => setDisabled( false ), 300 ); - return () => { - window.clearTimeout( timeoutId ); - }; - }, [] ); - - return ( - <> - } - description={ description } - hideBack - /> -
    - - - <> - - handleNavigatorItemSelect( 'color-palettes', NAVIGATOR_PATHS.STYLES_COLORS ) - } - > - { translate( 'Colors' ) } - - - handleNavigatorItemSelect( 'font-pairings', NAVIGATOR_PATHS.STYLES_FONTS ) - } - > - { translate( 'Fonts' ) } - - - - -
    -
    - -
    - - ); -}; - -export default ScreenStyles; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.scss deleted file mode 100644 index 042c2f91facc8..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.scss +++ /dev/null @@ -1,74 +0,0 @@ -@import "@automattic/typography/styles/fonts"; - -.screen-upsell { - .screen-upsell__plan { - margin: 10px 0 16px; - - .screen-upsell__plan-heading { - margin-bottom: 8px; - font-size: $font-title-small; - font-weight: 500; - line-height: 26px; - color: var(--studio-gray-100, #101517); - } - - .screen-upsell__plan-price { - display: flex; - - .plan-price__integer { - font-size: $font-title-large; - font-weight: 500; - color: var(--studio-gray-100, #101517); - } - - .plan-price__currency-symbol { - margin-top: 2px; - font-size: $font-body; - font-weight: 500; - color: var(--studio-gray-100, #101517); - } - } - - .screen-upsell__plan-billing-time-frame { - font-size: $font-body-extra-small; - color: var(--studio-gray-70, #3c434a); - } - } - - .screen-upsell__features-heading { - margin-bottom: 8px; - font-size: $font-body-small; - font-weight: 500; - line-height: 20px; - } - - ul.screen-upsell__features { - margin: 0 0 40px; - font-size: $font-body-small; - list-style: none; - - li { - display: flex; - align-items: center; - margin-top: 8px; - gap: 16px; - - /** Highlight the “Free domain for one year” feature */ - &:first-child strong { - font-weight: 600; - } - } - - strong { - font-weight: normal; - } - - svg { - color: var(--studio-blue-50); - } - } - - .pattern-assembler__button + .pattern-assembler__button { - margin-top: 8px; - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.tsx deleted file mode 100644 index ae676552312bb..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/screen-upsell.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { PLAN_PREMIUM } from '@automattic/calypso-products'; -import { Button, Gridicon, LoadingPlaceholder, PlanPrice } from '@automattic/components'; -import { Plans } from '@automattic/data-stores'; -import { formatCurrency } from '@automattic/format-currency'; -import { NavigatorHeader } from '@automattic/onboarding'; -import { useTranslate } from 'i18n-calypso'; -import { useSelector } from 'react-redux'; -import useGlobalStylesUpgradeTranslations from 'calypso/components/premium-global-styles-upgrade-modal/use-global-styles-upgrade-translations'; -import useCheckPlanAvailabilityForPurchase from 'calypso/my-sites/plans-features-main/hooks/use-check-plan-availability-for-purchase'; -import { getSelectedSiteId } from 'calypso/state/ui/selectors'; -import { useScreen } from './hooks'; -import NavigatorTitle from './navigator-title'; -import './screen-upsell.scss'; - -interface Props { - numOfSelectedGlobalStyles?: number; - onCheckout: () => void; - onTryStyle: () => void; -} - -const ScreenUpsell = ( { numOfSelectedGlobalStyles = 1, onCheckout, onTryStyle }: Props ) => { - const translate = useTranslate(); - const { title, description } = useScreen( 'upsell' ); - const translations = useGlobalStylesUpgradeTranslations( { numOfSelectedGlobalStyles } ); - const selectedSiteId = useSelector( getSelectedSiteId ) ?? undefined; - const pricingMeta = Plans.usePricingMetaForGridPlans( { - planSlugs: [ PLAN_PREMIUM ], - siteId: selectedSiteId, - coupon: undefined, - useCheckPlanAvailabilityForPurchase, - storageAddOns: null, - } ); - const pricing = pricingMeta?.[ PLAN_PREMIUM ]; - const isPricingLoaded = - pricing?.currencyCode && pricing?.originalPrice.monthly && pricing?.originalPrice.full; - - return ( - <> - } - description={ description } - hideBack - /> -
    -
    -
    - { translate( '%(planTitle)s plan', { - args: { planTitle: translations.planTitle }, - } ) } -
    - { isPricingLoaded ? ( - - ) : ( - - ) } -
    - { translate( 'per month, {{span}}%(rawPrice)s{{/span}} billed annually, excl. taxes', { - args: { - rawPrice: isPricingLoaded - ? formatCurrency( pricing?.originalPrice.full ?? 0, pricing?.currencyCode ?? '', { - stripZeros: true, - isSmallestUnit: true, - } ) - : '', - }, - comment: 'excl. taxes is short for excluding taxes', - components: { - span: isPricingLoaded ? ( - - ) : ( - - ), - }, - } ) } -
    -
    - - { translate( 'Included with the plan:' ) } - -
      - { translations.features.map( ( feature, i ) => ( -
    • - - { feature } -
    • - ) ) } -
    -
    -
    - - -
    - - ); -}; - -export default ScreenUpsell; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/style.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/style.scss deleted file mode 100644 index 95426a0e1c7d9..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/style.scss +++ /dev/null @@ -1,263 +0,0 @@ -@import "@wordpress/base-styles/breakpoints"; -@import "@wordpress/base-styles/mixins"; -@import "@automattic/typography/styles/variables"; -@import "./keyframes"; -@import "./variables"; - -@font-face { - font-family: Inter; - font-weight: 500; - font-display: swap; - src: url(https://s0.wp.com/i/fonts/inter/Inter-Medium.woff2?v=3.19) format("woff2"); -} - -$font-family: "SF Pro Text", $sans; - -.pattern-assembler { - display: flex; - height: calc(100vh - 60px); - width: 100%; - - .navigator-header { - // Force display because by default it shows only for min-width break-xlarge - display: block; - } - - .pattern-assembler__button { - width: 100%; - height: 40px; - border-radius: 4px; - - &.components-button.is-primary[aria-disabled="true"] { - &, - &:hover, - &:active { - background-color: var(--studio-gray-5); - border-color: var(--studio-gray-5); - color: var(--studio-white); - } - } - } - - .step-container__content { - display: flex; - width: 100%; - } - - .pattern-assembler__wrapper { - display: flex; - flex-direction: row; - flex: 1; - } - - .pattern-assembler__sidebar { - display: flex; - flex-direction: column; - width: $pattern-assembler-sidebar-width; - height: 100vh; - box-sizing: border-box; - padding: 110px 32px 32px; - background-color: var(--color-body-background); - position: relative; - z-index: 2; - overflow-x: visible; - - @include break-wide { - width: $pattern-assembler-sidebar-width-wide; - } - } - - .pattern-assembler__sidebar-panel { - margin-inline-end: 22px; - - // Disable the animation of the transform on the panel - .components-navigator-screen { - transform: none !important; - } - - &:empty { - display: none; - } - } - - /** - * Pattern Selector - */ - .pattern-selector { - display: flex; - flex-direction: column; - height: 100%; - width: 100%; - - .pattern-selector__header { - display: flex; - margin-bottom: 32px; - - .button { - padding: 0; - width: 25px; - margin-right: 10px; - - &:hover svg { - fill: var(--color-neutral-70); - } - } - - svg { - width: 16px; - height: 16px; - top: 4px; - margin-right: 12px; - margin-left: 4px; - fill: var(--studio-gray-100); - } - - h1 { - font-family: $font-family; - font-size: $font-title-small; - font-weight: 500; - line-height: 26px; - } - } - - .pattern-selector__body { - position: relative; - margin-bottom: 32px; - padding: 2px 2px 32px; - // Rest pattern border to expand sides out of wrapper - margin-right: -2px; - margin-left: -2px; - - &:last-child { - margin-bottom: 0; - padding-bottom: 0; - } - } - - .pattern-selector__block-list { - button { - box-shadow: 0 15px 25px rgba(0, 0, 0, 0.07); - display: block; - border: 1px solid rgba(0, 0, 0, 5%); - border-radius: 4px; - width: 100%; - overflow: hidden; - user-select: none; - cursor: pointer; - background: #fff; - - &:not(:last-child) { - margin-bottom: 16px; - } - - &.pattern-selector__block-list--selected-pattern { - box-shadow: - 0 15px 25px rgba(0, 0, 0, 0.07), - 0 0 0 2px var(--studio-gray); - } - - &:focus, - &:hover { - box-shadow: 0 0 0 2px var(--color-primary-light); - outline: 0; - } - } - } - } - - /** - * Screen Container - */ - .screen-container { - display: flex; - flex-direction: column; - height: 100%; - } - - .screen-container__body { - display: flex; - flex-direction: column; - padding: 2px 16px; - // Use negative margin to avoid the content and scrollbar overlapping - margin: 0 -16px 32px; - margin-bottom: 32px; - overflow-y: auto; - - &.screen-category-list__body { - // Reduces .navigator-header margin - margin-top: -10px; - } - } - - .screen-container__footer { - margin-top: auto; - - .screen-container__footer-description { - display: inline-block; - margin-bottom: 8px; - font-size: $font-body-small; - color: var(--studio-gray-80); - } - } - - .screen-container__description { - display: inline-block; - padding-bottom: 8px; - font-size: $font-body-small; - letter-spacing: -0.15px; - color: var(--color-neutral-60); - } - - .screen-container__notice { - padding: 11px 14px; - margin: 0; - border: none; - background-color: var(--studio-blue-0); - - .components-notice__dismiss { - align-self: center; - min-width: 24px; - height: 24px; - padding: 0; - - svg { - width: 20px; - height: 20px; - } - } - } - - /** - * The header of the stepper framework - */ - .signup-header { - z-index: 10; // Increase the z-index to avoid the WordPress Logo being covered by the sidebar - } - - /** - * Gutenberg Components - */ - .components-divider { - border-color: rgba(0, 0, 0, 0.1); - } - - .components-navigator-provider { - flex-grow: 1; - height: 100vh; - margin-top: -60px; - } - - .components-navigator-screen { - display: flex; - flex-direction: column; - flex-grow: 1; - overflow-x: visible; - } - - /** - * Calypso Components - */ - .components-button:focus:not(:disabled) { - box-shadow: 0 0 0 2px var(--color-primary-light); - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/index.tsx deleted file mode 100644 index b6294ece285c8..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import Banner from 'calypso/components/banner'; -import './survey.scss'; - -interface Props { - eventName?: string; - eventUrl?: string; - title?: string | React.ReactNode; - setSurveyDismissed: ( dismissed: boolean ) => void; -} - -const Survey = ( { eventName, eventUrl, title, setSurveyDismissed }: Props ) => { - if ( ! eventUrl ) { - return null; - } - - return ( - - We’d love to hear your thoughts. Fill out this{ ' ' } - - quick survey - { ' ' } - on your onboarding experience. - - ) - } - event={ eventName } - onDismiss={ ( e: Event ) => { - e.stopPropagation(); - setSurveyDismissed( true ); - } } - dismissTemporary - disableHref - showIcon={ false } - showLinkIcon={ false } - dismissWithoutSavingPreference - tracksImpressionName="calypso_onboarding_survey_impression" - tracksClickName="calypso_onboarding_survey_click" - tracksDismissName="calypso_onboarding_survey_dismiss" - /> - ); -}; - -export default Survey; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/survey.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/survey.scss deleted file mode 100644 index 922191e6c777a..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/survey/survey.scss +++ /dev/null @@ -1,40 +0,0 @@ -.pattern-assembler__survey { - border-radius: 4px; - background: #f0f7fc; - margin: 40px 0; - text-wrap: pretty; - - .banner__info .banner__title { - font-weight: 400; - line-height: 20px; - color: var(--studio-gray-70); - font-size: $font-body-extra-small; - font-family: "SF Pro Text", $sans; - - a, - a:visited { - font-weight: 600; - color: var(--studio-gray-90); - text-decoration: underline; - } - } - - .banner__close-icon { - fill: var(--studio-gray-60); - top: auto; - right: 14px; - height: 15.4px; - width: 15.4px; - } - - &.banner.card.is-dismissible { - cursor: default; - border: 0; - box-shadow: none; - - // Overwrite .banner.card - @media (min-width: 481px) { - padding: 14px 42px 14px 16px; - } - } -} diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/types.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/types.ts deleted file mode 100644 index 6fcc1744cac68..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/types.ts +++ /dev/null @@ -1,50 +0,0 @@ -export type Pattern = { - ID: number; - name: string; - title: string; - description?: string; - category?: Category; - categories: Record< string, Category | undefined >; - key?: string; - pattern_meta?: Record< string, boolean | undefined >; - html?: string; - tags: Record< string, Tag | undefined >; -}; - -export type PatternType = 'header' | 'footer' | 'section'; - -export interface NavigatorLocation { - path: string; - isInitial: boolean; -} - -export type Category = { - name?: string; - title?: string; - slug?: string; - label?: string; - description?: string; -}; - -export type PanelObject = { - type: PatternType; - label?: string; - description?: string; - category?: string; - selectedPattern: Pattern | null; - selectedPatterns?: Pattern[]; -}; - -export type ScreenName = 'main' | 'styles' | 'confirmation' | 'upsell' | 'pages'; - -export type Tag = { - slug: string; - title: string; - description: string; -}; - -export type CustomPageTitle = { - title: string; - ID: number; - selected: boolean; -}; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/utils.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/utils.ts deleted file mode 100644 index f4480b281537c..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/utils.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { isEnabled } from '@automattic/calypso-config'; -import { translate } from 'i18n-calypso'; -import { getPatternSourceSiteID } from './constants'; -import type { Pattern, Category } from './types'; - -export const encodePatternId = ( patternId: number ) => - `${ patternId }-${ getPatternSourceSiteID() }`; - -export const decodePatternId = ( encodedPatternId: number | string ) => - `${ encodedPatternId }`.split( '-' )[ 0 ]; - -export const getShuffledPattern = ( candidates: Pattern[], current: Pattern ) => { - const filteredCandidates = candidates.filter( ( { ID } ) => ID !== current.ID ); - const shuffledIndex = Math.floor( Math.random() * filteredCandidates.length ); - return filteredCandidates[ shuffledIndex ]; -}; - -export const injectCategoryToPattern = ( - pattern: Pattern, - categories: Category[], - selectedCategory?: string | null -) => { - // Inject the selected pattern category or the first category - // to be used in tracks and as selected pattern name. - const [ firstCategory ] = Object.keys( pattern.categories ); - pattern.category = categories.find( ( { name } ) => { - return name === ( selectedCategory || firstCategory ); - } ); - - return pattern; -}; - -export const isPriorityPattern = ( { categories, tags: { assembler_priority } }: Pattern ) => - isEnabled( 'pattern-assembler/v2' ) - ? categories.featured || categories.footer || categories.header - : Boolean( assembler_priority ); - -export const isPagePattern = ( { categories, tags: { assembler_page } }: Pattern ) => - Boolean( isEnabled( 'pattern-assembler/v2' ) ? categories.page : assembler_page ); - -export const getTitleForRenamedCategories = ( category: Category = {} ) => { - const { slug, title } = category; - if ( 'posts' === slug ) { - return translate( 'Blog' ); - } - return title; -}; - -export const getPagePatternTitle = ( { categories }: Pattern ) => { - const category = ( Object.values( categories ) as Category[] ).find( - ( { slug } ) => 'page' !== slug && 'featured' !== slug - ); - return getTitleForRenamedCategories( category ); -}; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/variables.scss b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/variables.scss deleted file mode 100644 index 7a2ad847809e6..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/variables.scss +++ /dev/null @@ -1,2 +0,0 @@ -$pattern-assembler-sidebar-width: 300px; -$pattern-assembler-sidebar-width-wide: 348px; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx deleted file mode 100644 index 8c1d0681a6c07..0000000000000 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { GlobalStylesProvider } from '@automattic/global-styles'; -import { createHigherOrderComponent } from '@wordpress/compose'; -import { useSelect } from '@wordpress/data'; -import { useSiteIdParam } from '../../../../hooks/use-site-id-param'; -import { useSiteSlugParam } from '../../../../hooks/use-site-slug-param'; -import { ONBOARD_STORE } from '../../../../stores'; -import StepperLoader from '../../components/stepper-loader'; -import type { OnboardSelect } from '@automattic/data-stores'; - -const withGlobalStylesProvider = createHigherOrderComponent( - < OuterProps extends object >( InnerComponent: React.ComponentType< OuterProps > ) => { - return ( props: OuterProps ) => { - const selectedDesign = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), - [] - ); - const siteSlug = useSiteSlugParam(); - const siteId = useSiteIdParam(); - const siteSlugOrId = siteSlug ? siteSlug : siteId; - const stylesheet = selectedDesign?.recipe?.stylesheet; - - if ( ! siteSlugOrId || ! stylesheet ) { - return ; - } - - // TODO: We might need to lazy load the GlobalStylesProvider - return ( - } - > - - - ); - }; - }, - 'withGlobalStylesProvider' -); - -export default withGlobalStylesProvider; diff --git a/client/landing/stepper/declarative-flow/internals/steps.tsx b/client/landing/stepper/declarative-flow/internals/steps.tsx index 7a88772d87d1c..b8b21a095ea84 100644 --- a/client/landing/stepper/declarative-flow/internals/steps.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps.tsx @@ -145,11 +145,6 @@ export const STEPS = { asyncComponent: () => import( './steps-repository/site-options' ), }, - PATTERN_ASSEMBLER: { - slug: 'pattern-assembler', - asyncComponent: () => import( './steps-repository/pattern-assembler' ), - }, - PLANS: { slug: 'plans', asyncComponent: () => import( './steps-repository/plans' ) }, PROCESSING: { @@ -172,11 +167,6 @@ export const STEPS = { asyncComponent: () => import( './steps-repository/site-picker-list' ), }, - SITE_PROMPT: { - slug: 'site-prompt', - asyncComponent: () => import( './steps-repository/ai-site-prompt' ), - }, - STORE_ADDRESS: { slug: 'storeAddress', asyncComponent: () => import( './steps-repository/store-address' ), diff --git a/client/landing/stepper/declarative-flow/site-setup-flow.ts b/client/landing/stepper/declarative-flow/site-setup-flow.ts index f7043515c0690..3b9f7e5d46002 100644 --- a/client/landing/stepper/declarative-flow/site-setup-flow.ts +++ b/client/landing/stepper/declarative-flow/site-setup-flow.ts @@ -1,8 +1,6 @@ import { Onboard } from '@automattic/data-stores'; -import { Design, isAssemblerDesign, isAssemblerSupported } from '@automattic/design-picker'; import { MIGRATION_FLOW } from '@automattic/onboarding'; import { useSelect, useDispatch } from '@wordpress/data'; -import { useEffect } from 'react'; import wpcomRequest from 'wpcom-proxy-request'; import { isTargetSitePlanCompatible } from 'calypso/blocks/importer/util'; import { useIsBigSkyEligible } from 'calypso/landing/stepper/hooks/use-is-site-big-sky-eligible'; @@ -18,7 +16,7 @@ import { useIsGoalsHoldout } from '../hooks/use-is-goals-holdout'; import { useIsPluginBundleEligible } from '../hooks/use-is-plugin-bundle-eligible'; import { useSiteData } from '../hooks/use-site-data'; import { useCanUserManageOptions } from '../hooks/use-user-can-manage-options'; -import { ONBOARD_STORE, SITE_STORE, USER_STORE, STEPPER_INTERNAL_STORE } from '../stores'; +import { ONBOARD_STORE, SITE_STORE, USER_STORE } from '../stores'; import { shouldRedirectToSiteMigration } from './helpers'; import { useLaunchpadDecider } from './internals/hooks/use-launchpad-decider'; import { STEPS } from './internals/steps'; @@ -30,12 +28,7 @@ import { Flow, ProvidedDependencies, } from './internals/types'; -import type { - OnboardSelect, - SiteSelect, - UserSelect, - StepperInternalSelect, -} from '@automattic/data-stores'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; const SiteIntent = Onboard.SiteIntent; @@ -51,20 +44,6 @@ const siteSetupFlow: Flow = { name: 'site-setup', isSignupFlow: false, - useSideEffect( currentStep, navigate ) { - const selectedDesign = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), - [] - ); - - useEffect( () => { - // Require to start the flow from the first step - if ( currentStep === 'pattern-assembler' && ! selectedDesign ) { - navigate( 'goals' ); - } - }, [] ); - }, - useSteps() { const isGoalsAtFrontExperiment = Boolean( useSelector( getInitialQueryArguments )?.[ 'goals-at-front-experiment' ] @@ -110,11 +89,6 @@ const siteSetupFlow: Flow = { useStepNavigation( currentStep, navigate ) { const isGoalsHoldout = useIsGoalsHoldout( currentStep ); - const stepData = useSelect( - ( select ) => ( select( STEPPER_INTERNAL_STORE ) as StepperInternalSelect ).getStepData(), - [] - ); - const intent = useSelect( ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), [] @@ -288,15 +262,8 @@ const siteSetupFlow: Flow = { } case 'designSetup': { - const { selectedDesign: _selectedDesign } = providedDependencies; - if ( isAssemblerDesign( _selectedDesign as Design ) && isAssemblerSupported() ) { - return navigate( 'pattern-assembler' ); - } - return navigate( 'processing' ); } - case 'pattern-assembler': - return navigate( 'processing' ); case 'processing': { const processingResult = params[ 0 ] as ProcessingResult; @@ -561,14 +528,6 @@ const siteSetupFlow: Flow = { return navigate( 'goals' ); } - case 'pattern-assembler': { - if ( stepData?.previousStep ) { - return navigate( stepData?.previousStep ); - } - - return navigate( 'designSetup' ); - } - case 'importList': if ( backToStep ) { return navigate( `${ backToStep }?siteSlug=${ siteSlug }` ); diff --git a/client/landing/stepper/declarative-flow/update-design.ts b/client/landing/stepper/declarative-flow/update-design.ts index 89bf009d2187b..c99454c1d908c 100644 --- a/client/landing/stepper/declarative-flow/update-design.ts +++ b/client/landing/stepper/declarative-flow/update-design.ts @@ -1,6 +1,5 @@ import { Onboard, useLaunchpad } from '@automattic/data-stores'; -import { isAssemblerDesign } from '@automattic/design-picker'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useDispatch } from '@wordpress/data'; import { useEffect } from '@wordpress/element'; import { translate } from 'i18n-calypso'; import { useLaunchpadDecider } from 'calypso/landing/stepper/declarative-flow/internals/hooks/use-launchpad-decider'; @@ -17,7 +16,6 @@ import { STEPS } from './internals/steps'; import { ProcessingResult } from './internals/steps-repository/processing-step/constants'; import { ProvidedDependencies } from './internals/types'; import type { Flow } from './internals/types'; -import type { OnboardSelect } from '@automattic/data-stores'; const updateDesign: Flow = { name: 'update-design', @@ -40,10 +38,6 @@ const updateDesign: Flow = { const siteSlug = useSiteSlug(); const flowToReturnTo = useQuery().get( 'flowToReturnTo' ) || 'free'; const { setPendingAction } = useDispatch( ONBOARD_STORE ); - const selectedDesign = useSelect( - ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), - [] - ); const { data: { launchpad_screen: launchpadScreenOption } = {} } = useLaunchpad( siteSlug ); const exitFlow = ( to: string ) => { @@ -73,15 +67,6 @@ const updateDesign: Flow = { return navigate( 'error' ); } - if ( isAssemblerDesign( selectedDesign ) ) { - const params = new URLSearchParams( { - canvas: 'edit', - assembler: '1', - } ); - - return exitFlow( `/site-editor/${ siteSlug }?${ params }` ); - } - if ( launchpadScreenOption === 'skipped' ) { return window.location.assign( `/home/${ siteSlug }` ); } @@ -111,26 +96,11 @@ const updateDesign: Flow = { ); } - if ( providedDependencies?.shouldGoToAssembler ) { - return navigate( 'pattern-assembler' ); - } - return navigate( `processing?siteSlug=${ siteSlug }&flowToReturnTo=${ flowToReturnTo }` ); - - case 'pattern-assembler': { - return navigate( `processing?siteSlug=${ siteSlug }&flowToReturnTo=${ flowToReturnTo }` ); - } } } - const goBack = () => { - switch ( currentStep ) { - case 'pattern-assembler': - return navigate( 'designSetup' ); - } - }; - - return { submit, goBack }; + return { submit }; }, }; diff --git a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts index 55912fef980eb..9909562392cdf 100644 --- a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts +++ b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts @@ -5,12 +5,14 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { useEffect } from 'react'; import { useSelector } from 'react-redux'; import { useQueryTheme } from 'calypso/components/data/query-theme'; +import { useDispatch as useReduxDispatch } from 'calypso/state'; +import { activateOrInstallThenActivate } from 'calypso/state/themes/actions'; import { getTheme } from 'calypso/state/themes/selectors'; -import { useSiteSlug } from '../hooks/use-site-slug'; +import { useSiteData } from '../hooks/use-site-data'; import { ONBOARD_STORE } from '../stores'; import { STEPS } from './internals/steps'; import { ProcessingResult } from './internals/steps-repository/processing-step/constants'; -import { Flow, ProvidedDependencies } from './internals/types'; +import { AssertConditionResult, AssertConditionState, Flow } from './internals/types'; import type { OnboardSelect } from '@automattic/data-stores'; const SiteIntent = Onboard.SiteIntent; @@ -23,7 +25,7 @@ const withThemeAssemblerFlow: Flow = { ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), [] ); - const { setSelectedDesign, setIntent } = useDispatch( ONBOARD_STORE ); + const { setIntent } = useDispatch( ONBOARD_STORE ); const selectedTheme = getAssemblerDesign().slug; const theme = useSelector( ( state ) => getTheme( state, 'wpcom', selectedTheme ) ); @@ -53,59 +55,81 @@ const withThemeAssemblerFlow: Flow = { }, useSteps() { - return [ STEPS.PATTERN_ASSEMBLER, STEPS.PROCESSING, STEPS.ERROR, STEPS.CELEBRATION ]; + return [ STEPS.PROCESSING, STEPS.ERROR ]; }, useStepNavigation( _currentStep, navigate ) { const { setPendingAction } = useDispatch( ONBOARD_STORE ); - const siteSlug = useSiteSlug(); + const reduxDispatch = useReduxDispatch(); + const selectedTheme = getAssemblerDesign().slug; + const { siteSlug, siteId } = useSiteData(); - const exitFlow = ( to: string ) => { - setPendingAction( () => { - return new Promise( () => { - window.location.assign( to ); - } ); - } ); + const handleSelectSite = () => { + setPendingAction( enableAssemblerTheme( selectedTheme, siteId, siteSlug, reduxDispatch ) ); - return navigate( 'processing' ); + navigate( 'processing' ); }; - const submit = ( providedDependencies: ProvidedDependencies = {}, ...results: string[] ) => { + const submit = ( _, ...results: string[] ) => { switch ( _currentStep ) { case 'processing': { if ( results.some( ( result ) => result === ProcessingResult.FAILURE ) ) { return navigate( 'error' ); } - const params = new URLSearchParams( { - canvas: 'edit', - assembler: '1', - } ); - - // We will navigate to the celebration step in the follow-up PR - return exitFlow( `/site-editor/${ siteSlug }?${ params }` ); - } - - case 'pattern-assembler': { - return navigate( 'processing' ); - } - - case 'celebration-step': { - return window.location.assign( providedDependencies.destinationUrl as string ); + return handleSelectSite(); } } }; - const goBack = () => { - switch ( _currentStep ) { - case 'pattern-assembler': { - return window.location.assign( `/themes/${ siteSlug }` ); - } - } - }; + return { submit }; + }, - return { submit, goBack }; + useAssertConditions(): AssertConditionResult { + const { site, siteSlug } = useSiteData(); + let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; + + if ( ! siteSlug ) { + result = { + state: AssertConditionState.FAILURE, + message: 'site-setup did not provide the site slug it is configured to.', + }; + } + + if ( ! site ) { + result = { + state: AssertConditionState.CHECKING, + }; + } + + return result; }, }; +function enableAssemblerTheme( + themeId: string, + siteId: number, + siteSlug: string, + reduxDispatch: CalypsoDispatch +) { + const params = new URLSearchParams( { + canvas: 'edit', + assembler: '1', + } ); + + return () => + Promise.resolve() + .then( () => + reduxDispatch( + activateOrInstallThenActivate( themeId, siteId, { source: 'assembler' } ) as ThunkAction< + PromiseLike< string >, + any, + any, + AnyAction + > + ) + ) + .then( () => window.location.assign( `/site-editor/${ siteSlug }?${ params }` ) ); +} + export default withThemeAssemblerFlow; diff --git a/client/my-sites/patterns/components/category-gallery/client.tsx b/client/my-sites/patterns/components/category-gallery/client.tsx index c08b5efe5bdc9..59536039def33 100644 --- a/client/my-sites/patterns/components/category-gallery/client.tsx +++ b/client/my-sites/patterns/components/category-gallery/client.tsx @@ -3,7 +3,6 @@ import { usePatternsRendererContext } from '@automattic/block-renderer/src/compo import clsx from 'clsx'; import { useTranslate } from 'i18n-calypso'; import { useEffect, useRef } from 'react'; -import { encodePatternId } from 'calypso/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/utils'; import { CategoryGalleryServer } from 'calypso/my-sites/patterns/components/category-gallery/server'; import { LocalizedLink } from 'calypso/my-sites/patterns/components/localized-link'; import { @@ -12,6 +11,7 @@ import { } from 'calypso/my-sites/patterns/components/pattern-preview'; import { PatternsSection } from 'calypso/my-sites/patterns/components/section'; import { RENDERER_SITE_ID } from 'calypso/my-sites/patterns/constants'; +import { encodePatternId } from 'calypso/my-sites/patterns/lib/encode-pattern-id'; import { getCategoryUrlPath } from 'calypso/my-sites/patterns/paths'; import { PatternTypeFilter, Category, CategoryGalleryFC } from 'calypso/my-sites/patterns/types'; diff --git a/client/my-sites/patterns/components/pattern-preview/index.tsx b/client/my-sites/patterns/components/pattern-preview/index.tsx index 3370bc63610e2..be684c8f6e4a1 100644 --- a/client/my-sites/patterns/components/pattern-preview/index.tsx +++ b/client/my-sites/patterns/components/pattern-preview/index.tsx @@ -12,12 +12,12 @@ import clsx from 'clsx'; import { useRtl, useTranslate } from 'i18n-calypso'; import { useEffect, useRef, useState } from 'react'; import ClipboardButton from 'calypso/components/forms/clipboard-button'; -import { encodePatternId } from 'calypso/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/utils'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { PatternsGetAccessModal } from 'calypso/my-sites/patterns/components/get-access-modal'; import { patternFiltersClassName } from 'calypso/my-sites/patterns/components/pattern-library'; import { usePatternsContext } from 'calypso/my-sites/patterns/context'; import { useRecordPatternsEvent } from 'calypso/my-sites/patterns/hooks/use-record-patterns-event'; +import { encodePatternId } from 'calypso/my-sites/patterns/lib/encode-pattern-id'; import { getTracksPatternType } from 'calypso/my-sites/patterns/lib/get-tracks-pattern-type'; import { useSelector } from 'calypso/state'; import { isUserLoggedIn } from 'calypso/state/current-user/selectors'; diff --git a/client/my-sites/patterns/constants.ts b/client/my-sites/patterns/constants.ts index 58a50a7e329ae..20dd6ac36ceda 100644 --- a/client/my-sites/patterns/constants.ts +++ b/client/my-sites/patterns/constants.ts @@ -1,4 +1,5 @@ export const CATEGORY_FEATURED = 'featured'; export const CATEGORY_PAGE = 'page'; +export const PATTERN_SOURCE_SITE_ID = 174455321; //dotcompatterns export const RENDERER_SITE_ID = 226011606; // assemblerdemo diff --git a/client/my-sites/patterns/lib/encode-pattern-id.ts b/client/my-sites/patterns/lib/encode-pattern-id.ts new file mode 100644 index 0000000000000..62bca91901cc8 --- /dev/null +++ b/client/my-sites/patterns/lib/encode-pattern-id.ts @@ -0,0 +1,4 @@ +import { PATTERN_SOURCE_SITE_ID } from 'calypso/my-sites/patterns/constants'; + +export const encodePatternId = ( patternId: number ) => + `${ patternId }-${ PATTERN_SOURCE_SITE_ID }`; From 373ea11bfc262ee1257b8a213f49f56d534f71d1 Mon Sep 17 00:00:00 2001 From: Griffith Chen Date: Wed, 11 Dec 2024 21:20:19 +0800 Subject: [PATCH 2/4] Type check --- .../declarative-flow/assembler-first-flow.ts | 1 - .../stepper/declarative-flow/site-setup-flow.ts | 11 ----------- .../stepper/declarative-flow/update-design.ts | 2 +- .../declarative-flow/with-theme-assembler-flow.ts | 14 +++++++++++--- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/client/landing/stepper/declarative-flow/assembler-first-flow.ts b/client/landing/stepper/declarative-flow/assembler-first-flow.ts index 849cdcd69cfad..f6a80f13816e0 100644 --- a/client/landing/stepper/declarative-flow/assembler-first-flow.ts +++ b/client/landing/stepper/declarative-flow/assembler-first-flow.ts @@ -71,7 +71,6 @@ const assemblerFirstFlow: Flow = { STEPS.NEW_OR_EXISTING_SITE, STEPS.SITE_PICKER, STEPS.SITE_CREATION_STEP, - STEPS.PATTERN_ASSEMBLER, STEPS.FREE_POST_SETUP, STEPS.PROCESSING, STEPS.ERROR, diff --git a/client/landing/stepper/declarative-flow/site-setup-flow.ts b/client/landing/stepper/declarative-flow/site-setup-flow.ts index 3b9f7e5d46002..b23f26ae3bf57 100644 --- a/client/landing/stepper/declarative-flow/site-setup-flow.ts +++ b/client/landing/stepper/declarative-flow/site-setup-flow.ts @@ -55,7 +55,6 @@ const siteSetupFlow: Flow = { STEPS.OPTIONS, STEPS.DESIGN_CHOICES, STEPS.DESIGN_SETUP, - STEPS.PATTERN_ASSEMBLER, STEPS.BLOGGER_STARTING_POINT, STEPS.COURSES, STEPS.IMPORT, @@ -272,16 +271,6 @@ const siteSetupFlow: Flow = { return navigate( 'error' ); } - // End of Pattern Assembler flow - if ( isAssemblerDesign( selectedDesign ) ) { - const params = new URLSearchParams( { - canvas: 'edit', - assembler: '1', - } ); - - return exitFlow( `/site-editor/${ siteSlug }?${ params }` ); - } - // If the user skips starting point, redirect them to the post editor if ( isGoalsHoldout && intent === 'write' && startingPoint !== 'skip-to-my-home' ) { if ( startingPoint !== 'write' ) { diff --git a/client/landing/stepper/declarative-flow/update-design.ts b/client/landing/stepper/declarative-flow/update-design.ts index c99454c1d908c..24ffe41089c78 100644 --- a/client/landing/stepper/declarative-flow/update-design.ts +++ b/client/landing/stepper/declarative-flow/update-design.ts @@ -24,7 +24,7 @@ const updateDesign: Flow = { }, isSignupFlow: false, useSteps() { - return [ STEPS.DESIGN_SETUP, STEPS.PATTERN_ASSEMBLER, STEPS.PROCESSING, STEPS.ERROR ]; + return [ STEPS.DESIGN_SETUP, STEPS.PROCESSING, STEPS.ERROR ]; }, useSideEffect() { const { setIntent } = useDispatch( ONBOARD_STORE ); diff --git a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts index 9909562392cdf..dad5f82385eff 100644 --- a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts +++ b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts @@ -12,8 +12,16 @@ import { useSiteData } from '../hooks/use-site-data'; import { ONBOARD_STORE } from '../stores'; import { STEPS } from './internals/steps'; import { ProcessingResult } from './internals/steps-repository/processing-step/constants'; -import { AssertConditionResult, AssertConditionState, Flow } from './internals/types'; +import { + AssertConditionResult, + AssertConditionState, + Flow, + ProvidedDependencies, +} from './internals/types'; import type { OnboardSelect } from '@automattic/data-stores'; +import type { CalypsoDispatch } from 'calypso/state/types'; +import type { AnyAction } from 'redux'; +import type { ThunkAction } from 'redux-thunk'; const SiteIntent = Onboard.SiteIntent; @@ -25,7 +33,7 @@ const withThemeAssemblerFlow: Flow = { ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), [] ); - const { setIntent } = useDispatch( ONBOARD_STORE ); + const { setSelectedDesign, setIntent } = useDispatch( ONBOARD_STORE ); const selectedTheme = getAssemblerDesign().slug; const theme = useSelector( ( state ) => getTheme( state, 'wpcom', selectedTheme ) ); @@ -70,7 +78,7 @@ const withThemeAssemblerFlow: Flow = { navigate( 'processing' ); }; - const submit = ( _, ...results: string[] ) => { + const submit = ( _: ProvidedDependencies, ...results: string[] ) => { switch ( _currentStep ) { case 'processing': { if ( results.some( ( result ) => result === ProcessingResult.FAILURE ) ) { From 5a0be4490660288c9f873d74e16f06a4cc518c49 Mon Sep 17 00:00:00 2001 From: Griffith Chen Date: Wed, 11 Dec 2024 22:01:14 +0800 Subject: [PATCH 3/4] Type check --- .../declarative-flow/with-theme-assembler-flow.ts | 3 ++- client/my-sites/patterns/types.ts | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts index dad5f82385eff..77479aa6f2459 100644 --- a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts +++ b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts @@ -78,7 +78,8 @@ const withThemeAssemblerFlow: Flow = { navigate( 'processing' ); }; - const submit = ( _: ProvidedDependencies, ...results: string[] ) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const submit = ( providedDependencies: ProvidedDependencies, ...results: string[] ) => { switch ( _currentStep ) { case 'processing': { if ( results.some( ( result ) => result === ProcessingResult.FAILURE ) ) { diff --git a/client/my-sites/patterns/types.ts b/client/my-sites/patterns/types.ts index fabd78c615a3c..13bf5fe88c364 100644 --- a/client/my-sites/patterns/types.ts +++ b/client/my-sites/patterns/types.ts @@ -1,7 +1,6 @@ import { GlobalStylesObject } from '@automattic/global-styles'; import type { Context } from '@automattic/calypso-router'; import type { QueryClient } from '@tanstack/react-query'; -import type { Pattern as AssemblerPattern } from 'calypso/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/types'; import type { PartialContext as PerformanceMarkContext } from 'calypso/server/lib/performance-mark'; export type RouterNext = ( error?: Error ) => void; @@ -12,7 +11,17 @@ export type RouterContext = Context & queryClient: QueryClient; }; -export type Pattern = AssemblerPattern & { +export type Pattern = { + ID: number; + name: string; + title: string; + description?: string; + category?: Category; + categories: Record< string, Category | undefined >; + key?: string; + pattern_meta?: Record< string, boolean | undefined >; + html?: string; + tags: Record< string, Tag | undefined >; can_be_copied_without_account?: boolean; }; From ace42211fac24e49ae0f72836c34e81d52f02813 Mon Sep 17 00:00:00 2001 From: Griffith Chen Date: Wed, 11 Dec 2024 22:14:30 +0800 Subject: [PATCH 4/4] Type check --- .../with-theme-assembler-flow.ts | 2 +- client/my-sites/patterns/types.ts | 25 ++++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts index 77479aa6f2459..2af009bf451d3 100644 --- a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts +++ b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts @@ -79,7 +79,7 @@ const withThemeAssemblerFlow: Flow = { }; // eslint-disable-next-line @typescript-eslint/no-unused-vars - const submit = ( providedDependencies: ProvidedDependencies, ...results: string[] ) => { + const submit = ( providedDependencies: ProvidedDependencies = {}, ...results: string[] ) => { switch ( _currentStep ) { case 'processing': { if ( results.some( ( result ) => result === ProcessingResult.FAILURE ) ) { diff --git a/client/my-sites/patterns/types.ts b/client/my-sites/patterns/types.ts index 13bf5fe88c364..8dfaada1f8834 100644 --- a/client/my-sites/patterns/types.ts +++ b/client/my-sites/patterns/types.ts @@ -11,17 +11,34 @@ export type RouterContext = Context & queryClient: QueryClient; }; -export type Pattern = { +export type AssemblerPattern = { ID: number; name: string; title: string; description?: string; - category?: Category; - categories: Record< string, Category | undefined >; + category?: AssemblerCategory; + categories: Record< string, AssemblerCategory | undefined >; key?: string; pattern_meta?: Record< string, boolean | undefined >; html?: string; - tags: Record< string, Tag | undefined >; + tags: Record< string, AssemblerTag | undefined >; +}; + +export type AssemblerCategory = { + name?: string; + title?: string; + slug?: string; + label?: string; + description?: string; +}; + +export type AssemblerTag = { + slug: string; + title: string; + description: string; +}; + +export type Pattern = AssemblerPattern & { can_be_copied_without_account?: boolean; };