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

Change the post template visually #28390

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 14 additions & 10 deletions packages/block-editor/src/components/block-preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import { memo, useMemo } from '@wordpress/element';
import BlockEditorProvider from '../provider';
import LiveBlockPreview from './live';
import AutoHeightBlockPreview from './auto';
import { BlockContextProvider } from '../block-context';

export function BlockPreview( {
blocks,
context = {},
__experimentalPadding = 0,
viewportWidth = 1200,
__experimentalLive = false,
Expand All @@ -32,16 +34,18 @@ export function BlockPreview( {
return null;
}
return (
<BlockEditorProvider value={ renderedBlocks } settings={ settings }>
{ __experimentalLive ? (
<LiveBlockPreview onClick={ __experimentalOnClick } />
) : (
<AutoHeightBlockPreview
viewportWidth={ viewportWidth }
__experimentalPadding={ __experimentalPadding }
/>
) }
</BlockEditorProvider>
<BlockContextProvider value={ context }>
<BlockEditorProvider value={ renderedBlocks } settings={ settings }>
{ __experimentalLive ? (
<LiveBlockPreview onClick={ __experimentalOnClick } />
) : (
<AutoHeightBlockPreview
viewportWidth={ viewportWidth }
__experimentalPadding={ __experimentalPadding }
/>
) }
</BlockEditorProvider>
</BlockContextProvider>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* External dependencies
*/
import { map } from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { Modal, Spinner } from '@wordpress/components';
import { store as editorStore } from '@wordpress/editor';
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
import { BlockPreview } from '@wordpress/block-editor';
import { useMemo } from '@wordpress/element';
import { parse } from '@wordpress/blocks';
import { ENTER, SPACE } from '@wordpress/keycodes';

function TemplatePreview( { slug } ) {
const { isResolved, template, postId, postType } = useSelect(
( select ) => {
const {
getCurrentTheme,
getEntityRecord,
hasFinishedResolution,
} = select( coreStore );
const { getCurrentPostId, getCurrentPostType } = select(
editorStore
);
const theme = getCurrentTheme();
const templateId = theme ? theme.stylesheet + '//' + slug : null;
const getEntityArgs = [ 'postType', 'wp_template', templateId ];
const entityRecord = templateId
? getEntityRecord( ...getEntityArgs )
: null;
const hasResolvedEntity = templateId
? hasFinishedResolution( 'getEntityRecord', getEntityArgs )
: false;

return {
template: entityRecord,
isResolved: hasResolvedEntity,
postId: getCurrentPostId(),
postType: getCurrentPostType(),
};
},
[ slug ]
);

const blocks = useMemo( () => {
if ( ! template?.content?.raw ) {
return [];
}
return parse( template.content.raw );
}, [ template ] );

const defaultBlockContext = useMemo( () => {
return { postId, postType };
}, [ postId, postType ] );

return ! isResolved ? (
<Spinner />
) : (
<BlockPreview blocks={ blocks } context={ defaultBlockContext } />
);
}

function TemplateItem( { slug, name, isSelected } ) {
const { editPost } = useDispatch( editorStore );

const onSelect = () => {
editPost( {
template: slug,
} );
};

return (
<div
className={ classnames( 'edit-post-template-change-modal__item', {
'is-selected': isSelected,
'is-default': ! slug,
} ) }
role="button"
tabIndex={ 0 }
aria-label={ name }
onClick={ onSelect }
onKeyDown={ ( event ) => {
if ( ENTER === event.keyCode || SPACE === event.keyCode ) {
onSelect();
}
} }
>
<div className="edit-post-template-change-modal__item-preview">
{ slug && <TemplatePreview slug={ slug } /> }
</div>
<div className="edit-post-template-change-modal__item-title">
{ name }
</div>
</div>
);
}

function TemplateChangeModal( { onClose } ) {
const { availableTemplates, selectedTemplate } = useSelect( ( select ) => {
const { getEditorSettings, getEditedPostAttribute } = select(
editorStore
);
const { availableTemplates: _templates } = getEditorSettings();
return {
selectedTemplate: getEditedPostAttribute( 'template' ),
availableTemplates: _templates,
};
}, [] );

return (
<Modal
className="edit-post-post-template-modal"
title={ __( 'Change Template' ) }
closeLabel={ __( 'Close' ) }
onRequestClose={ onClose }
isFullScreen
>
<div className="edit-post-template-change-modal__items">
{ map( availableTemplates, ( name, slug ) => {
return (
<TemplateItem
key={ slug }
slug={ slug }
name={ name }
isSelected={
slug === selectedTemplate ||
( ! slug && ! selectedTemplate )
}
/>
);
} ) }
</div>
</Modal>
);
}

export default TemplateChangeModal;
97 changes: 59 additions & 38 deletions packages/edit-post/src/components/sidebar/post-template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { __, sprintf } from '@wordpress/i18n';
import { PanelRow, Button } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { createInterpolateElement } from '@wordpress/element';
import { createInterpolateElement, useState } from '@wordpress/element';
import { store as editorStore } from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { store as noticesStore } from '@wordpress/notices';
Expand All @@ -13,6 +13,7 @@ import { store as noticesStore } from '@wordpress/notices';
* Internal dependencies
*/
import { store as editPostStore } from '../../../store';
import TemplateChangeModal from './change-modal';

function PostTemplate() {
const { template, isEditing, isFSETheme } = useSelect( ( select ) => {
Expand Down Expand Up @@ -44,51 +45,71 @@ function PostTemplate() {
}, [] );
const { setIsEditingTemplate } = useDispatch( editPostStore );
const { createSuccessNotice } = useDispatch( noticesStore );
const [ isChangingTemplate, setIsChangingTemplate ] = useState( false );

if ( ! isFSETheme || ! template ) {
return null;
}

return (
<PanelRow className="edit-post-post-template">
<span>{ __( 'Template' ) }</span>
{ ! isEditing && (
<span className="edit-post-post-template__value">
{ createInterpolateElement(
sprintf(
/* translators: 1: Template name. */
__( '%s (<a>Edit</a>)' ),
template.slug
),
{
a: (
<Button
isLink
onClick={ () => {
setIsEditingTemplate( true );
createSuccessNotice(
__(
'Editing template. Changes made here affect all posts and pages that use the template.'
),
{
type: 'snackbar',
}
);
} }
>
{ __( 'Edit' ) }
</Button>
<>
<PanelRow className="edit-post-post-template">
<span>{ __( 'Template' ) }</span>
{ ! isEditing && (
<span className="edit-post-post-template__value">
{ createInterpolateElement(
sprintf(
/* translators: 1: Template name. */
__(
'%s (<edit>Edit</edit> | <change>Change</change>)'
),
template.slug
),
}
) }
</span>
{
edit: (
<Button
isLink
onClick={ () => {
setIsEditingTemplate( true );
createSuccessNotice(
__(
'Editing template. Changes made here affect all posts and pages that use the template.'
),
{
type: 'snackbar',
}
);
} }
>
{ __( 'Edit' ) }
</Button>
),
change: (
<Button
isLink
onClick={ () => {
setIsChangingTemplate( true );
} }
>
{ __( 'Change' ) }
</Button>
),
}
) }
</span>
) }
{ isEditing && (
<span className="edit-post-post-template__value">
{ template.slug }
</span>
) }
</PanelRow>
{ isChangingTemplate && (
<TemplateChangeModal
onClose={ () => setIsChangingTemplate( false ) }
/>
) }
{ isEditing && (
<span className="edit-post-post-template__value">
{ template.slug }
</span>
) }
</PanelRow>
</>
);
}

Expand Down
61 changes: 61 additions & 0 deletions packages/edit-post/src/components/sidebar/post-template/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,67 @@
}
}

.edit-post-post-template-modal {
background-color: $gray-100;

@include break-small {
width: 80vw;
}
}

.edit-post-post-template__value {
padding-left: 6px;
}

.edit-post-template-change-modal__items {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 200px));
grid-gap: $grid-unit-20;
}

.edit-post-template-change-modal__item {
border-radius: $radius-block-ui;
cursor: pointer;
margin-top: $grid-unit-20;
transition: all 0.05s ease-in-out;
position: relative;
border: $border-width solid transparent;

&:hover {
border: $border-width solid var(--wp-admin-theme-color);
}

&:focus,
&.is-selected {
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);

// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 2px solid transparent;
}

&[draggable="true"] .block-editor-block-preview__container {
cursor: grab;
}
}

.edit-post-template-change-modal__item-title {
padding: $grid-unit-10 0;
font-size: 12px;
text-align: center;
font-weight: 500;
}

.edit-post-template-change-modal__item-preview {
overflow: hidden;
box-shadow: $shadow-popover;
background-color: $white;
height: 200px;
display: flex;
align-items: center;
justify-content: center;

.edit-post-template-change-modal__item.is-default & {
opacity: 0.4;
background: repeating-linear-gradient(-45deg, $gray-400, $gray-400 10px, $white 10px, $white 50px);
}
}