From 857a8621ec89878b3ffa2776a45eb2e9d25f3dee Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 9 May 2026 20:17:17 -0400 Subject: [PATCH] feat(web): MobileNavDrawer off-canvas nav for --- web/src/lib/components/MobileNavDrawer.svelte | 138 ++++++++++++++++++ .../lib/components/MobileNavDrawer.test.ts | 43 ++++++ 2 files changed, 181 insertions(+) create mode 100644 web/src/lib/components/MobileNavDrawer.svelte create mode 100644 web/src/lib/components/MobileNavDrawer.test.ts diff --git a/web/src/lib/components/MobileNavDrawer.svelte b/web/src/lib/components/MobileNavDrawer.svelte new file mode 100644 index 00000000..f9f2d7c7 --- /dev/null +++ b/web/src/lib/components/MobileNavDrawer.svelte @@ -0,0 +1,138 @@ + + + + +{#if mobileNav.value} + +{/if} + + diff --git a/web/src/lib/components/MobileNavDrawer.test.ts b/web/src/lib/components/MobileNavDrawer.test.ts new file mode 100644 index 00000000..c094d85b --- /dev/null +++ b/web/src/lib/components/MobileNavDrawer.test.ts @@ -0,0 +1,43 @@ +import { describe, it, expect, beforeEach } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; +import MobileNavDrawer from './MobileNavDrawer.svelte'; +import { mobileNav, openMobileNav, closeMobileNav } from '$lib/stores/mobileNav.svelte'; + +describe('MobileNavDrawer', () => { + beforeEach(() => { + closeMobileNav(); + }); + + it('renders inert + aria-hidden when closed', () => { + render(MobileNavDrawer); + const aside = screen.getByLabelText('Main navigation'); + expect(aside.getAttribute('aria-hidden')).toBe('true'); + expect(aside.hasAttribute('inert')).toBe(true); + }); + + it('flips to visible when mobileNav opens', async () => { + render(MobileNavDrawer); + openMobileNav(); + await Promise.resolve(); + const aside = screen.getByLabelText('Main navigation'); + expect(aside.getAttribute('aria-hidden')).toBe('false'); + expect(aside.hasAttribute('inert')).toBe(false); + }); + + it('renders all nav items + Settings + Log out', () => { + openMobileNav(); + render(MobileNavDrawer); + expect(screen.getByText('Home')).toBeInTheDocument(); + expect(screen.getByText('Artists')).toBeInTheDocument(); + expect(screen.getByText('Settings')).toBeInTheDocument(); + expect(screen.getByText('Log out')).toBeInTheDocument(); + }); + + it('Escape key closes the drawer', () => { + openMobileNav(); + render(MobileNavDrawer); + expect(mobileNav.value).toBe(true); + window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' })); + expect(mobileNav.value).toBe(false); + }); +});