Skip to content

Commit

Permalink
Navigation Screen: Consolidate menu name and switcher (#34786)
Browse files Browse the repository at this point in the history
* Navigation Screen: Consolidate menu name and switcher

* Update E2E test selectors

* Use MenuSwitcher

* Update dropdown z-index styles

* Style menu switcher's new button

* Hide top level 'New menu' button on small screens

* Render minimal header when menu isn't selected

* Add explaining comment for menu item group style reset

* Try better name for file and component
  • Loading branch information
Mamaduka authored Sep 14, 2021
1 parent 639a603 commit 2bc960a
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 89 deletions.
2 changes: 1 addition & 1 deletion packages/base-styles/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ $z-layers: (
".components-popover.edit-widgets-more-menu__content": 99998,
".components-popover.block-editor-rich-text__inline-format-toolbar": 99998,
".components-popover.block-editor-warning__dropdown": 99998,
".components-popover.edit-navigation-header__menu-switcher-dropdown": 99998,
".components-popover.edit-navigation-menu-actions__switcher-dropdown": 99998,

".components-autocomplete__results": 1000000,

Expand Down
22 changes: 7 additions & 15 deletions packages/e2e-tests/specs/experiments/navigation-editor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,12 @@ describe( 'Navigation editor', () => {
await visitNavigationEditor();

// Wait for the header to show the menu name.
await page.waitForXPath( '//h2[contains(., "Editing: Test Menu 1")]', {
await page.waitForXPath( '//h2[contains(., "Test Menu 1")]', {
visible: true,
} );

// Open up the menu creation dialog and create a new menu.
const switchMenuButton = await page.waitForXPath(
'//button[.="Switch menu"]'
);
await switchMenuButton.click();

const createMenuButton = await page.waitForXPath(
'//button[.="Create a new menu"]'
'//button[.="New menu"]'
);
await createMenuButton.click();

Expand Down Expand Up @@ -305,7 +299,7 @@ describe( 'Navigation editor', () => {
await visitNavigationEditor();

// Wait for the header to show the menu name.
await page.waitForXPath( '//h2[contains(., "Editing: Test Menu 1")]', {
await page.waitForXPath( '//h2[contains(., "Test Menu 1")]', {
visible: true,
} );

Expand Down Expand Up @@ -495,13 +489,13 @@ describe( 'Navigation editor', () => {
await saveButton.click();
await page.waitForSelector( '.components-snackbar' );
const headerSubtitle = await page.waitForSelector(
'.edit-navigation-header__subtitle'
'.edit-navigation-menu-actions__subtitle'
);
expect( headerSubtitle ).toBeTruthy();
const headerSubtitleText = await headerSubtitle.evaluate(
( element ) => element.innerText
);
expect( headerSubtitleText ).toBe( `Editing: ${ newName }` );
expect( headerSubtitleText ).toBe( newName );
} );

it( 'does not save a menu name upon clicking save button when name is empty', async () => {
Expand Down Expand Up @@ -532,15 +526,13 @@ describe( 'Navigation editor', () => {
await saveButton.click();
await page.waitForSelector( '.components-snackbar' );
const headerSubtitle = await page.waitForSelector(
'.edit-navigation-header__subtitle'
'.edit-navigation-menu-actions__subtitle'
);
expect( headerSubtitle ).toBeTruthy();
const headerSubtitleText = await headerSubtitle.evaluate(
( element ) => element.innerText
);
expect( headerSubtitleText ).toBe(
`Editing: ${ initialMenuName }`
);
expect( headerSubtitleText ).toBe( initialMenuName );
} );
} );

Expand Down
78 changes: 18 additions & 60 deletions packages/edit-navigation/src/components/header/index.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,39 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { NavigableToolbar } from '@wordpress/block-editor';
import { DropdownMenu } from '@wordpress/components';
import { useViewportMatch } from '@wordpress/compose';
import { PinnedItems } from '@wordpress/interface';
import { __, sprintf } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';

/**
* Internal dependencies
*/
import MenuActions from './menu-actions';
import NewButton from './new-button';
import SaveButton from './save-button';
import UndoButton from './undo-button';
import RedoButton from './redo-button';
import InserterToggle from './inserter-toggle';
import MenuSwitcher from '../menu-switcher';
import { useMenuEntityProp } from '../../hooks';

export default function Header( {
isMenuSelected,
menus,
selectedMenuId,
onSelectMenu,
isPending,
navigationPost,
} ) {
const isMediumViewport = useViewportMatch( 'medium' );

const [ menuName ] = useMenuEntityProp( 'name', selectedMenuId );

let actionHeaderText;

if ( menuName ) {
actionHeaderText = sprintf(
// translators: Name of the menu being edited, e.g. 'Main Menu'.
__( 'Editing: %s' ),
menuName
if ( ! isMenuSelected ) {
return (
<div className="edit-navigation-header">
<div className="edit-navigation-header__toolbar-wrapper">
<h1 className="edit-navigation-header__title">
{ __( 'Navigation' ) }
</h1>
</div>
</div>
);
} else if ( isPending ) {
// Loading text won't be displayed if menus are preloaded.
actionHeaderText = __( 'Loading …' );
} else {
actionHeaderText = __( 'No menus available' );
}

return (
Expand All @@ -68,46 +59,13 @@ export default function Header( {
</NavigableToolbar>
</div>

<h2 className="edit-navigation-header__subtitle">
{ isMenuSelected && decodeEntities( actionHeaderText ) }
</h2>

{ isMenuSelected && (
<div className="edit-navigation-header__actions">
<DropdownMenu
icon={ null }
toggleProps={ {
children: __( 'Switch menu' ),
'aria-label': __(
'Switch menu, or create a new menu'
),
showTooltip: false,
variant: 'tertiary',
disabled: ! menus?.length,
__experimentalIsFocusable: true,
} }
popoverProps={ {
className:
'edit-navigation-header__menu-switcher-dropdown',
position: 'bottom center',
} }
>
{ ( { onClose } ) => (
<MenuSwitcher
menus={ menus }
selectedMenuId={ selectedMenuId }
onSelectMenu={ ( menuId ) => {
onSelectMenu( menuId );
onClose();
} }
/>
) }
</DropdownMenu>
<MenuActions menus={ menus } isLoading={ isPending } />

<SaveButton navigationPost={ navigationPost } />
<PinnedItems.Slot scope="core/edit-navigation" />
</div>
) }
<div className="edit-navigation-header__actions">
{ isMediumViewport && <NewButton menus={ menus } /> }
<SaveButton navigationPost={ navigationPost } />
<PinnedItems.Slot scope="core/edit-navigation" />
</div>
</div>
);
}
80 changes: 80 additions & 0 deletions packages/edit-navigation/src/components/header/menu-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import {
DropdownMenu,
__experimentalText as Text,
} from '@wordpress/components';
import { chevronDown } from '@wordpress/icons';
import { useRef } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';

/**
* Internal dependencies
*/
import MenuSwitcher from '../menu-switcher';
import { useMenuEntityProp, useSelectedMenuId } from '../../hooks';

export default function MenuActions( { menus, isLoading } ) {
const [ selectedMenuId, setSelectedMenuId ] = useSelectedMenuId();
const [ menuName ] = useMenuEntityProp( 'name', selectedMenuId );

// The title ref is passed to the popover as the anchorRef so that the
// dropdown is centered over the whole title area rather than just one
// part of it.
const titleRef = useRef();

if ( isLoading ) {
return (
<div className="edit-navigation-menu-actions">
{ __( 'Loading…' ) }
</div>
);
}

return (
<div className="edit-navigation-menu-actions">
<div
ref={ titleRef }
className="edit-navigation-menu-actions__subtitle-wrapper"
>
<Text
size="body"
className="edit-navigation-menu-actions__subtitle"
as="h2"
>
{ decodeEntities( menuName ) }
</Text>

<DropdownMenu
icon={ chevronDown }
toggleProps={ {
label: __( 'Switch menu' ),
className:
'edit-navigation-menu-actions__switcher-toggle',
showTooltip: false,
__experimentalIsFocusable: true,
} }
popoverProps={ {
className:
'edit-navigation-menu-actions__switcher-dropdown',
position: 'bottom center',
anchorRef: titleRef.current,
} }
>
{ ( { onClose } ) => (
<MenuSwitcher
menus={ menus }
selectedMenuId={ selectedMenuId }
onSelectMenu={ ( menuId ) => {
setSelectedMenuId( menuId );
onClose();
} }
/>
) }
</DropdownMenu>
</div>
</div>
);
}
42 changes: 42 additions & 0 deletions packages/edit-navigation/src/components/header/new-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import AddMenu from '../add-menu';
import { useSelectedMenuId } from '../../hooks';

export default function NewButton( { menus } ) {
const [ isModalOpen, setIsModalOpen ] = useState( false );
const [ , setSelectedMenuId ] = useSelectedMenuId();

return (
<>
<Button variant="tertiary" onClick={ () => setIsModalOpen( true ) }>
{ __( 'New menu' ) }
</Button>
{ isModalOpen && (
<Modal
title={ __( 'Create a new menu' ) }
onRequestClose={ () => setIsModalOpen( false ) }
>
<AddMenu
menus={ menus }
helpText={ __(
'A short descriptive name for your menu.'
) }
onCreate={ ( menuId ) => {
setIsModalOpen( false );
setSelectedMenuId( menuId );
} }
/>
</Modal>
) }
</>
);
}
62 changes: 52 additions & 10 deletions packages/edit-navigation/src/components/header/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,58 @@
}
}

.edit-navigation-header__subtitle {
display: block;
margin: 0;
font-size: 15px;
font-weight: normal;
.edit-navigation-menu-actions {
display: flex;
flex-direction: column;
justify-content: center;

.edit-navigation-menu-actions__subtitle-wrapper {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}

.edit-navigation-menu-actions__switcher-toggle {
padding: 0;
min-width: 0;
}
}

.edit-navigation-menu-actions__switcher-dropdown {
// Appear below the modal overlay.
z-index: z-index(".components-popover.edit-navigation-menu-actions__switcher-dropdown");

// Resetting MenuItemGroup padding so button can take full space.
.components-menu-group.has-hidden-separator {
padding: 0;
}

.edit-navigation-menu-switcher__new-button.components-button {
justify-content: center;
background: $gray-900;
color: $white;
height: ($button-size + $grid-unit-10);
border-radius: 0;

&:hover {
color: $white;
}

&:active {
color: $gray-400;
}

&:focus:not(:disabled) {
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color), inset 0 0 0 3px $white;
}

// This is needed to center the button text.
.components-menu-item__item {
min-width: 0;
margin: 0;
}
}
}

.edit-navigation-header__actions {
Expand All @@ -63,11 +110,6 @@
}
}

.edit-navigation-header__menu-switcher-dropdown {
// Appear below the modal overlay.
z-index: z-index(".components-popover.edit-navigation-header__menu-switcher-dropdown");
}

// Hide notices.
.gutenberg_page_gutenberg-navigation {
.notice,
Expand Down
2 changes: 0 additions & 2 deletions packages/edit-navigation/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@ export default function Layout( { blockEditorSettings } ) {
isMenuSelected={ isMenuSelected }
isPending={ ! hasLoadedMenus }
menus={ menus }
selectedMenuId={ selectedMenuId }
onSelectMenu={ selectMenu }
navigationPost={ navigationPost }
/>
}
Expand Down
Loading

0 comments on commit 2bc960a

Please sign in to comment.