Skip to content

Commit

Permalink
Add: Modal to choose a start pattern on new templates.
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Dec 2, 2022
1 parent aede098 commit f592ccb
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 23 deletions.
12 changes: 12 additions & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,15 @@ function gutenberg_register_legacy_social_link_blocks() {
}

add_action( 'init', 'gutenberg_register_legacy_social_link_blocks' );

register_block_pattern(
'custom-pattern',
array(
'title' => _x( 'Start post pattern', 'Block pattern title', 'gutenberg' ),
'blockTypes' => array( 'core/paragraph', 'core/post-content' ),
// 'postTypes' => array( 'page' ),
'content' => '<!-- wp:paragraph -->
<p>A start post pattern</p>
<!-- /wp:paragraph -->',
)
);
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ class Gutenberg_REST_Templates_Controller_6_2 extends Gutenberg_REST_Templates_C
* @return void
*/
public function register_routes() {
parent::register_routes();
// Get fallback template content.

register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/lookup',
Expand All @@ -41,10 +40,17 @@ public function register_routes() {
'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`', 'gutenberg' ),
'type' => 'string',
),
'ignore_empty' => array(
'description' => __( 'If true templates with empty content are ignored.', 'gutenberg' ),
'type' => 'boolean',
'default' => false,
),
),
),
)
);
parent::register_routes();
// Get fallback template content.
}

