From cfe38c39aa1f42385606f77ac7f5a5a5c686af18 Mon Sep 17 00:00:00 2001 From: Marcel Raddatz Date: Thu, 2 Apr 2026 13:18:09 +0200 Subject: [PATCH] feat(nav): add AppShell layout with breakpoint-switched navigation Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/lib/nav/AppShell.svelte | 19 ++++++++++++++ frontend/src/lib/nav/AppShell.test.ts | 37 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 frontend/src/lib/nav/AppShell.svelte create mode 100644 frontend/src/lib/nav/AppShell.test.ts diff --git a/frontend/src/lib/nav/AppShell.svelte b/frontend/src/lib/nav/AppShell.svelte new file mode 100644 index 0000000..dba02e4 --- /dev/null +++ b/frontend/src/lib/nav/AppShell.svelte @@ -0,0 +1,19 @@ + + +
+ +
+ +
+ {@render children?.()} +
+ +
+
diff --git a/frontend/src/lib/nav/AppShell.test.ts b/frontend/src/lib/nav/AppShell.test.ts new file mode 100644 index 0000000..63e9eb0 --- /dev/null +++ b/frontend/src/lib/nav/AppShell.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect, vi } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; +import AppShell from './AppShell.svelte'; + +vi.mock('$app/stores', () => { + const { readable } = require('svelte/store'); + return { + page: readable({ url: new URL('http://localhost/planner') }) + }; +}); + +describe('AppShell', () => { + const defaultProps = { appName: 'Mealprep', householdName: 'Familie Müller' }; + + it('renders the DesktopSidebar', () => { + render(AppShell, { props: defaultProps }); + expect(screen.getByTestId('variety-widget-slot')).toBeInTheDocument(); + }); + + it('renders the MobileTabBar nav', () => { + render(AppShell, { props: defaultProps }); + const navs = screen.getAllByLabelText('Hauptnavigation'); + expect(navs.length).toBeGreaterThanOrEqual(2); + }); + + it('renders a main content area', () => { + render(AppShell, { props: defaultProps }); + expect(screen.getByRole('main')).toBeInTheDocument(); + }); + + it('renders all navigation links from all nav variants', () => { + render(AppShell, { props: defaultProps }); + const links = screen.getAllByRole('link'); + // Mobile: 4, Tablet: 4, Desktop: 5 = 13 total + expect(links).toHaveLength(13); + }); +});