From 37a1db480e687f20753d294d17bb5a607100b2d6 Mon Sep 17 00:00:00 2001 From: Ashar Fuadi Date: Wed, 5 Aug 2026 19:01:49 +0700 Subject: [PATCH] Omnibar: add pressed state for the Help and Notifications buttons Introduce an `isActive` flag on `OmnibarNode` and render leaf nodes with `is-active` plus `aria-pressed`, then wire the help center and notifications plugins to it. Co-Authored-By: Claude Opus 5 (1M context) --- client/dashboard/app/omnibar/plugin-help-center.tsx | 1 + client/dashboard/app/omnibar/plugin-notifications.scss | 3 ++- client/dashboard/app/omnibar/plugin-notifications.tsx | 4 ++++ packages/omnibar/src/components/omnibar-menu.tsx | 4 +++- packages/omnibar/src/components/omnibar.scss | 1 + packages/omnibar/src/types/omnibar.ts | 1 + 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/client/dashboard/app/omnibar/plugin-help-center.tsx b/client/dashboard/app/omnibar/plugin-help-center.tsx index 9ab7df7f7a79..9b27ef7389d5 100644 --- a/client/dashboard/app/omnibar/plugin-help-center.tsx +++ b/client/dashboard/app/omnibar/plugin-help-center.tsx @@ -28,6 +28,7 @@ export function useHelpCenterPlugin(): OmnibarNode { id: 'help-center', label: __( 'Help' ), icon: , + isActive: isHelpCenterShown, onClick: () => setShowHelpCenter( ! isHelpCenterShown ), }; } diff --git a/client/dashboard/app/omnibar/plugin-notifications.scss b/client/dashboard/app/omnibar/plugin-notifications.scss index 911303426517..6e27d419a9f1 100644 --- a/client/dashboard/app/omnibar/plugin-notifications.scss +++ b/client/dashboard/app/omnibar/plugin-notifications.scss @@ -23,6 +23,7 @@ .omnibar .omnibar__menu:hover .omnibar__notifications-unread-dot, .omnibar .omnibar__menu:focus-visible .omnibar__notifications-unread-dot, -.omnibar .omnibar__menu:active .omnibar__notifications-unread-dot { +.omnibar .omnibar__menu:active .omnibar__notifications-unread-dot, +.omnibar .omnibar__menu.is-active .omnibar__notifications-unread-dot { stroke: var( --omnibar-menu-active-background ); } diff --git a/client/dashboard/app/omnibar/plugin-notifications.tsx b/client/dashboard/app/omnibar/plugin-notifications.tsx index 3f65c3e58277..d55c2e505967 100644 --- a/client/dashboard/app/omnibar/plugin-notifications.tsx +++ b/client/dashboard/app/omnibar/plugin-notifications.tsx @@ -21,11 +21,14 @@ export function useNotificationsPlugin( { user }: { user?: User } ): OmnibarNode const [ hasUnseenNotifications, setHasUnseenNotifications ] = useState( !! user?.has_unseen_notes ); + const [ isPanelOpen, setIsPanelOpen ] = useState( false ); useOmnibarEvent( 'notificationsUnseenCount', ( count ) => setHasUnseenNotifications( count > 0 ) ); + useOmnibarEvent( 'notificationsOpen', setIsPanelOpen ); + const bellRef = useRef< HTMLSpanElement >( null ); // Re-runs every commit so the anchor stays correct if the bell button is replaced. @@ -41,6 +44,7 @@ export function useNotificationsPlugin( { user }: { user?: User } ): OmnibarNode ), + isActive: isPanelOpen, onClick: () => omnibarEvents.notifications.emit(), }; } diff --git a/packages/omnibar/src/components/omnibar-menu.tsx b/packages/omnibar/src/components/omnibar-menu.tsx index 3e8a6d91f156..f63c297a99a6 100644 --- a/packages/omnibar/src/components/omnibar-menu.tsx +++ b/packages/omnibar/src/components/omnibar-menu.tsx @@ -67,7 +67,8 @@ function OmnibarMenuContent( { nodes }: { nodes: OmnibarNode[] } ) { export function OmnibarMenu( { node, className }: { node: OmnibarNode; className?: string } ) { const label = node.title || node.label || ''; - const menuClassName = className ? `omnibar__menu ${ className }` : 'omnibar__menu'; + const classNames = [ 'omnibar__menu', className, node.isActive && 'is-active' ].filter( Boolean ); + const menuClassName = classNames.join( ' ' ); const [ isOpen, setIsOpen ] = useState( false ); const triggerRef = useRef< HTMLElement >( null ); const popoverRef = useRef< HTMLElement >( null ); @@ -82,6 +83,7 @@ export function OmnibarMenu( { node, className }: { node: OmnibarNode; className nativeButton={ ! node.href } onClick={ node.onClick } aria-label={ label } + aria-pressed={ node.href ? undefined : node.isActive } > diff --git a/packages/omnibar/src/components/omnibar.scss b/packages/omnibar/src/components/omnibar.scss index 677a66cc1976..2a2ff69348ef 100644 --- a/packages/omnibar/src/components/omnibar.scss +++ b/packages/omnibar/src/components/omnibar.scss @@ -56,6 +56,7 @@ body:has( .omnibar ) { &:hover, &:focus-visible, &:active, + &.is-active, &[aria-expanded='true'] { background-color: var( --omnibar-menu-active-background ); color: $omnibar-text-color; diff --git a/packages/omnibar/src/types/omnibar.ts b/packages/omnibar/src/types/omnibar.ts index ac6c9b1bb231..9423af0e30f7 100644 --- a/packages/omnibar/src/types/omnibar.ts +++ b/packages/omnibar/src/types/omnibar.ts @@ -6,6 +6,7 @@ export interface OmnibarNode { group?: boolean; href?: string; onClick?: () => void; + isActive?: boolean; meta?: SiteActionNodeMeta & UserInfoNodeMeta; render?: ( node: OmnibarNode ) => React.ReactNode; children?: OmnibarNode[];