diff --git a/src/web/App.sidebar-mobile.test.tsx b/src/web/App.sidebar-mobile.test.tsx new file mode 100644 index 0000000..147f320 --- /dev/null +++ b/src/web/App.sidebar-mobile.test.tsx @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +describe('App mobile sidebar', () => { + it('renders hamburger trigger for mobile navigation', () => { + const source = readFileSync(resolve(process.cwd(), 'src/web/App.tsx'), 'utf8'); + + expect(source).toContain('aria-label="Open navigation"'); + expect(source).toContain('MobileDrawer'); + expect(source).toContain('mobile-nav'); + }); +}); diff --git a/src/web/App.tsx b/src/web/App.tsx index ebdbec2..45c2e25 100644 --- a/src/web/App.tsx +++ b/src/web/App.tsx @@ -17,6 +17,7 @@ import { resolveLoginErrorMessage } from './loginError.js'; import { SITE_DOCS_URL } from './docsLink.js'; import { useAnimatedVisibility } from './components/useAnimatedVisibility.js'; import { useIsMobile } from './components/useIsMobile.js'; +import { MobileDrawer } from './components/MobileDrawer.js'; const Dashboard = lazy(() => import('./pages/Dashboard.js')); const Sites = lazy(() => import('./pages/Sites.js')); const Accounts = lazy(() => import('./pages/Accounts.js')); @@ -378,6 +379,7 @@ function AppShell() { const [showProfileModal, setShowProfileModal] = useState(false); const [showSearch, setShowSearch] = useState(false); const [showNotifications, setShowNotifications] = useState(false); + const [drawerOpen, setDrawerOpen] = useState(false); const themeMenuPresence = useAnimatedVisibility(showThemeMenu, 160); const userMenuPresence = useAnimatedVisibility(showUserMenu, 160); const [unreadCount, setUnreadCount] = useState(0); @@ -551,6 +553,17 @@ function AppShell() { return ( <>
+ {isMobile && ( + + )}
Metapi Metapi @@ -673,32 +686,56 @@ function AppShell() {
- + + + ) : ( + + )}