-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Site Editor: Add template tab to sidebar (#28633)
- Loading branch information
1 parent
5401bf2
commit 5dcaad4
Showing
9 changed files
with
371 additions
and
5 deletions.
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
packages/e2e-tests/specs/experiments/settings-sidebar.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
trashAllPosts, | ||
activateTheme, | ||
getAllBlocks, | ||
selectBlockByClientId, | ||
} from '@wordpress/e2e-test-utils'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { navigationPanel, siteEditor } from '../../experimental-features'; | ||
|
||
async function toggleSidebar() { | ||
await page.click( | ||
'.edit-site-header__actions button[aria-label="Settings"]' | ||
); | ||
} | ||
|
||
async function getActiveTabLabel() { | ||
return await page.$eval( | ||
'.edit-site-sidebar__panel-tab.is-active', | ||
( element ) => element.getAttribute( 'aria-label' ) | ||
); | ||
} | ||
|
||
async function getTemplateCard() { | ||
return { | ||
title: await page.$eval( | ||
'.edit-site-template-card__title', | ||
( element ) => element.innerText | ||
), | ||
description: await page.$eval( | ||
'.edit-site-template-card__description', | ||
( element ) => element.innerText | ||
), | ||
}; | ||
} | ||
|
||
describe( 'Settings sidebar', () => { | ||
beforeAll( async () => { | ||
await activateTheme( 'tt1-blocks' ); | ||
await trashAllPosts( 'wp_template' ); | ||
await trashAllPosts( 'wp_template_part' ); | ||
} ); | ||
afterAll( async () => { | ||
await trashAllPosts( 'wp_template' ); | ||
await trashAllPosts( 'wp_template_part' ); | ||
await activateTheme( 'twentytwentyone' ); | ||
} ); | ||
beforeEach( async () => { | ||
await siteEditor.visit(); | ||
} ); | ||
|
||
describe( 'Template tab', () => { | ||
it( 'should open template tab by default if no block is selected', async () => { | ||
await toggleSidebar(); | ||
|
||
expect( await getActiveTabLabel() ).toEqual( | ||
'Template (selected)' | ||
); | ||
} ); | ||
|
||
it( "should show the currently selected template's title and description", async () => { | ||
await toggleSidebar(); | ||
|
||
const templateCardBeforeNavigation = await getTemplateCard(); | ||
await navigationPanel.open(); | ||
await navigationPanel.backToRoot(); | ||
await navigationPanel.navigate( 'Templates' ); | ||
await navigationPanel.clickItemByText( '404' ); | ||
await navigationPanel.close(); | ||
const templateCardAfterNavigation = await getTemplateCard(); | ||
|
||
expect( templateCardBeforeNavigation ).toMatchObject( { | ||
title: 'Index', | ||
description: | ||
'The default template which is used when no other template can be found', | ||
} ); | ||
expect( templateCardAfterNavigation ).toMatchObject( { | ||
title: '404', | ||
description: 'Used when the queried content cannot be found', | ||
} ); | ||
} ); | ||
} ); | ||
|
||
describe( 'Block tab', () => { | ||
it( 'should open block tab by default if a block is selected', async () => { | ||
const allBlocks = await getAllBlocks(); | ||
await selectBlockByClientId( allBlocks[ 0 ].clientId ); | ||
|
||
await toggleSidebar(); | ||
// TODO: Remove when toolbar supports text fields | ||
expect( console ).toHaveWarnedWith( | ||
'Using custom components as toolbar controls is deprecated. Please use ToolbarItem or ToolbarButton components instead. See: https://developer.wordpress.org/block-editor/components/toolbar-button/#inside-blockcontrols' | ||
); | ||
expect( await getActiveTabLabel() ).toEqual( 'Block (selected)' ); | ||
} ); | ||
} ); | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const SIDEBAR_TEMPLATE = 'edit-site/template'; | ||
export const SIDEBAR_BLOCK = 'edit-site/block-inspector'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
packages/edit-site/src/components/sidebar/settings-header/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Button } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { useDispatch } from '@wordpress/data'; | ||
import { store as interfaceStore } from '@wordpress/interface'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { STORE_NAME } from '../../../store/constants'; | ||
import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from '../constants'; | ||
|
||
const SettingsHeader = ( { sidebarName } ) => { | ||
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' ), '' ]; | ||
|
||
/* Use a list so screen readers will announce how many tabs there are. */ | ||
return ( | ||
<ul> | ||
<li> | ||
<Button | ||
onClick={ openTemplateSettings } | ||
className={ `edit-site-sidebar__panel-tab ${ templateActiveClass }` } | ||
aria-label={ templateAriaLabel } | ||
// translators: Data label for the Template Settings Sidebar tab. | ||
data-label={ __( 'Template' ) } | ||
> | ||
{ | ||
// translators: Text label for the Template Settings Sidebar tab. | ||
__( 'Template' ) | ||
} | ||
</Button> | ||
</li> | ||
<li> | ||
<Button | ||
onClick={ openBlockSettings } | ||
className={ `edit-site-sidebar__panel-tab ${ blockActiveClass }` } | ||
aria-label={ blockAriaLabel } | ||
// translators: Data label for the Block Settings Sidebar tab. | ||
data-label={ __( 'Block' ) } | ||
> | ||
{ | ||
// translators: Text label for the Block Settings Sidebar tab. | ||
__( 'Block' ) | ||
} | ||
</Button> | ||
</li> | ||
</ul> | ||
); | ||
}; | ||
|
||
export default SettingsHeader; |
80 changes: 80 additions & 0 deletions
80
packages/edit-site/src/components/sidebar/settings-header/style.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
.components-panel__header.edit-site-sidebar__panel-tabs { | ||
justify-content: flex-start; | ||
padding-left: 0; | ||
padding-right: $grid-unit-20; | ||
border-top: 0; | ||
margin-top: 0; | ||
|
||
ul { | ||
display: flex; | ||
} | ||
li { | ||
margin: 0; | ||
} | ||
|
||
.components-button.has-icon { | ||
display: none; | ||
margin: 0 0 0 auto; | ||
padding: 0; | ||
min-width: $icon-size; | ||
height: $icon-size; | ||
|
||
@include break-medium() { | ||
display: flex; | ||
} | ||
} | ||
} | ||
|
||
.components-button.edit-site-sidebar__panel-tab { | ||
border-radius: 0; | ||
height: $grid-unit-60; | ||
background: transparent; | ||
border: none; | ||
box-shadow: none; | ||
cursor: pointer; | ||
display: inline-block; | ||
padding: 3px 15px; // Use padding to offset the is-active border, this benefits Windows High Contrast mode | ||
margin-left: 0; | ||
font-weight: 500; | ||
|
||
// This pseudo-element "duplicates" the tab label and sets the text to bold. | ||
// This ensures that the tab doesn't change width when selected. | ||
// See: https://github.com/WordPress/gutenberg/pull/9793 | ||
&::after { | ||
content: attr(data-label); | ||
display: block; | ||
font-weight: 600; | ||
height: 0; | ||
overflow: hidden; | ||
speak: none; | ||
visibility: hidden; | ||
} | ||
|
||
&.is-active { | ||
// The transparent shadow ensures no jumpiness when focus animates on an active tab. | ||
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) transparent, inset 0 0 -$border-width-tab 0 0 var(--wp-admin-theme-color); | ||
position: relative; | ||
z-index: z-index(".edit-post-sidebar__panel-tab.is-active"); | ||
|
||
// This border appears in Windows High Contrast mode instead of the box-shadow. | ||
&::before { | ||
content: ""; | ||
position: absolute; | ||
top: 0; | ||
bottom: 1px; | ||
right: 0; | ||
left: 0; | ||
border-bottom: $border-width-tab solid transparent; | ||
} | ||
} | ||
|
||
&:focus { | ||
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color); | ||
position: relative; | ||
z-index: z-index(".edit-post-sidebar__panel-tab.is-active"); | ||
} | ||
|
||
&.is-active:focus { | ||
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color), inset 0 0 -$border-width-tab 0 0 var(--wp-admin-theme-color); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
packages/edit-site/src/components/sidebar/template-card/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect } from '@wordpress/data'; | ||
import { Icon } from '@wordpress/components'; | ||
import { layout } from '@wordpress/icons'; | ||
import { store as editorStore } from '@wordpress/editor'; | ||
import { store as coreStore } from '@wordpress/core-data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as editSiteStore } from '../../../store'; | ||
|
||
export default function TemplateCard() { | ||
const { title, description } = useSelect( ( select ) => { | ||
const { getEditedPostType, getEditedPostId } = select( editSiteStore ); | ||
const { getEntityRecord } = select( coreStore ); | ||
const { __experimentalGetTemplateInfo: getTemplateInfo } = select( | ||
editorStore | ||
); | ||
|
||
const postType = getEditedPostType(); | ||
const postId = getEditedPostId(); | ||
const record = getEntityRecord( 'postType', postType, postId ); | ||
const info = record ? getTemplateInfo( record ) : {}; | ||
|
||
return info; | ||
}, [] ); | ||
|
||
if ( ! title && ! description ) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className="edit-site-template-card"> | ||
<Icon className="edit-site-template-card__icon" icon={ layout } /> | ||
<div className="edit-site-template-card__content"> | ||
<h2 className="edit-site-template-card__title">{ title }</h2> | ||
<span className="edit-site-template-card__description"> | ||
{ description } | ||
</span> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.