diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index 989c185943c2c..133e423e71497 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -47,6 +47,7 @@ import SettingsSidebar from '../sidebar/settings-sidebar'; import MetaBoxes from '../meta-boxes'; import WelcomeGuide from '../welcome-guide'; import ActionsPanel from './actions-panel'; +import StartPageOptions from '../start-page-options'; import { store as editPostStore } from '../../store'; const interfaceLabels = { @@ -286,6 +287,7 @@ function Layout( { styles } ) { + diff --git a/packages/edit-post/src/components/start-page-options/index.js b/packages/edit-post/src/components/start-page-options/index.js new file mode 100644 index 0000000000000..092883d3654d7 --- /dev/null +++ b/packages/edit-post/src/components/start-page-options/index.js @@ -0,0 +1,216 @@ +/** + * WordPress dependencies + */ +import { Modal } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { useState, useMemo, useEffect } from '@wordpress/element'; +import { + store as blockEditorStore, + __experimentalBlockPatternsList as BlockPatternsList, +} from '@wordpress/block-editor'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useAsyncList } from '@wordpress/compose'; +import { store as editorStore } from '@wordpress/editor'; +import { store as coreStore } from '@wordpress/core-data'; +import { parse } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { store as editPostStore } from '../../store'; + +function TemplateSelection( { onChooseTemplate } ) { + const { availableTemplates, fetchedTemplates, linkedTemplate } = useSelect( + ( select ) => { + const { + getEditorSettings, + getCurrentPostType, + getCurrentPost, + } = select( editorStore ); + const { getEntityRecords } = select( coreStore ); + + const currentPostType = getCurrentPostType(); + const currentPostLink = getCurrentPost().link; + + const templateRecords = getEntityRecords( + 'postType', + 'wp_template', + { + post_type: currentPostType, + per_page: -1, + } + ); + + const linkedTemplateRecords = getEntityRecords( + 'postType', + 'wp_template', + { + 'find-template': currentPostLink, + per_page: 1, + } + ); + + return { + availableTemplates: getEditorSettings().availableTemplates, + fetchedTemplates: templateRecords, + linkedTemplate: + linkedTemplateRecords && linkedTemplateRecords[ 0 ], + }; + }, + [] + ); + const templatesAsPatterns = useMemo( () => { + let templates = ( fetchedTemplates || [] ).filter( + ( { slug } ) => !! availableTemplates[ slug ] + ); + if ( + linkedTemplate && + ! templates.some( ( { id } ) => id === linkedTemplate.id ) + ) { + templates = [ linkedTemplate, ...templates ]; + } + return templates.map( ( template ) => ( { + name: template.id, + title: template.title.rendered, + blocks: parse( template.content.raw ), + template, + } ) ); + }, [ availableTemplates, fetchedTemplates, linkedTemplate ] ); + const shownPatterns = useAsyncList( templatesAsPatterns ); + const { editPost } = useDispatch( editorStore ); + useEffect( () => { + if ( availableTemplates.length <= 1 ) { + onChooseTemplate(); + } + }, [ availableTemplates.length ] ); + return ( + { + if ( template.id !== linkedTemplate.id ) { + editPost( { template: template.slug } ); + } + onChooseTemplate(); + } } + /> + ); +} + +function PatternSelection( { onChoosePattern } ) { + const { blockPatterns } = useSelect( ( select ) => { + const { __experimentalGetPatternsByBlockTypes } = select( + blockEditorStore + ); + return { + blockPatterns: __experimentalGetPatternsByBlockTypes( + 'core/post-content' + ), + }; + }, [] ); + const shownBlockPatterns = useAsyncList( blockPatterns ); + const { resetEditorBlocks } = useDispatch( editorStore ); + useEffect( () => { + if ( blockPatterns.length <= 1 ) { + onChoosePattern(); + } + }, [ blockPatterns.length ] ); + return ( + { + resetEditorBlocks( blocks ); + onChoosePattern(); + } } + /> + ); +} + +const START_PAGE_MODAL_STATES = { + INITIAL: 'INITIAL', + TEMPLATE: 'TEMPLATE', + PATTERN: 'PATTERN', + CLOSED: 'CLOSED', +}; + +export default function StartPageOptions() { + const [ modalState, setModalState ] = useState( + START_PAGE_MODAL_STATES.INITIAL + ); + const shouldOpenModel = useSelect( + ( select ) => { + if ( modalState !== START_PAGE_MODAL_STATES.INITIAL ) { + return false; + } + const { + getCurrentPostType, + getEditedPostContent, + getEditedPostAttribute, + isEditedPostSaveable, + } = select( editorStore ); + const { isEditingTemplate, isFeatureActive } = select( + editPostStore + ); + return ( + getCurrentPostType() === 'page' && + ! isEditedPostSaveable() && + '' === getEditedPostContent() && + '' === getEditedPostAttribute( 'template' ) && + ! isEditingTemplate() && + ! isFeatureActive( 'welcomeGuide' ) + ); + }, + [ modalState ] + ); + + useEffect( () => { + if ( shouldOpenModel ) { + setModalState( START_PAGE_MODAL_STATES.TEMPLATE ); + } + }, [ shouldOpenModel ] ); + + if ( + modalState === START_PAGE_MODAL_STATES.INITIAL || + modalState === START_PAGE_MODAL_STATES.CLOSED + ) { + return null; + } + return ( + { + switch ( modalState ) { + case START_PAGE_MODAL_STATES.TEMPLATE: + setModalState( START_PAGE_MODAL_STATES.PATTERN ); + return; + case START_PAGE_MODAL_STATES.PATTERN: + setModalState( START_PAGE_MODAL_STATES.CLOSED ); + } + } } + > +
+ { modalState === START_PAGE_MODAL_STATES.TEMPLATE && ( + { + setModalState( START_PAGE_MODAL_STATES.PATTERN ); + } } + /> + ) } + { modalState === START_PAGE_MODAL_STATES.PATTERN && ( + { + setModalState( START_PAGE_MODAL_STATES.CLOSED ); + } } + /> + ) } +
+
+ ); +} diff --git a/packages/edit-post/src/components/start-page-options/style.scss b/packages/edit-post/src/components/start-page-options/style.scss new file mode 100644 index 0000000000000..78c0011aa6f28 --- /dev/null +++ b/packages/edit-post/src/components/start-page-options/style.scss @@ -0,0 +1,27 @@ +.edit-post-start-page-options__modal { + // To keep modal dimensions consistent as subsections are navigated, width + // and height are used instead of max-(width/height). + @include break-small() { + width: calc(100% - #{ $grid-unit-20 * 2 }); + height: calc(100% - #{ $header-height * 2 }); + } + @include break-medium() { + width: $break-medium - $grid-unit-20 * 2; + } + @include break-large() { + height: 70%; + } +} + +.edit-post-start-page-options__modal-content .block-editor-block-patterns-list { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: $grid-unit-10; + + .block-editor-block-patterns-list__list-item { + margin-bottom: 0; + .block-editor-block-preview__container { + min-height: 100px; + } + } +} diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index fe6f8d3f6a0a1..519197cb789a4 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -24,6 +24,7 @@ @import "./components/text-editor/style.scss"; @import "./components/visual-editor/style.scss"; @import "./components/welcome-guide/style.scss"; +@import "./components/start-page-options/style.scss"; /** * Animations