/**
Expand All @@ -56,8 +62,16 @@ public function register_routes() {
*/
public function get_template_fallback( $request ) {
$hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] );
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
$response = $this->prepare_item_for_response( $fallback_template, $request );
$fallback_template = null;
if ( true === $request['ignore_empty'] ) {
do {
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
array_shift( $hierarchy );
} while ( ! empty( $hierarchy ) && empty( $fallback_template->content ) );
} else {
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
}
$response = $this->prepare_item_for_response( $fallback_template, $request );
return rest_ensure_response( $response );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ function BlockPattern( { isDraggable, pattern, onClick, composite } ) {
blocks={ blocks }
viewportWidth={ viewportWidth }
/>
<div className="block-editor-block-patterns-list__item-title">
{ pattern.title }
</div>
{ pattern.title && (
<div className="block-editor-block-patterns-list__item-title">
{ pattern.title }
</div>
) }
{ !! pattern.description && (
<VisuallyHidden id={ descriptionId }>
{ pattern.description }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
import {
DropdownMenu,
MenuGroup,
Expand Down Expand Up @@ -102,19 +100,7 @@ export default function NewTemplate( { postType } ) {
}
setIsCreatingTemplate( true );
try {
const { title, description, slug, templatePrefix } = template;
let templateContent = template.content;
// Try to find fallback content from existing templates.
if ( ! templateContent ) {
const fallbackTemplate = await apiFetch( {
path: addQueryArgs( '/wp/v2/templates/lookup', {
slug,
is_custom: ! isWPSuggestion,
template_prefix: templatePrefix,
} ),
} );
templateContent = fallbackTemplate.content.raw;
}
const { title, description, slug } = template;
const newTemplate = await saveEntityRecord(
'postType',
'wp_template',
Expand All @@ -124,7 +110,6 @@ export default function NewTemplate( { postType } ) {
slug: slug.toString(),
status: 'publish',
title,
content: templateContent,
// This adds a post meta field in template that is part of `is_custom` value calculation.
is_wp_suggestion: isWPSuggestion,
},
Expand Down
2 changes: 2 additions & 0 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import useInitEditedEntityFromURL from '../use-init-edited-entity-from-url';
import InserterSidebar from '../secondary-sidebar/inserter-sidebar';
import ListViewSidebar from '../secondary-sidebar/list-view-sidebar';
import WelcomeGuide from '../welcome-guide';
import StartTemplateOptions from '../start-template-options';
import { store as editSiteStore } from '../../store';
import { GlobalStylesRenderer } from '../global-styles-renderer';
import { GlobalStylesProvider } from '../global-styles/global-styles-provider';
Expand Down Expand Up @@ -183,6 +184,7 @@ export default function Editor() {
>
<GlobalStylesProvider>
<BlockContextProvider value={ blockContext }>
<StartTemplateOptions />
<InterfaceSkeleton
className={
showIconLabels && 'show-icon-labels'
Expand Down
166 changes: 166 additions & 0 deletions packages/edit-site/src/components/start-template-options/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* WordPress dependencies
*/
import { Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { __experimentalBlockPatternsList as BlockPatternsList } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { useAsyncList } from '@wordpress/compose';
import { store as preferencesStore } from '@wordpress/preferences';
import { parse } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../store';
import { store as coreStore, useEntityBlockEditor } from '@wordpress/core-data';
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';

function useFallbackTemplateContent( slug, isCustom = false ) {
const [ templateContent, setTemplateContent ] = useState( '' );

useEffect( () => {
apiFetch( {
path: addQueryArgs( '/wp/v2/templates/lookup', {
slug,
is_custom: isCustom,
ignore_empty: true,
} ),
} ).then( ( { content } ) => setTemplateContent( content.raw ) );
}, [ slug ] );
return templateContent;
}

function PatternSelection( { fallbackContent, onChoosePattern, postType } ) {
const [ , , onChange ] = useEntityBlockEditor( 'postType', postType );
const blockPatterns = useMemo(
() => [
{
name: 'fallback',
blocks: parse( fallbackContent ),
},
{
name: 'start-blank',
blocks: parse(
'<!-- wp:paragraph --><p></p><!-- /wp:paragraph -->'
),
title: __( 'Start blank' ),
},
],
[ fallbackContent ]
);
const shownBlockPatterns = useAsyncList( blockPatterns );
return (
<BlockPatternsList
blockPatterns={ blockPatterns }
shownPatterns={ shownBlockPatterns }
onClickPattern={ ( pattern, blocks ) => {
onChange( 'start-blank' === pattern.name ? [] : blocks, {
selection: undefined,
} );
onChoosePattern();
} }
/>
);
}

function StartModal( { slug, isCustom, onClose, postType } ) {
const fallbackContent = useFallbackTemplateContent( slug, isCustom );
if ( ! fallbackContent ) {
return null;
}
return (
<Modal
className="edit-site-start-template-options__modal"
title={ __( 'Choose a pattern' ) }
closeLabel={ __( 'Cancel' ) }
focusOnMount="firstElement"
onRequestClose={ onClose }
>
<div className="edit-site-start-template-options__modal-content">
<PatternSelection
fallbackContent={ fallbackContent }
slug={ slug }
isCustom={ isCustom }
postType={ postType }
onChoosePattern={ () => {
onClose();
} }
/>
</div>
</Modal>
);
}

const START_TEMPLATE_MODAL_STATES = {
INITIAL: 'INITIAL',
PATTERN: 'PATTERN',
CLOSED: 'CLOSED',
};

export default function StartTemplateOptions() {
const [ modalState, setModalState ] = useState(
START_TEMPLATE_MODAL_STATES.INITIAL
);
const { shouldOpenModel, slug, isCustom, postType } = useSelect(
( select ) => {
const { getEditedPostType, getEditedPostId } =
select( editSiteStore );
const _postType = getEditedPostType();
const postId = getEditedPostId();
const {
__experimentalGetDirtyEntityRecords,
getEditedEntityRecord,
} = select( coreStore );
const templateRecord = getEditedEntityRecord(
'postType',
_postType,
postId
);

const hasDirtyEntityRecords =
__experimentalGetDirtyEntityRecords().length > 0;

return {
shouldOpenModel:
modalState === START_TEMPLATE_MODAL_STATES.INITIAL &&
! hasDirtyEntityRecords &&
'' === templateRecord.content &&
'wp_template' === _postType &&
! select( preferencesStore ).get(
'core/edit-site',
'welcomeGuide'
),
slug: templateRecord.slug,
isCustom: templateRecord.is_custom,
postType: _postType,
};
},
[ modalState ]
);

useEffect( () => {
if ( shouldOpenModel ) {
setModalState( START_TEMPLATE_MODAL_STATES.PATTERN );
}
}, [ shouldOpenModel ] );

if (
modalState === START_TEMPLATE_MODAL_STATES.INITIAL ||
modalState === START_TEMPLATE_MODAL_STATES.CLOSED
) {
return null;
}
return (
<StartModal
slug={ slug }
isCustom={ isCustom }
postType={ postType }
onClose={ () =>
setModalState( START_TEMPLATE_MODAL_STATES.CLOSED )
}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.edit-site-start-template-options__modal.components-modal__frame {
// 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: 70%;
}
@include break-large() {
height: fit-content;
}
}

// 2 column masonry layout.
.edit-site-start-template-options__modal-content .block-editor-block-patterns-list {
display: flex;
width: 100%;
margin-top: $grid-unit-05;
gap: $grid-unit-10;

.block-editor-block-patterns-list__list-item {
break-inside: avoid-column;
margin-bottom: $grid-unit-30;
width: 240px;

> div {
width: 240px !important;
}

.block-editor-block-preview__container {
height: 320px;
width: 240px;
}

.block-editor-block-preview__content {
width: 100%;
position: absolute;
}
}

// The start blank pattern is the last and we are selecting it.
.block-editor-block-patterns-list__list-item:nth-last-child(2) {
.block-editor-block-patterns-list__item-title {
position: absolute;
padding: 0;
width: 100%;
top: 50%;
margin-top: -1em;
}
.block-editor-block-preview__container {
background: #f0f0f0;
}
iframe {
display: none;
}
}
}
1 change: 1 addition & 0 deletions packages/edit-site/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
@import "./components/create-template-part-modal/style.scss";
@import "./components/secondary-sidebar/style.scss";
@import "./components/welcome-guide/style.scss";
@import "./components/start-template-options/style.scss";
@import "./components/keyboard-shortcut-help-modal/style.scss";
@import "./components/layout/style.scss";
@import "./components/sidebar/style.scss";
Expand Down

0 comments on commit f592ccb

Please sign in to comment.