Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AMP Stories] Add template Inserter #2029

Merged
merged 25 commits into from
Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bf424fc
Start adding template inserter.
miina Mar 25, 2019
7e0b682
Make template inserter (kind of) functional.
miina Mar 26, 2019
738d975
Improve style.
miina Mar 26, 2019
1932e3f
Improve API request.
miina Mar 26, 2019
9273dc0
Remove unused params.
miina Mar 26, 2019
f0b70f9
Rework getting reusable blocks.
miina Mar 27, 2019
1306f9c
Remove unused code.
miina Mar 27, 2019
8ae5c64
Style adjustments.
miina Mar 27, 2019
3c43aeb
Add icons for the template inserter and reordering.
miina Mar 28, 2019
7eb3a3e
Allow saving custom templates.
miina Mar 28, 2019
24bf37c
Update dashicon.
miina Mar 28, 2019
364a61f
Prevent endless loading.
miina Mar 28, 2019
3a53207
Merge remote-tracking branch 'origin/amp-stories-redux' into amp-stor…
miina Mar 28, 2019
788d22d
Style fix.
miina Mar 28, 2019
46834cf
Add todo notice.
miina Mar 29, 2019
4f3baf5
Use pre-existing pageIcon file
swissspidy Apr 1, 2019
9f4d919
Use pre-existing BlockPreview component
swissspidy Apr 1, 2019
de77363
Extract all SVGs into separate files
swissspidy Apr 1, 2019
379d51d
Fix reorder cancel button styling
swissspidy Apr 1, 2019
6859bfd
ESLint fix
swissspidy Apr 1, 2019
cdec4ae
Merge branch 'amp-stories-redux' into amp-story/1902-template_inserter
swissspidy Apr 1, 2019
abd0879
Remove unused import after merge
swissspidy Apr 1, 2019
d72d6ee
Add role to PluginBlockSettingsMenuItem
swissspidy Apr 1, 2019
53def88
Remove allowedBlockNames todo
swissspidy Apr 1, 2019
a5ee722
Rename allowedBlockNames to allowedBlocks as per upstream discussion
swissspidy Apr 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions assets/css/amp-editor-story-blocks.css
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,80 @@ div[data-type="amp/amp-story-page"] .wp-block-image {
* 10. Custom Components
*/

/*
* Template Inserter Component.
*/
.amp-stories__template-inserter__popover.components-popover .components-popover__content:not(.is-mobile) {
width: 386px;
height: 400px;
padding: 2px;
transform: translateX(-90%);
}

@media (min-width: 782px) {
.amp-stories__template-inserter__popover.block-editor-inserter__popover:not(.is-mobile) > .components-popover__content {
overflow-y: scroll;
}
}

.edit-post-layout:not(.is-sidebar-opened) .amp-stories__template-inserter__popover.components-popover .components-popover__content:not(.is-mobile) {
left: initial;
transform: none;
}

.amp-stories__template-inserter__popover.block-editor-inserter__popover .block-editor-block-types-list {
margin: 0;
padding: 5px;
}

.amp-stories__template-inserter__popover.components-popover.is-top .components-popover__content {
bottom: initial;
}

.amp-stories__editor-inserter__results li {
display: block;
list-style-type: none;
width: 160px;
height: 268px;
float: left;
margin: 15px;
}

.amp-stories__editor-inserter__results li amp-story-page,
.amp-stories__editor-inserter__results li amp-story-grid-layer {
display: block;
width: 100%;
height: 100%;
}

.amp-stories__editor-inserter__results .block-editor-block-preview {
width: 160px;
height: 268px;
margin: 10px;
padding: 0;
}

.amp-stories__editor-inserter__results .block-editor-block-preview .block-editor-block-preview__content,
.amo-stories__editor-inserter__results .components-placeholder {
padding: 0;
width: 100%;
height: 100%;
}

.amp-stories__blank-page-inserter {
height: 100%;
width: 100%;
}

.amp-stories__blank-page-inserter svg {
margin: 0 auto;
}

.amp-stories__editor-inserter__results .block-editor-block-preview {
pointer-events: initial;
}


/*
* Preview Picker component
*
Expand Down
1 change: 1 addition & 0 deletions assets/src/blocks/amp-story-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const name = 'amp/amp-story-text';
const supports = {
className: false,
anchor: true,
reusable: true,
};

const schema = {
Expand Down
4 changes: 4 additions & 0 deletions assets/src/blocks/amp-story/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export const settings = {
icon: BLOCK_ICONS[ 'amp/amp-story-page' ],
attributes: schema,

supports: {
reusable: true,
},

/*
* <amp-story-page>:
* mandatory_parent: "AMP-STORY"
Expand Down
1 change: 1 addition & 0 deletions assets/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { default as StoryControls } from './story-controls';
export { default as Shortcuts } from './shortcuts';
export { default as StoryBlockDropZone } from './story-block-drop-zone';
export { default as StoryBlockMover } from './block-mover';
export { default as TemplateInserter } from './template-inserter';
export { default as FontFamilyPicker } from './font-family-picker';
export { default as withAmpStorySettings } from './with-amp-story-settings';
export { default as withAnimationControls } from './with-animation-controls';
Expand Down
27 changes: 6 additions & 21 deletions assets/src/components/story-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
* to add new pages and start/stop reordering pages.
*/

/**
* Internal dependencies
*/
import { TemplateInserter } from './';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { IconButton, Button } from '@wordpress/components';
import { Fragment } from '@wordpress/element';
import { Inserter } from '@wordpress/editor';
import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';

Expand Down Expand Up @@ -38,26 +42,7 @@ function StoryControls( { isReordering, startReordering, saveOrder, resetOrder }

return (
<Fragment>
<Inserter
rootClientId=""
clientId=""
isAppender={ false }
position="bottom left"
title={ __( 'Add New Page', 'amp' ) }
style={ { position: 'relative' } }
renderToggle={ ( { onToggle, disabled, isOpen } ) => (
<IconButton
icon="insert"
label={ __( 'Add New Page', 'amp' ) }
labelPosition="bottom left"
onClick={ onToggle }
className="editor-inserter__toggle"
aria-haspopup="true"
aria-expanded={ isOpen }
disabled={ disabled }
/>
) }
/>
<TemplateInserter />
<IconButton
className="amp-story-controls-reorder"
icon="sort"
Expand Down
44 changes: 44 additions & 0 deletions assets/src/components/template-inserter/block-preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* External dependencies
*/
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import { createBlock } from '@wordpress/blocks';
import { Disabled } from '@wordpress/components';
// import { BlockEdit } from '@wordpress/block-editor';

/**
* Block Preview Component: It renders a preview given a block name and attributes.
*
* @param {Object} props Component props.
*
* @return {WPElement} Rendered element.
*/
function BlockPreview( props ) {
return (
<button onClick={ props.onClick } className="components-button editor-block-preview block-editor-block-preview">
<BlockPreviewContent { ...props } />
</button>
);
}

export function BlockPreviewContent( { name, attributes } ) {
// @todo Importing this outside of the function causes error for some reason.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because the new block-editor package is not yet listed in wpDependencies in webpack.config.js nor in package.json.

You can still use @wordpress/editor for now. It just proxies to the new package behind the scenes for BC.

Alternatively, since I am probably going to merge #2000 today and doing some rewriting there from @wordpress/editor to @wordpress/block-editor, you could then just merge in the latest changes from the amp-stories-redux branch.

const BlockEdit = wp.blockEditor.BlockEdit;
const block = createBlock( name, attributes );
return (
<Disabled className="editor-block-preview__content block-editor-block-preview__content editor-styles-wrapper" aria-hidden>
<BlockEdit
name={ block.name }
focus={ false }
attributes={ block.attributes }
setAttributes={ noop }
/>
</Disabled>
);
}

export default BlockPreview;
20 changes: 20 additions & 0 deletions assets/src/components/template-inserter/icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const pageIcon = (
<svg width="86" height="96" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#a)">
<path d="M71.115 91.034H1.654V1.655h52.923l16.538 16.552v72.828z" fill="#fff" />
<path d="M54.577 1.655v16.552h16.538L54.577 1.655z" fill="#A9A9A9" />
<path d="M71.115 19.862H54.577a1.66 1.66 0 0 1-1.654-1.655V1.655c0-.91.744-1.655 1.654-1.655.447 0 .86.182 1.174.48L72.29 17.032a1.65 1.65 0 0 1 0 2.334 1.652 1.652 0 0 1-1.175.496zm-14.884-3.31H67.13L56.23 5.644v10.908z" fill="#686868" />
<path d="M38.038 92.69H1.654A1.66 1.66 0 0 1 0 91.034V1.655C0 .745.744 0 1.654 0h52.923c.447 0 .86.182 1.174.48L72.29 17.032c.297.314.48.728.48 1.175V48c0 .91-.745 1.655-1.655 1.655S69.462 48.91 69.462 48V18.886L53.898 3.31H3.308v86.07h34.73c.91 0 1.654.744 1.654 1.655a1.66 1.66 0 0 1-1.654 1.655z" fill="#686868" />
<path d="M64.5 94.345c10.96 0 19.846-8.893 19.846-19.862 0-10.97-8.885-19.862-19.846-19.862-10.96 0-19.846 8.892-19.846 19.862 0 10.97 8.885 19.862 19.846 19.862z" fill="#A9A9A9" />
<path d="M64.5 96C52.625 96 43 86.367 43 74.483s9.625-21.517 21.5-21.517S86 62.599 86 74.483c-.017 11.884-9.625 21.5-21.5 21.517zm0-39.724c-10.055 0-18.192 8.143-18.192 18.207 0 10.063 8.137 18.207 18.192 18.207s18.192-8.144 18.192-18.207c-.016-10.047-8.153-18.19-18.192-18.207z" fill="#686868" />
<path d="M64.5 86.069a1.66 1.66 0 0 1-1.654-1.655V64.552c0-.91.744-1.655 1.654-1.655.91 0 1.654.744 1.654 1.655v19.862a1.66 1.66 0 0 1-1.654 1.655z" fill="#fff" /><path d="M74.423 76.138H54.577a1.66 1.66 0 0 1-1.654-1.655c0-.91.744-1.655 1.654-1.655h19.846c.91 0 1.654.745 1.654 1.655a1.66 1.66 0 0 1-1.654 1.655z" fill="#fff" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h86v96H0z" />
</clipPath>
</defs>
</svg>
);

export default pageIcon;
157 changes: 157 additions & 0 deletions assets/src/components/template-inserter/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Dropdown, IconButton, Spinner } from '@wordpress/components';
import { Component } from '@wordpress/element';
import { withSelect, withDispatch } from '@wordpress/data';
import { createBlock, cloneBlock } from '@wordpress/blocks';
import { compose } from '@wordpress/compose';

/**
* Internal dependencies
*/
import BlockPreview from './block-preview';
import pageIcon from './icon';

const storyPageBlockName = 'amp/amp-story-page';

class TemplateInserter extends Component {
constructor() {
super( ...arguments );

this.onToggle = this.onToggle.bind( this );

this.state = {
reusableBlocks: null,
};
}

componentDidMount() {
this.props.fetchReusableBlocks();
Copy link
Contributor Author

@miina miina Mar 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@swissspidy I reworked this not to use API fetch here, however, we'll need to change it again once we get to categories.

Also looked into using the local store together with API but didn't come to a reasonable solution at this moment. Maybe for now we could actually use the API fetch as it was before and improve it later.

I'm thinking of improving the style to be acceptable and then leave the rest to the next PR-s / issues, potentially reverting to using API fetch for now. Thoughts?

EDIT: Actually I'll probably add the possibility to add reusable blocks as well (to some extent), for the inserter to make more sense.

}

componentDidUpdate( prevProps ) {
// This check is needed to make sure that the blocks are loaded in time.
if ( prevProps.reusableBlocks !== this.props.reusableBlocks || prevProps.allBlocks !== this.props.allBlocks ) {
this.setState( {
reusableBlocks: this.props.reusableBlocks,
} );
}
}

onToggle( isOpen ) {
const { onToggle } = this.props;

// Surface toggle callback to parent component
if ( onToggle ) {
onToggle( isOpen );
}
}

render() {
const { insertBlock, getBlock } = this.props;
return (
<Dropdown
className="editor-inserter block-editor-inserter"
contentClassName="amp-stories__template-inserter__popover is-bottom editor-inserter__popover block-editor-inserter__popover"
onToggle={ this.onToggle }
expandOnMobile
renderToggle={ ( { onToggle, isOpen } ) => (
<IconButton
icon="insert"
label={ __( 'Insert Template', 'amp' ) }
onClick={ onToggle }
className="editor-inserter__amp-inserter"
aria-haspopup="true"
aria-expanded={ isOpen }
/>
) }
renderContent={ ( { onClose } ) => {
const isStoryBlock = ( clientId ) => {
const block = getBlock( clientId );
return block && storyPageBlockName === block.name;
};

const onSelect = ( item ) => {
const block = ! item ? createBlock( storyPageBlockName ) : getBlock( item.clientId );
onClose();
// Clone block to avoid duplicate ID-s.
insertBlock( cloneBlock( block ) );
};
if ( ! this.state.reusableBlocks ) {
return (
<Spinner />
);
}
const storyTemplates = this.state.reusableBlocks.filter( ( { clientId } ) => isStoryBlock( clientId ) );

return (
<div key="template-list" className="amp-stories__editor-inserter__menu">
<div
className="amp-stories__editor-inserter__results"
tabIndex="0"
role="region"
aria-label={ __( 'Available templates', 'amp' ) }
>
<div role="list" className="editor-block-types-list block-editor-block-types-list">
<div className="editor-block-preview block-editor-block-preview">
<IconButton
icon={ pageIcon }
label={ __( 'Blank Page', 'amp' ) }
onClick={ () => {
onSelect( null );
} }
className="amp-stories__blank-page-inserter editor-block-preview__content block-editor-block-preview__content editor-styles-wrapper"
/>
</div>
{ storyTemplates && storyTemplates.map( ( item ) =>
<BlockPreview
key="template-preview"
name="core/block"
attributes={ { ref: item.id } }
onClick={ () => {
onSelect( item );
} }
/>
) }
</div>
</div>
</div>
);
} }
/>
);
}
}

export default compose(
withSelect( ( select ) => {
const {
__experimentalGetReusableBlocks: getReusableBlocks,
} = select( 'core/editor' );

const {
getBlock,
getBlocks,
} = select( 'core/block-editor' );

return {
reusableBlocks: getReusableBlocks(),
getBlock,
allBlocks: getBlocks(),
};
} ),
withDispatch( ( dispatch ) => {
const {
__experimentalFetchReusableBlocks: fetchReusableBlocks,
} = dispatch( 'core/editor' );

const { insertBlock } = dispatch( 'core/block-editor' );

return {
fetchReusableBlocks,
insertBlock,
};
} )
)( TemplateInserter );
4 changes: 4 additions & 0 deletions assets/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const STORY_PAGE_WIDTH = STORY_PAGE_INNER_WIDTH + storyPageBorderWidth;

export const ALLOWED_TOP_LEVEL_BLOCKS = [
'amp/amp-story-page',
'core/block', // Reusable blocks.
'core/template', // Reusable blocks.
];

export const ALLOWED_CHILD_BLOCKS = [
Expand All @@ -50,6 +52,8 @@ export const ALLOWED_CHILD_BLOCKS = [
'core/verse',
'core/video',
'amp/amp-story-text',
'core/block', // Reusable blocks.
'core/template', // Reusable blocks.
];

export const ALLOWED_BLOCKS = [
Expand Down