From ddc8dd686c7be481e453883f240c2dacdf4811aa Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 2 Jun 2023 15:34:18 +1000 Subject: [PATCH] Site Editor: Add ability to focus on editing a page's content vs the page's template (#50857) * Add ability to prevent editing blocks using useBlockEditingMode() * Make useBlockEditingMode use context * Remove rootBlockEditingMode setting * Fix private createRegistrySelector selectors * Consolidate templateLock=contentOnly logic into getBlockEditingMode * Hide disabled blocks from List View * Hide disabled blocks from breadcrumbs * Add doc comments * Add unit tests * Use @typedef to document mode param * Restore packages/components/package.json from trunk * Restore packages/block-library/src/post-title/edit.js from trunk * Move BlockListBlockContext out of block.js so that it exists on mobile platforms * Site Editor: Add ability to focus on editing a page's content vs the page's template * Show page information in DocumentActions * Implement Content panel * Prevent block overlay on disabled blocks * Fix Navigation block being selectable * Show 'Page' in breadcrumbs when focused on editing page * Update post title, post featured image, and post content blocks to say 'Page' instead of 'Post' * toolbar title styling * Remove removePostFromContentBlockLabels for now * Fix being able to select text within disabled blocks * Hide BlockAppender when block is disabled * Fix comments block in non-post templates * Update template card selector in E2E tests * Fix 'Add submenu' button in Navigation block * Remove unhelpful comments * Remove more unnecessary comments * Use constant for block types array * Use BEMish selectors * Be explicit that we're switching away from the page lock * Update removePageFromBlockContext() test * Fix post context from appearing in Edit Template preview We have to set postId and postType to null for the preview and omit them in the editor. No point having helper methods, therefore. * Clear block selection when switching from template focus to page focus * Prevent insertion into a disabled block * Don't allow removing and moving children of disabled blocks * Work around @wordpress/data bug by not using createRegistrySelector() for now * Fix typo * Fix select() mock * Fix block-editor selector tests * Revert block-editor changes * Improve useDisableNonContentBlocks performance * Fix performance tests --------- Co-authored-by: Saxon Fletcher Co-authored-by: ramon --- .../data/data-core-edit-site.md | 36 +++++ .../block-library/src/navigation/editor.scss | 26 ++-- packages/block-library/src/post-title/edit.js | 35 +++-- .../specs/performance/site-editor.test.js | 3 +- .../site-editor/settings-sidebar.test.js | 4 +- .../src/components/block-editor/index.js | 39 +++-- .../edit-site/src/components/editor/index.js | 22 ++- .../document-actions/index.js | 138 ++++++++++++++---- .../document-actions/style.scss | 32 ++-- .../components/page-content-lock/constants.js | 5 + .../src/components/page-content-lock/index.js | 14 ++ .../use-disable-non-content-blocks.js | 44 ++++++ .../use-page-content-lock-notifications.js | 128 ++++++++++++++++ .../src/components/sidebar-edit-mode/index.js | 30 ++-- .../page-panels/content-blocks-list.js | 77 ++++++++++ .../sidebar-edit-mode/page-panels/index.js | 89 +++++++++++ .../sidebar-edit-mode/page-panels/style.scss | 10 ++ .../settings-header/index.js | 79 ++++++---- .../sidebar-edit-mode/sidebar-card/index.js | 34 +++++ .../sidebar-edit-mode/sidebar-card/style.scss | 34 +++++ .../index.js | 41 +++--- .../last-revision.js} | 0 .../style.scss | 34 +---- .../template-actions.js | 0 .../template-areas.js | 0 packages/edit-site/src/store/actions.js | 18 +++ packages/edit-site/src/store/reducer.js | 20 +++ packages/edit-site/src/store/selectors.js | 24 +++ packages/edit-site/src/store/test/actions.js | 31 ++++ packages/edit-site/src/store/test/reducer.js | 44 ++++++ .../edit-site/src/store/test/selectors.js | 57 ++++++++ packages/edit-site/src/style.scss | 4 +- 32 files changed, 969 insertions(+), 183 deletions(-) create mode 100644 packages/edit-site/src/components/page-content-lock/constants.js create mode 100644 packages/edit-site/src/components/page-content-lock/index.js create mode 100644 packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js create mode 100644 packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/index.js (60%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-revisions/index.js => template-panel/last-revision.js} (100%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/style.scss (50%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/template-actions.js (100%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/template-areas.js (100%) diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index 0dad03bbc8ca2..523bb8d2bbff5 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -131,6 +131,18 @@ _Returns_ - `Object`: Settings. +### hasPageContentLock + +Whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor is locked. + ### isFeatureActive > **Deprecated** @@ -174,6 +186,22 @@ _Returns_ > **Deprecated** +### isPage + +Whether or not the editor has a page loaded into it. + +_Related_ + +- setPage + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor has a page loaded into it. + ### isSaveViewOpened Returns the current opened/closed state of the save panel. @@ -252,6 +280,14 @@ _Returns_ - `number`: The resolved template ID for the page route. +### setHasPageContentLock + +Sets whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _hasPageContentLock_ `boolean`: True to enable lock, false to disable. + ### setHomeTemplateId > **Deprecated** diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index 949a7c773eb6e..4a6a6fe6b4395 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -508,20 +508,22 @@ body.editor-styles-wrapper .wp-block-navigation__responsive-container.is-menu-op // so focus is applied naturally on the block container. // It's important the right container has focus, otherwise you can't press // "Delete" to remove the block. -.wp-block-navigation__responsive-container, -.wp-block-navigation__responsive-close { - @include break-small() { - pointer-events: none; - - .wp-block-navigation__responsive-container-close, - .block-editor-block-list__layout * { - pointer-events: all; +.wp-block-navigation:not(.is-editing-disabled) { + .wp-block-navigation__responsive-container, + .wp-block-navigation__responsive-close { + @include break-small() { + pointer-events: none; + + .wp-block-navigation__responsive-container-close, + .block-editor-block-list__layout * { + pointer-events: all; + } } - } - // Page List items should remain inert. - .wp-block-pages-list__item__link { - pointer-events: none; + // Page List items should remain inert. + .wp-block-pages-list__item__link { + pointer-events: none; + } } } diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index d7e8e2788ebe9..96fd62178b974 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -12,6 +12,7 @@ import { InspectorControls, useBlockProps, PlainText, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { ToggleControl, TextControl, PanelBody } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -23,6 +24,9 @@ import { useEntityProp } from '@wordpress/core-data'; */ import HeadingLevelDropdown from '../heading/heading-level-dropdown'; import { useCanEditEntity } from '../utils/hooks'; +import { unlock } from '../private-apis'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); export default function PostTitleEdit( { attributes: { level, textAlign, isLink, rel, linkTarget }, @@ -58,6 +62,7 @@ export default function PostTitleEdit( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ); + const blockEditingMode = useBlockEditingMode(); let titleElement = { __( 'Title' ) }; @@ -112,20 +117,22 @@ export default function PostTitleEdit( { return ( <> - - - setAttributes( { level: newLevel } ) - } - /> - { - setAttributes( { textAlign: nextAlign } ); - } } - /> - + { blockEditingMode === 'default' && ( + + + setAttributes( { level: newLevel } ) + } + /> + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + + ) } { await enterEditMode(); // Insert a new paragraph right under the first one. - await firstParagraph.focus(); + await firstParagraph.click(); // Once to select the block overlay. + await firstParagraph.click(); // Once again to select the paragraph. await insertBlock( 'Paragraph' ); // Start tracing. diff --git a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js index 88bf954e86ce2..ae28019cf0d99 100644 --- a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js +++ b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js @@ -27,11 +27,11 @@ async function getActiveTabLabel() { async function getTemplateCard() { return { title: await page.$eval( - '.edit-site-template-card__title', + '.edit-site-sidebar-card__title', ( element ) => element.innerText ), description: await page.$eval( - '.edit-site-template-card__description', + '.edit-site-sidebar-card__description', ( element ) => element.innerText ), }; diff --git a/packages/edit-site/src/components/block-editor/index.js b/packages/edit-site/src/components/block-editor/index.js index cc5e7c8d9254d..a2409b3f1baa2 100644 --- a/packages/edit-site/src/components/block-editor/index.js +++ b/packages/edit-site/src/components/block-editor/index.js @@ -38,6 +38,10 @@ import ResizableEditor from './resizable-editor'; import EditorCanvas from './editor-canvas'; import { unlock } from '../../private-apis'; import EditorCanvasContainer from '../editor-canvas-container'; +import { + PageContentLock, + usePageContentLockNotifications, +} from '../page-content-lock'; const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); @@ -49,20 +53,25 @@ const LAYOUT = { export default function BlockEditor() { const { setIsInserterOpened } = useDispatch( editSiteStore ); - const { storedSettings, templateType, canvasMode } = useSelect( - ( select ) => { - const { getSettings, getEditedPostType, getCanvasMode } = unlock( - select( editSiteStore ) - ); - - return { - storedSettings: getSettings( setIsInserterOpened ), - templateType: getEditedPostType(), - canvasMode: getCanvasMode(), - }; - }, - [ setIsInserterOpened ] - ); + const { storedSettings, templateType, canvasMode, hasPageContentLock } = + useSelect( + ( select ) => { + const { + getSettings, + getEditedPostType, + getCanvasMode, + hasPageContentLock: _hasPageContentLock, + } = unlock( select( editSiteStore ) ); + + return { + storedSettings: getSettings( setIsInserterOpened ), + templateType: getEditedPostType(), + canvasMode: getCanvasMode(), + hasPageContentLock: _hasPageContentLock(), + }; + }, + [ setIsInserterOpened ] + ); const settingsBlockPatterns = storedSettings.__experimentalAdditionalBlockPatterns ?? // WP 6.0 @@ -137,6 +146,7 @@ export default function BlockEditor() { contentRef, useClipboardHandler(), useTypingObserver(), + usePageContentLockNotifications(), ] ); const isMobileViewport = useViewportMatch( 'small', '<' ); const { clearSelectedBlock } = useDispatch( blockEditorStore ); @@ -162,6 +172,7 @@ export default function BlockEditor() { onChange={ onChange } useSubRegistry={ false } > + { hasPageContentLock && } diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 72a8d41fb22f0..f70c6abd787d4 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -37,7 +37,6 @@ import WelcomeGuide from '../welcome-guide'; import StartTemplateOptions from '../start-template-options'; import { store as editSiteStore } from '../../store'; import { GlobalStylesRenderer } from '../global-styles-renderer'; - import useTitle from '../routes/use-title'; import CanvasSpinner from '../canvas-spinner'; import { unlock } from '../../private-apis'; @@ -74,6 +73,7 @@ export default function Editor( { isLoading } ) { isListViewOpen, showIconLabels, showBlockBreadcrumbs, + hasPageContentLock, } = useSelect( ( select ) => { const { getEditedPostContext, @@ -81,6 +81,7 @@ export default function Editor( { isLoading } ) { getCanvasMode, isInserterOpened, isListViewOpened, + hasPageContentLock: _hasPageContentLock, } = unlock( select( editSiteStore ) ); const { __unstableGetEditorMode } = select( blockEditorStore ); const { getActiveComplementaryArea } = select( interfaceStore ); @@ -105,6 +106,7 @@ export default function Editor( { isLoading } ) { 'core/edit-site', 'showBlockBreadcrumbs' ), + hasPageContentLock: _hasPageContentLock(), }; }, [] ); const { setEditedPostContext } = useDispatch( editSiteStore ); @@ -122,9 +124,10 @@ export default function Editor( { isLoading } ) { const secondarySidebarLabel = isListViewOpen ? __( 'List View' ) : __( 'Block Library' ); - const blockContext = useMemo( - () => ( { - ...context, + const blockContext = useMemo( () => { + const { postType, postId, ...nonPostFields } = context ?? {}; + return { + ...( hasPageContentLock ? context : nonPostFields ), queryContext: [ context?.queryContext || { page: 1 }, ( newQueryContext ) => @@ -136,9 +139,8 @@ export default function Editor( { isLoading } ) { }, } ), ], - } ), - [ context, setEditedPostContext ] - ); + }; + }, [ hasPageContentLock, context, setEditedPostContext ] ); let title; if ( hasLoadedPost ) { @@ -227,7 +229,11 @@ export default function Editor( { isLoading } ) { footer={ shouldShowBlockBreakcrumbs && ( ) } diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index 94f8358fda993..a23c9c3595d32 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -1,8 +1,13 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { sprintf, __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { Button, VisuallyHidden, @@ -11,6 +16,11 @@ import { } from '@wordpress/components'; import { BlockIcon } from '@wordpress/block-editor'; import { privateApis as commandsPrivateApis } from '@wordpress/commands'; +import { + chevronLeftSmall as chevronLeftSmallIcon, + page as pageIcon, +} from '@wordpress/icons'; +import { useEntityRecord } from '@wordpress/core-data'; import { displayShortcut } from '@wordpress/keycodes'; /** @@ -18,19 +28,62 @@ import { displayShortcut } from '@wordpress/keycodes'; */ import useEditedEntityRecord from '../../use-edited-entity-record'; import { unlock } from '../../../private-apis'; +import { store as editSiteStore } from '../../../store'; const { store: commandsStore } = unlock( commandsPrivateApis ); export default function DocumentActions() { - const { open: openCommandCenter } = useDispatch( commandsStore ); + const isPage = useSelect( ( select ) => select( editSiteStore ).isPage() ); + return isPage ? : ; +} + +function PageDocumentActions() { + const { hasPageContentLock, context } = useSelect( + ( select ) => ( { + hasPageContentLock: select( editSiteStore ).hasPageContentLock(), + context: select( editSiteStore ).getEditedPostContext(), + } ), + [] + ); + + const { hasResolved, editedRecord } = useEntityRecord( + 'postType', + context.postType, + context.postId + ); + + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + if ( ! hasResolved ) { + return null; + } + + if ( ! editedRecord ) { + return ( +
+ { __( 'Document not found' ) } +
+ ); + } + + return hasPageContentLock ? ( + + { editedRecord.title } + + ) : ( + setHasPageContentLock( true ) } + /> + ); +} + +function TemplateDocumentActions( { onBack } ) { const { isLoaded, record, getTitle, icon } = useEditedEntityRecord(); - // Return a simple loading indicator until we have information to show. if ( ! isLoaded ) { return null; } - // Return feedback that the template does not seem to exist. if ( ! record ) { return (
@@ -45,31 +98,58 @@ export default function DocumentActions() { : __( 'template' ); return ( - + ) } + + + + + { children } + + + + { displayShortcut.primary( 'k' ) } + + +
); } diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss index 247b901975fd8..8bd3475de6956 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss @@ -1,10 +1,7 @@ .edit-site-document-actions { - display: flex; - align-items: center; - gap: $grid-unit; + display: grid; + grid-template-columns: 1fr 2fr 1fr; height: $button-size; - padding: $grid-unit; - justify-content: space-between; // Flex items will, by default, refuse to shrink below a minimum // intrinsic width. In order to shrink this flexbox item, and // subsequently truncate child text, we set an explicit min-width. @@ -20,29 +17,46 @@ } } +.edit-site-document-actions__command { + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 2fr 1fr; + grid-row: 1; +} + + .edit-site-document-actions__title { flex-grow: 1; color: var(--wp-block-synced-color); overflow: hidden; + grid-column: 2 / 3; + &.is-page { + color: $gray-800; + h1 { + color: $gray-800; + } + } h1 { - color: var(--wp-block-synced-color); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + color: var(--wp-block-synced-color); } } .edit-site-document-actions__shortcut { - flex-shrink: 0; color: $gray-700; - width: #{$grid-unit * 4.5}; + text-align: right; &:hover { color: $gray-700; } } -.edit-site-document-actions__left { +.edit-site-document-actions__back { min-width: $button-size; flex-shrink: 0; + grid-column: 1 / 2; + grid-row: 1; + z-index: 1; } diff --git a/packages/edit-site/src/components/page-content-lock/constants.js b/packages/edit-site/src/components/page-content-lock/constants.js new file mode 100644 index 0000000000000..668fe8af00d69 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/constants.js @@ -0,0 +1,5 @@ +export const CONTENT_BLOCK_TYPES = [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', +]; diff --git a/packages/edit-site/src/components/page-content-lock/index.js b/packages/edit-site/src/components/page-content-lock/index.js new file mode 100644 index 0000000000000..83d096fb39f5d --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/index.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import { useDisableNonContentBlocks } from './use-disable-non-content-blocks'; + +/** + * Component that when rendered, locks the site editor so that only page content + * can be edited. + */ +export function PageContentLock() { + useDisableNonContentBlocks(); +} + +export { usePageContentLockNotifications } from './use-page-content-lock-notifications'; diff --git a/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js new file mode 100644 index 0000000000000..ce198909877f6 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js @@ -0,0 +1,44 @@ +/** + * WordPress dependencies + */ +import { createHigherOrderComponent } from '@wordpress/compose'; +import { addFilter, removeFilter } from '@wordpress/hooks'; +import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { unlock } from '../../private-apis'; +import { CONTENT_BLOCK_TYPES } from './constants'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); + +/** + * Disables non-content blocks using the `useBlockEditingMode` hook. + */ +export function useDisableNonContentBlocks() { + useBlockEditingMode( 'disabled' ); + useEffect( () => { + addFilter( + 'editor.BlockEdit', + 'core/edit-site/disable-non-content-blocks', + withDisableNonContentBlocks + ); + return () => + removeFilter( + 'editor.BlockEdit', + 'core/edit-site/disable-non-content-blocks' + ); + }, [] ); +} + +const withDisableNonContentBlocks = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + const isContent = CONTENT_BLOCK_TYPES.includes( props.name ); + const mode = isContent ? 'contentOnly' : undefined; + useBlockEditingMode( mode ); + return ; + }, + 'withBlockEditingMode' +); diff --git a/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js new file mode 100644 index 0000000000000..2a800317a33a9 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js @@ -0,0 +1,128 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect, useRef } from '@wordpress/element'; +import { store as noticesStore } from '@wordpress/notices'; +import { __ } from '@wordpress/i18n'; +import { useRefEffect } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../store'; + +/** + * Hook that displays notifications that guide the user towards using the + * content vs. template editing modes. + * + * @return {import('react').RefObject} Ref which should be passed + * (using useMergeRefs()) to + * the editor iframe canvas. + */ +export function usePageContentLockNotifications() { + const ref = useEditTemplateNotification(); + useBackToPageNotification(); + return ref; +} + +/** + * Hook that displays a 'Edit your template to edit this block' notification + * when the user is focusing on editing page content and clicks on a locked + * template block. + * + * @return {import('react').RefObject} Ref which should be passed + * (using useMergeRefs()) to + * the editor iframe canvas. + */ +function useEditTemplateNotification() { + const hasPageContentLock = useSelect( + ( select ) => select( editSiteStore ).hasPageContentLock(), + [] + ); + + const alreadySeen = useRef( false ); + + const { createInfoNotice } = useDispatch( noticesStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + return useRefEffect( + ( node ) => { + const handleClick = ( event ) => { + if ( + ! alreadySeen.current && + hasPageContentLock && + event.target.classList.contains( 'is-root-container' ) + ) { + createInfoNotice( + __( 'Edit your template to edit this block' ), + { + isDismissible: true, + type: 'snackbar', + actions: [ + { + label: __( 'Edit template' ), + onClick: () => + setHasPageContentLock( false ), + }, + ], + } + ); + alreadySeen.current = true; + } + }; + node.addEventListener( 'click', handleClick ); + return () => node.removeEventListener( 'click', handleClick ); + }, + [ + hasPageContentLock, + alreadySeen, + createInfoNotice, + setHasPageContentLock, + ] + ); +} + +/** + * Hook that displays a 'You are editing a template' notification when the user + * switches from focusing on editing page content to editing a template. + */ +function useBackToPageNotification() { + const hasPageContentLock = useSelect( + ( select ) => select( editSiteStore ).hasPageContentLock(), + [] + ); + + const alreadySeen = useRef( false ); + const prevHasPageContentLock = useRef( false ); + + const { createInfoNotice } = useDispatch( noticesStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + useEffect( () => { + if ( + ! alreadySeen.current && + prevHasPageContentLock.current && + ! hasPageContentLock + ) { + createInfoNotice( __( 'You are editing a template' ), { + isDismissible: true, + type: 'snackbar', + actions: [ + { + label: __( 'Back to page' ), + onClick: () => setHasPageContentLock( true ), + }, + ], + } ); + alreadySeen.current = true; + } + prevHasPageContentLock.current = hasPageContentLock; + }, [ + alreadySeen, + prevHasPageContentLock, + hasPageContentLock, + createInfoNotice, + setHasPageContentLock, + ] ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/index.js b/packages/edit-site/src/components/sidebar-edit-mode/index.js index 5086981f87144..78ada88a4d5fa 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { createSlotFill, PanelBody, PanelRow } from '@wordpress/components'; +import { createSlotFill } from '@wordpress/components'; import { isRTL, __ } from '@wordpress/i18n'; import { drawerLeft, drawerRight } from '@wordpress/icons'; import { useEffect } from '@wordpress/element'; @@ -16,8 +16,8 @@ import DefaultSidebar from './default-sidebar'; import GlobalStylesSidebar from './global-styles-sidebar'; import { STORE_NAME } from '../../store/constants'; import SettingsHeader from './settings-header'; -import LastRevision from './template-revisions'; -import TemplateCard from './template-card'; +import PagePanels from './page-panels'; +import TemplatePanel from './template-panel'; import PluginTemplateSettingPanel from '../plugin-template-setting-panel'; import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from './constants'; import { store as editSiteStore } from '../../store'; @@ -33,6 +33,7 @@ export function SidebarComplementaryAreaFills() { isEditorSidebarOpened, hasBlockSelection, supportsGlobalStyles, + hasPageContentLock, } = useSelect( ( select ) => { const _sidebar = select( interfaceStore ).getActiveComplementaryArea( STORE_NAME ); @@ -47,18 +48,23 @@ export function SidebarComplementaryAreaFills() { hasBlockSelection: !! select( blockEditorStore ).getBlockSelectionStart(), supportsGlobalStyles: ! settings?.supportsTemplatePartsMode, + hasPageContentLock: select( editSiteStore ).hasPageContentLock(), }; }, [] ); const { enableComplementaryArea } = useDispatch( interfaceStore ); useEffect( () => { - if ( ! isEditorSidebarOpened ) return; + // Don't automatically switch tab when the sidebar is closed or when we + // are focused on page content. + if ( ! isEditorSidebarOpened || hasPageContentLock ) { + return; + } if ( hasBlockSelection ) { enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK ); } else { enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); } - }, [ hasBlockSelection, isEditorSidebarOpened ] ); + }, [ hasBlockSelection, isEditorSidebarOpened, hasPageContentLock ] ); let sidebarName = sidebar; if ( ! isEditorSidebarOpened ) { @@ -77,15 +83,11 @@ export function SidebarComplementaryAreaFills() { > { sidebarName === SIDEBAR_TEMPLATE && ( <> - - - - - - + { hasPageContentLock ? ( + + ) : ( + + ) } ) } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js new file mode 100644 index 0000000000000..9035c5677f91a --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js @@ -0,0 +1,77 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { + Button, + __experimentalVStack as VStack, + __experimentalHStack as HStack, + FlexItem, +} from '@wordpress/components'; +import { getBlockType, __experimentalGetBlockLabel } from '@wordpress/blocks'; +import { store as blockEditorStore, BlockIcon } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { CONTENT_BLOCK_TYPES } from '../../page-content-lock/constants'; + +// TODO: This overlaps a lot with BlockInspectorLockedBlocks in +// @wordpress/block-editor. DRY them into a single component. +export default function ContentBlocksList() { + const contentBlocks = useSelect( ( select ) => { + const { + getClientIdsWithDescendants, + getBlockName, + getBlock, + isBlockSelected, + hasSelectedInnerBlock, + } = select( blockEditorStore ); + return getClientIdsWithDescendants().flatMap( ( clientId ) => { + const blockName = getBlockName( clientId ); + if ( ! CONTENT_BLOCK_TYPES.includes( blockName ) ) { + return []; + } + return [ + { + block: getBlock( clientId ), + isSelected: + isBlockSelected( clientId ) || + hasSelectedInnerBlock( clientId, /* deep: */ true ), + }, + ]; + } ); + }, [] ); + + const { selectBlock } = useDispatch( blockEditorStore ); + + if ( ! contentBlocks.length ) { + return null; + } + + return ( + + { contentBlocks.map( ( { block, isSelected } ) => { + const blockType = getBlockType( block.name ); + return ( + + ); + } ) } + + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js new file mode 100644 index 0000000000000..c913a689d54dc --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -0,0 +1,89 @@ +/** + * WordPress dependencies + */ +import { + PanelBody, + __experimentalVStack as VStack, + Button, +} from '@wordpress/components'; +import { page as pageIcon } from '@wordpress/icons'; +import { __, sprintf } from '@wordpress/i18n'; +import { humanTimeDiff } from '@wordpress/date'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEntityRecord } from '@wordpress/core-data'; +import { BlockContextProvider, BlockPreview } from '@wordpress/block-editor'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../../store'; +import useEditedEntityRecord from '../../use-edited-entity-record'; +import SidebarCard from '../sidebar-card'; +import ContentBlocksList from './content-blocks-list'; + +export default function PagePanels() { + const context = useSelect( + ( select ) => select( editSiteStore ).getEditedPostContext(), + [] + ); + + const { hasResolved: hasPageResolved, editedRecord: page } = + useEntityRecord( 'postType', context.postType, context.postId ); + + const { + isLoaded: isTemplateLoaded, + getTitle: getTemplateTitle, + record: template, + } = useEditedEntityRecord(); + + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + const blockContext = useMemo( + () => ( { ...context, postType: null, postId: null } ), + [ context ] + ); + + if ( ! hasPageResolved || ! isTemplateLoaded ) { + return null; + } + + return ( + <> + + + + + + + + +
{ getTemplateTitle() }
+
+ + + +
+ +
+
+ + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss new file mode 100644 index 0000000000000..58178303e48e5 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -0,0 +1,10 @@ +.edit-site-page-panels__edit-template-preview { + border: 1px solid $gray-200; + height: 200px; + max-height: 200px; + overflow: hidden; +} + +.edit-site-page-panels__edit-template-button { + justify-content: center; +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js b/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js index 8e5e80d9fecc5..b11d9acb2314f 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js @@ -1,9 +1,14 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { store as interfaceStore } from '@wordpress/interface'; /** @@ -11,27 +16,35 @@ import { store as interfaceStore } from '@wordpress/interface'; */ import { STORE_NAME } from '../../../store/constants'; import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from '../constants'; +import { store as editSiteStore } from '../../../store'; const SettingsHeader = ( { sidebarName } ) => { + const hasPageContentLock = useSelect( ( select ) => + select( editSiteStore ).hasPageContentLock() + ); + const { enableComplementaryArea } = useDispatch( interfaceStore ); const openTemplateSettings = () => enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); const openBlockSettings = () => enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK ); - const [ templateAriaLabel, templateActiveClass ] = - sidebarName === SIDEBAR_TEMPLATE - ? // translators: ARIA label for the Template sidebar tab, selected. - [ __( 'Template (selected)' ), 'is-active' ] - : // translators: ARIA label for the Template Settings Sidebar tab, not selected. - [ __( 'Template' ), '' ]; - - const [ blockAriaLabel, blockActiveClass ] = - sidebarName === SIDEBAR_BLOCK - ? // translators: ARIA label for the Block Settings Sidebar tab, selected. - [ __( 'Block (selected)' ), 'is-active' ] - : // translators: ARIA label for the Block Settings Sidebar tab, not selected. - [ __( 'Block' ), '' ]; + let templateAriaLabel; + if ( hasPageContentLock ) { + templateAriaLabel = + sidebarName === SIDEBAR_TEMPLATE + ? // translators: ARIA label for the Template sidebar tab, selected. + __( 'Page (selected)' ) + : // translators: ARIA label for the Template Settings Sidebar tab, not selected. + __( 'Page' ); + } else { + templateAriaLabel = + sidebarName === SIDEBAR_TEMPLATE + ? // translators: ARIA label for the Template sidebar tab, selected. + __( 'Template (selected)' ) + : // translators: ARIA label for the Template Settings Sidebar tab, not selected. + __( 'Template' ); + } /* Use a list so screen readers will announce how many tabs there are. */ return ( @@ -39,29 +52,39 @@ const SettingsHeader = ( { sidebarName } ) => {
  • diff --git a/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js new file mode 100644 index 0000000000000..04e8d5667a2c2 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js @@ -0,0 +1,34 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { Icon } from '@wordpress/components'; + +export default function SidebarCard( { + className, + title, + icon, + description, + actions, + children, +} ) { + return ( +
    + +
    +
    +

    { title }

    + { actions } +
    +
    + { description } +
    + { children } +
    +
    + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss new file mode 100644 index 0000000000000..718fe8fb5a0fb --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss @@ -0,0 +1,34 @@ +.edit-site-sidebar-card { + display: flex; + align-items: flex-start; + + &__content { + flex-grow: 1; + margin-bottom: $grid-unit-05; + } + + &__title { + font-weight: 500; + line-height: $icon-size; + &.edit-site-sidebar-card__title { + margin: 0; + } + } + + &__description { + font-size: $default-font-size; + } + + &__icon { + flex: 0 0 $icon-size; + margin-right: $grid-unit-15; + width: $icon-size; + height: $icon-size; + } + + &__header { + display: flex; + justify-content: space-between; + margin: 0 0 $grid-unit-05; + } +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js similarity index 60% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js index d43dca3b803f5..1c369703be5d7 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js @@ -2,10 +2,11 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { Icon } from '@wordpress/components'; +import { PanelRow, PanelBody } from '@wordpress/components'; import { store as editorStore } from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -13,8 +14,10 @@ import { decodeEntities } from '@wordpress/html-entities'; import { store as editSiteStore } from '../../../store'; import TemplateActions from './template-actions'; import TemplateAreas from './template-areas'; +import LastRevision from './last-revision'; +import SidebarCard from '../sidebar-card'; -export default function TemplateCard() { +export default function TemplatePanel() { const { info: { title, description, icon }, template, @@ -38,22 +41,22 @@ export default function TemplateCard() { } return ( - <> -
    - -
    -
    -

    - { decodeEntities( title ) } -

    - -
    -
    - { decodeEntities( description ) } -
    - -
    -
    - + + } + > + + + + + + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-revisions/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/last-revision.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-revisions/index.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/last-revision.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss similarity index 50% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss index 67054c25d2476..4c8ef94855dcb 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss @@ -1,30 +1,6 @@ .edit-site-template-card { - display: flex; - align-items: flex-start; - - &__content { - flex-grow: 1; - margin-bottom: $grid-unit-05; - } - - &__title { - font-weight: 500; - line-height: $icon-size; - &.edit-site-template-card__title { - margin: 0; - } - } - - &__description { - font-size: $default-font-size; - margin: 0 0 $grid-unit-20; - } - - &__icon { - flex: 0 0 $icon-size; - margin-right: $grid-unit-15; - width: $icon-size; - height: $icon-size; + &__template-areas { + margin-top: $grid-unit-20; } &__template-areas-list { @@ -44,12 +20,6 @@ } } - &__header { - display: flex; - justify-content: space-between; - margin: 0 0 $grid-unit-05; - } - &__actions { line-height: 0; > .components-button.is-small.has-icon { diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/template-actions.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-actions.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/template-actions.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-actions.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/template-areas.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-areas.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/template-areas.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-areas.js diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index a67406349e164..67fbec4811db4 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -530,3 +530,21 @@ export const switchEditorMode = speak( __( 'Code editor selected' ), 'assertive' ); } }; + +/** + * Sets whether or not the editor is locked so that only page content can be + * edited. + * + * @param {boolean} hasPageContentLock True to enable lock, false to disable. + */ +export const setHasPageContentLock = + ( hasPageContentLock ) => + ( { dispatch, registry } ) => { + if ( hasPageContentLock ) { + registry.dispatch( blockEditorStore ).clearSelectedBlock(); + } + dispatch( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock, + } ); + }; diff --git a/packages/edit-site/src/store/reducer.js b/packages/edit-site/src/store/reducer.js index a46d215f90507..a003ee958894e 100644 --- a/packages/edit-site/src/store/reducer.js +++ b/packages/edit-site/src/store/reducer.js @@ -157,6 +157,25 @@ function editorCanvasContainerView( state = undefined, action ) { return state; } +/** + * Reducer used to track whether the page content is locked. + * + * @param {boolean} state Current state. + * @param {Object} action Dispatched action. + * + * @return {boolean} Updated state. + */ +export function hasPageContentLock( state = false, action ) { + switch ( action.type ) { + case 'SET_EDITED_POST': + return !! action.context?.postId; + case 'SET_HAS_PAGE_CONTENT_LOCK': + return action.hasPageContentLock; + } + + return state; +} + export default combineReducers( { deviceType, settings, @@ -166,4 +185,5 @@ export default combineReducers( { saveViewPanel, canvasMode, editorCanvasContainerView, + hasPageContentLock, } ); diff --git a/packages/edit-site/src/store/selectors.js b/packages/edit-site/src/store/selectors.js index 583f37b55241b..16b6dc588ea26 100644 --- a/packages/edit-site/src/store/selectors.js +++ b/packages/edit-site/src/store/selectors.js @@ -321,3 +321,27 @@ export function isNavigationOpened() { version: '6.4', } ); } + +/** + * Whether or not the editor has a page loaded into it. + * + * @see setPage + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether or not the editor has a page loaded into it. + */ +export function isPage( state ) { + return !! state.editedPost.context?.postId; +} + +/** + * Whether or not the editor is locked so that only page content can be edited. + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether or not the editor is locked. + */ +export function hasPageContentLock( state ) { + return isPage( state ) ? state.hasPageContentLock : false; +} diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js index 2df1cc72b6611..cca479e277662 100644 --- a/packages/edit-site/src/store/test/actions.js +++ b/packages/edit-site/src/store/test/actions.js @@ -13,6 +13,7 @@ import { store as preferencesStore } from '@wordpress/preferences'; * Internal dependencies */ import { store as editSiteStore } from '..'; +import { setHasPageContentLock } from '../actions'; const ENTITY_TYPES = { wp_template: { @@ -215,4 +216,34 @@ describe( 'actions', () => { ); } ); } ); + + describe( 'setHasPageContentLock', () => { + it( 'toggles the page content lock on', () => { + const dispatch = jest.fn(); + const clearSelectedBlock = jest.fn(); + const registry = { + dispatch: () => ( { clearSelectedBlock } ), + }; + setHasPageContentLock( true )( { dispatch, registry } ); + expect( clearSelectedBlock ).toHaveBeenCalled(); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: true, + } ); + } ); + + it( 'toggles the page content lock off', () => { + const dispatch = jest.fn(); + const clearSelectedBlock = jest.fn(); + const registry = { + dispatch: () => ( { clearSelectedBlock } ), + }; + setHasPageContentLock( false )( { dispatch, registry } ); + expect( clearSelectedBlock ).not.toHaveBeenCalled(); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: false, + } ); + } ); + } ); } ); diff --git a/packages/edit-site/src/store/test/reducer.js b/packages/edit-site/src/store/test/reducer.js index f6ce205ad6353..1ddc6bfb6fa7b 100644 --- a/packages/edit-site/src/store/test/reducer.js +++ b/packages/edit-site/src/store/test/reducer.js @@ -11,6 +11,7 @@ import { editedPost, blockInserterPanel, listViewPanel, + hasPageContentLock, } from '../reducer'; import { setIsInserterOpened, setIsListViewOpened } from '../actions'; @@ -135,4 +136,47 @@ describe( 'state', () => { ); } ); } ); + + describe( 'hasPageContentLocked()', () => { + it( 'defaults to false', () => { + expect( hasPageContentLock( undefined, {} ) ).toBe( false ); + } ); + + it( 'becomes false when editing a template', () => { + expect( + hasPageContentLock( true, { + type: 'SET_EDITED_POST', + postType: 'wp_template', + } ) + ).toBe( false ); + } ); + + it( 'becomes true when editing a page', () => { + expect( + hasPageContentLock( false, { + type: 'SET_EDITED_POST', + postType: 'wp_template', + context: { + postType: 'page', + postId: 123, + }, + } ) + ).toBe( true ); + } ); + + it( 'can be set', () => { + expect( + hasPageContentLock( false, { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: true, + } ) + ).toBe( true ); + expect( + hasPageContentLock( true, { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: false, + } ) + ).toBe( false ); + } ); + } ); } ); diff --git a/packages/edit-site/src/store/test/selectors.js b/packages/edit-site/src/store/test/selectors.js index 223bcd1f0ba04..d9ed31411ffcc 100644 --- a/packages/edit-site/src/store/test/selectors.js +++ b/packages/edit-site/src/store/test/selectors.js @@ -15,6 +15,8 @@ import { isInserterOpened, isListViewOpened, __unstableGetPreference, + isPage, + hasPageContentLock, } from '../selectors'; describe( 'selectors', () => { @@ -145,4 +147,59 @@ describe( 'selectors', () => { expect( isListViewOpened( state ) ).toBe( false ); } ); } ); + + describe( 'isPage', () => { + it( 'returns true if the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + }; + expect( isPage( state ) ).toBe( true ); + } ); + + it( 'returns false if the edited post type is a template', () => { + const state = { + editedPost: { + postType: 'wp_template', + }, + }; + expect( isPage( state ) ).toBe( false ); + } ); + } ); + + describe( 'hasPageContentLock', () => { + it( 'returns true if locked and the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + hasPageContentLock: true, + }; + expect( hasPageContentLock( state ) ).toBe( true ); + } ); + + it( 'returns false if not locked and the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + hasPageContentLock: false, + }; + expect( hasPageContentLock( state ) ).toBe( false ); + } ); + + it( 'returns false if locked and the edited post type is a template', () => { + const state = { + editedPost: { + postType: 'wp_template', + }, + hasPageContentLock: true, + }; + expect( hasPageContentLock( state ) ).toBe( false ); + } ); + } ); } ); diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 3e2b34ea65f5f..e31978cf0f45d 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -10,8 +10,10 @@ @import "./components/header-edit-mode/document-actions/style.scss"; @import "./components/list/style.scss"; @import "./components/sidebar-edit-mode/style.scss"; +@import "./components/sidebar-edit-mode/page-panels/style.scss"; @import "./components/sidebar-edit-mode/settings-header/style.scss"; -@import "./components/sidebar-edit-mode/template-card/style.scss"; +@import "./components/sidebar-edit-mode/sidebar-card/style.scss"; +@import "./components/sidebar-edit-mode/template-panel/style.scss"; @import "./components/editor/style.scss"; @import "./components/create-template-part-modal/style.scss"; @import "./components/secondary-sidebar/style.scss";