Skip to content

Commit 669b1bb

Browse files
authored
Omnibar: support wpcom-account node (#113341)
1 parent 0a5d28a commit 669b1bb

14 files changed

Lines changed: 171 additions & 47 deletions

File tree

client/dashboard/app/omnibar/omnibar.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,23 @@ import { OmnibarHomeIcon } from './home';
1515
import { useHelpCenterPlugin } from './plugin-help-center';
1616
import { useNotificationsPlugin } from './plugin-notifications';
1717
import { useStatsSparklinePlugin } from './plugin-stats-sparkline';
18+
import { buildWpcomAccountNode } from './plugin-wpcom-account';
1819
import type { AppConfig } from '../context';
1920
import type { User } from '@automattic/api-core';
21+
import type { OmnibarNodeBuilders } from '@automattic/omnibar';
2022

2123
const onClickResponsiveMenu = () => omnibarEvents.mobileMenu.emit();
2224

2325
const UNSUPPORTED_DOTCOM_NODE_IDS = new Set( [
2426
'site-plan',
2527
'site-plan-badge',
2628
'site-status-badge',
27-
'my-wpcom-account',
2829
] );
2930

31+
const DOTCOM_NODE_BUILDERS: OmnibarNodeBuilders = {
32+
'my-wpcom-account': buildWpcomAccountNode,
33+
};
34+
3035
function removeUnsupportedNodes( nodes: AdminBarNode[], supports: AppConfig[ 'supports' ] ) {
3136
return nodes.filter( ( node ) => {
3237
if ( UNSUPPORTED_DOTCOM_NODE_IDS.has( node.id ) ) {
@@ -59,7 +64,10 @@ export default function OmnibarContainer( { user }: { user?: User } ) {
5964

6065
const baseOmnibarNodes = useMemo( () => {
6166
const nodes = siteNodes ?? dashboardNodes ?? [];
62-
const result = buildOmnibarNodesFromAdminBarNodes( removeUnsupportedNodes( nodes, supports ) );
67+
const result = buildOmnibarNodesFromAdminBarNodes(
68+
removeUnsupportedNodes( nodes, supports ),
69+
DOTCOM_NODE_BUILDERS
70+
);
6371

6472
if ( ! result.home ) {
6573
result.home = { id: '' };
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.omnibar__popover {
2+
.omnibar__wpcom-account {
3+
display: block;
4+
box-sizing: border-box;
5+
width: 100%;
6+
height: 34px;
7+
padding: 0 14px;
8+
margin-block: 6px;
9+
border-radius: 2px;
10+
background-color: var( --studio-wordpress-blue-50, #3858e9 );
11+
color: var( --omnibar-text-color );
12+
line-height: 32px;
13+
text-align: center;
14+
15+
svg {
16+
position: relative;
17+
top: -1px;
18+
margin-inline: -2px -4px;
19+
fill: currentColor;
20+
vertical-align: middle;
21+
transform: scale( 0.8 );
22+
}
23+
}
24+
25+
[role='menuitem']:hover,
26+
[role='menuitem'][data-active-item] {
27+
.omnibar__wpcom-account {
28+
background-color: #4664eb;
29+
}
30+
}
31+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { OmnibarHomeIcon } from './home';
2+
import type { AdminBarNode, OmnibarNode } from '@automattic/omnibar';
3+
4+
import './plugin-wpcom-account.scss';
5+
6+
export function buildWpcomAccountNode( adminBarNode: AdminBarNode ): Partial< OmnibarNode > {
7+
const doc = new DOMParser().parseFromString( adminBarNode.title || '', 'text/html' );
8+
const button = doc.querySelector( '.wpcom-button' ) ?? doc.body;
9+
const content = Array.from( button.childNodes ).map( ( child, index ) =>
10+
( child as Element ).classList?.contains( 'wpcom-logo' ) ? (
11+
<OmnibarHomeIcon key={ index } />
12+
) : (
13+
child.textContent
14+
)
15+
);
16+
17+
return {
18+
title: undefined,
19+
render: () => <span className="omnibar__wpcom-account">{ content }</span>,
20+
};
21+
}

packages/omnibar/src/components/_variables.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ $omnibar-submenu-background: #0c0c0c;
88
$omnibar-text-color: #fff;
99
$omnibar-submenu-text-color: #bcbcbc;
1010
$omnibar-highlight-color: #7b90ff;
11-
11+
$omnibar-secondary-group-background: rgba( 255, 255, 255, 0.15 );
1212
$omnibar-avatar-ring-color: #303030;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
.omnibar__popover {
2+
// All colors used by the Menu's internal Emotion styles read from these
3+
// CSS custom properties (see node_modules/@wordpress/components/src/menu/styles.ts).
4+
// Setting them here re-skins the entire popover without specificity wars.
5+
--wp-components-color-background: var( --omnibar-submenu-background );
6+
--wp-components-color-foreground: var( --omnibar-text-color );
7+
--wp-components-color-accent: transparent; // hover/active item bg
8+
--wp-components-color-accent-inverted: var(
9+
--omnibar-submenu-highlight-color
10+
); // hover/active item text
11+
--wp-components-color-gray-100: transparent; // submenu-trigger-open bg
12+
--wp-components-color-gray-700: var( --omnibar-text-color ); // prefix / suffix text
13+
14+
// Padding, border-radius, and the elevation portion of the popover's
15+
// box-shadow are hardcoded (not tokens). Class is doubled to outrank
16+
// Emotion's auto-generated selector at the popover level.
17+
&.omnibar__popover {
18+
border-radius: 0;
19+
box-shadow: none;
20+
padding-inline: 0;
21+
}
22+
23+
[role='menuitem'],
24+
[role='menuitemradio'],
25+
[role='menuitemcheckbox'] {
26+
border-radius: 0;
27+
grid-template-columns: minmax( 0, max-content ) 1fr;
28+
padding-inline: 10px;
29+
}
30+
31+
.omnibar__menu-group.is-secondary {
32+
grid-column: 1 / -1;
33+
margin-block-start: 8px;
34+
background-color: var( --omnibar-secondary-group-background );
35+
36+
&:first-child {
37+
margin-block-start: -4px;
38+
}
39+
40+
&:last-child {
41+
margin-block-end: -4px;
42+
}
43+
44+
@supports ( grid-template-columns: subgrid ) {
45+
display: grid;
46+
grid-template-columns: subgrid;
47+
}
48+
}
49+
}

packages/omnibar/src/components/omnibar-menu.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { useRef, useState } from 'react';
55
import { OmnibarNodeContent } from './omnibar-node';
66
import type { OmnibarNode } from '../types';
77

8+
import './omnibar-menu.scss';
9+
810
const { unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
911
'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',
1012
'@wordpress/components'
@@ -54,7 +56,12 @@ function OmnibarMenuContent( { nodes }: { nodes: OmnibarNode[] } ) {
5456
</Menu.Group>
5557
) }
5658
{ groups.map( ( group ) => (
57-
<Menu.Group key={ group.id }>
59+
<Menu.Group
60+
key={ group.id }
61+
className={
62+
group.variant ? `omnibar__menu-group is-${ group.variant }` : 'omnibar__menu-group'
63+
}
64+
>
5865
{ group.title && <Menu.GroupLabel>{ group.title }</Menu.GroupLabel> }
5966
{ ( group.children || [] ).map( ( item ) => (
6067
<OmnibarMenuItem key={ item.id } node={ item } />
@@ -89,7 +96,7 @@ export function OmnibarMenu( { node, className }: { node: OmnibarNode; className
8996
}
9097

9198
const handleMouseLeave = ( event: React.MouseEvent ) => {
92-
const movingTo = event.relatedTarget as Node | null;
99+
const movingTo = event.relatedTarget instanceof Node ? event.relatedTarget : null;
93100
if (
94101
! triggerRef.current?.contains( movingTo ) &&
95102
! popoverRef.current?.contains( movingTo )

packages/omnibar/src/components/omnibar-user.scss

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@
3939
gap: 6px;
4040
}
4141

42-
.omnibar__user-info {
43-
opacity: 0.8;
42+
.omnibar__user-username {
4443
font-size: 11px;
44+
color: var( --omnibar-submenu-text-color );
45+
}
46+
47+
.omnibar__user-details > span {
48+
line-height: 18px;
4549
}
4650
}
4751

@@ -55,10 +59,22 @@
5559
}
5660
}
5761

62+
.omnibar__popover:has( .omnibar__user ) {
63+
min-width: 270px;
64+
}
65+
5866
.omnibar__popover {
5967
.omnibar__user-avatar {
6068
width: 64px;
6169
height: 64px;
6270
border: 0;
6371
}
72+
73+
[role='group']:has( .omnibar__user ) [role='menuitem'] {
74+
padding-inline-start: 88px;
75+
}
76+
77+
.omnibar__user .omnibar__user-avatar {
78+
margin-inline-start: -72px;
79+
}
6480
}

packages/omnibar/src/components/omnibar-user.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,12 @@ export function OmnibarUserNode( { node }: { node: OmnibarNode } ) {
3232
return {
3333
...grandChild,
3434
render: ( { title, icon, meta } ) => (
35-
<Stack direction="row" gap="md" align="center" className="omnibar__user">
35+
<Stack direction="row" gap="sm" align="center" className="omnibar__user">
3636
{ icon && <span className="omnibar__user-avatar">{ icon }</span> }
37-
<Stack direction="column" gap="sm">
38-
<Stack direction="column" gap="xs">
39-
<span>{ meta?.displayName }</span>
40-
<span className="omnibar__user-info">@{ meta?.username }</span>
41-
</Stack>
42-
<span className="omnibar__user-info">{ title }</span>
37+
<Stack direction="column" className="omnibar__user-details">
38+
<span>{ meta?.displayName }</span>
39+
<span className="omnibar__user-username">{ meta?.username }</span>
40+
<span>{ title }</span>
4341
</Stack>
4442
</Stack>
4543
),

packages/omnibar/src/components/omnibar.scss

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ body:has( .omnibar ) {
88
--omnibar-menu-active-background: #{$omnibar-submenu-background};
99
--omnibar-submenu-background: #{$omnibar-submenu-background};
1010
--omnibar-text-color: #{$omnibar-text-color};
11+
--omnibar-submenu-text-color: #{$omnibar-submenu-text-color};
1112
--omnibar-highlight-color: #{$omnibar-highlight-color};
1213
--omnibar-submenu-highlight-color: #{$omnibar-highlight-color};
1314
--omnibar-avatar-ring-color: #{$omnibar-avatar-ring-color};
15+
--omnibar-secondary-group-background: #{$omnibar-secondary-group-background};
1416

1517
@media ( min-width: 782px ) {
1618
--omnibar-height: #{$omnibar-height};
@@ -218,33 +220,3 @@ body:has( .omnibar ) {
218220
.omnibar .dashicons-menu-alt::before {
219221
top: 0.5px;
220222
}
221-
222-
.omnibar__popover {
223-
// All colors used by the Menu's internal Emotion styles read from these
224-
// CSS custom properties (see node_modules/@wordpress/components/src/menu/styles.ts).
225-
// Setting them here re-skins the entire popover without specificity wars.
226-
--wp-components-color-background: var( --omnibar-submenu-background );
227-
--wp-components-color-foreground: var( --omnibar-text-color );
228-
--wp-components-color-accent: transparent; // hover/active item bg
229-
--wp-components-color-accent-inverted: var(
230-
--omnibar-submenu-highlight-color
231-
); // hover/active item text
232-
--wp-components-color-gray-100: transparent; // submenu-trigger-open bg
233-
--wp-components-color-gray-700: var( --omnibar-text-color ); // prefix / suffix text
234-
235-
// Padding, border-radius, and the elevation portion of the popover's
236-
// box-shadow are hardcoded (not tokens). Class is doubled to outrank
237-
// Emotion's auto-generated selector at the popover level.
238-
&.omnibar__popover {
239-
border-radius: 0;
240-
box-shadow: none;
241-
}
242-
243-
[role='menuitem'],
244-
[role='menuitemradio'],
245-
[role='menuitemcheckbox'] {
246-
border-radius: 0;
247-
grid-template-columns: minmax( 0, max-content ) 1fr;
248-
padding-inline: 6px;
249-
}
250-
}

packages/omnibar/src/style.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
@import './components/omnibar.scss';
2+
@import './components/omnibar-menu.scss';
23
@import './components/omnibar-responsive-menu.scss';
34
@import './components/omnibar-user.scss';

0 commit comments

Comments
 (0)