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

Navigation Screen: Consolidate menu name and switcher #34786

Merged
merged 9 commits into from
Sep 14, 2021
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;
}
Mamaduka marked this conversation as resolved.
Show resolved Hide resolved

.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