From 2015e379c53282f29e0915054da0eb144597f7f4 Mon Sep 17 00:00:00 2001 From: Siavash Safi Date: Thu, 3 Sep 2026 16:44:41 +0200 Subject: [PATCH] feat(ui): add mantine burger menu navigation - render a burger menu+dropdown when page width is small (mobile, etc.) - add tests Signed-off-by: Siavash Safi --- ui/mantine-ui/src/App.test.tsx | 27 ++++++++++- .../src/components/Header.module.css | 7 +++ ui/mantine-ui/src/components/Header.tsx | 47 ++++++++++++++++--- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/ui/mantine-ui/src/App.test.tsx b/ui/mantine-ui/src/App.test.tsx index 40ba84b61f..d989344622 100644 --- a/ui/mantine-ui/src/App.test.tsx +++ b/ui/mantine-ui/src/App.test.tsx @@ -1,4 +1,5 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import App from './App'; import headerClasses from './components/Header.module.css'; @@ -21,4 +22,28 @@ describe('App routing', () => { expect(screen.getByRole('banner')).toHaveClass(headerClasses.header); }); + + it('provides navigation from the mobile menu', async () => { + const user = userEvent.setup(); + render(); + + const menuButton = screen.getByRole('button', { name: 'Toggle navigation menu' }); + await user.click(menuButton); + + expect(menuButton).toHaveAttribute('aria-expanded', 'true'); + + const menu = await screen.findByRole('menu', { hidden: true }); + const activeMenuItem = within(menu).getByRole('menuitem', { name: 'Alerts', hidden: true }); + expect(activeMenuItem).toHaveAttribute('aria-current', 'page'); + expect(activeMenuItem).toHaveClass(headerClasses.menuItem); + expect( + within(menu).getByRole('menuitem', { name: 'Silences', hidden: true }) + ).toBeInTheDocument(); + expect( + within(menu).getByRole('menuitem', { name: 'Runtime & Build Information', hidden: true }) + ).toBeInTheDocument(); + expect( + within(menu).getByRole('menuitem', { name: 'Configuration', hidden: true }) + ).toBeInTheDocument(); + }); }); diff --git a/ui/mantine-ui/src/components/Header.module.css b/ui/mantine-ui/src/components/Header.module.css index 7ce33c4d0d..1ebae0e47d 100644 --- a/ui/mantine-ui/src/components/Header.module.css +++ b/ui/mantine-ui/src/components/Header.module.css @@ -28,3 +28,10 @@ color: var(--mantine-color-white); } } + +.menuItem { + &[aria-current="page"] { + background-color: var(--mantine-color-blue-filled); + color: var(--mantine-color-white); + } +} diff --git a/ui/mantine-ui/src/components/Header.tsx b/ui/mantine-ui/src/components/Header.tsx index d6da9b5517..8b2a2d127e 100644 --- a/ui/mantine-ui/src/components/Header.tsx +++ b/ui/mantine-ui/src/components/Header.tsx @@ -1,4 +1,5 @@ -import { AppShell, Button, Group, Menu, Text } from '@mantine/core'; +import { AppShell, Burger, Button, Group, Menu, Text } from '@mantine/core'; +import { useDisclosure } from '@mantine/hooks'; import { Link, NavLink, Route, Routes } from 'react-router-dom'; import { AlertsPage } from '@/pages/Alerts.page'; @@ -9,6 +10,8 @@ import classes from './Header.module.css'; const navLinkXPadding = 'md'; export const Header = () => { + const [mobileMenuOpened, { open, close }] = useDisclosure(false); + const mainNavPages = [ { title: 'Alerts', @@ -99,6 +102,38 @@ export const Header = () => { ); + const mobileNavLinks = ( + (opened ? open() : close())} + menuItemTabIndex={0} + trapFocus={false} + position="bottom-end" + > + + + + + {mainNavPages.map((page) => ( + + {page.title} + + ))} + + Runtime & Build Information + + + Configuration + + + + ); + return ( @@ -107,17 +142,15 @@ export const Header = () => { {/* */} - - Alertmanager - - - Alertmanager - + Alertmanager {navLinks} + + {mobileNavLinks} +