style(web): dunkle App-Leiste und Fluent-Seitenleiste

Kopfzeile 48 px dunkel mit Seitentitel statt immer Startseite,
Dashboard-Reiter mit Akzent-Unterstrich; Seitenleiste mit
Auswahlpille, Modul-Kacheln, aufgeklappten Kategorien und gefuelltem
Suchfeld; eingeklappt nur Kacheln. Einheitlicher PageHeader.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-25 14:32:37 +02:00
parent 7192be223a
commit b80db49c5e
11 changed files with 389 additions and 150 deletions
@@ -147,12 +147,10 @@ describe('Sidebar', () => {
const Sidebar = await importSidebar();
render(<Sidebar />);
// Categories are collapsed by default — wait for category header, then expand
// Design „Mosaik“: Kategorien sind anfangs aufgeklappt.
await waitFor(() => {
expect(screen.getByText('Domain Tools')).toBeInTheDocument();
expect(screen.getByText('Domain-Tools')).toBeInTheDocument();
});
await userEvent.click(screen.getByText('Domain Tools'));
await waitFor(() => {
expect(screen.getByText('Domaincheck')).toBeInTheDocument();
});
@@ -165,13 +163,46 @@ describe('Sidebar', () => {
});
});
it('Kategorien sind aufgeklappt, ein Klick auf die Kopfzeile klappt zu und wieder auf', async () => {
const Sidebar = await importSidebar();
render(<Sidebar />);
await waitFor(() => {
expect(screen.getByText('Domaincheck')).toBeInTheDocument();
});
const header = screen.getByText('Domain-Tools').closest('button');
expect(header).toHaveAttribute('aria-expanded', 'true');
await userEvent.click(screen.getByText('Domain-Tools'));
expect(screen.queryByText('Domaincheck')).not.toBeInTheDocument();
expect(header).toHaveAttribute('aria-expanded', 'false');
await userEvent.click(screen.getByText('Domain-Tools'));
expect(screen.getByText('Domaincheck')).toBeInTheDocument();
});
it('Modul-Eintraege tragen die App-Kachel, die Auswahl die Akzent-Pille', async () => {
mockPathname = '/modules/Domain-Tools/domaincheck';
const Sidebar = await importSidebar();
render(<Sidebar />);
await waitFor(() => {
expect(screen.getByText('Domaincheck')).toBeInTheDocument();
});
const link = screen.getByText('Domaincheck').closest('a');
expect(link?.querySelector('[data-module-tile="domaincheck"]')).not.toBeNull();
expect(link?.querySelector('[data-testid="nav-selection-pill"]')).not.toBeNull();
const dashLink = screen.getByText('Dashboard').closest('a');
expect(dashLink?.querySelector('[data-testid="nav-selection-pill"]')).toBeNull();
});
it('re-fetches modules when sidebarRefreshKey changes', async () => {
const Sidebar = await importSidebar();
const { rerender } = render(<Sidebar />);
// Wait for category header to confirm initial fetch completed
await waitFor(() => {
expect(screen.getByText('Domain Tools')).toBeInTheDocument();
expect(screen.getByText('Domain-Tools')).toBeInTheDocument();
});
const initialCallCount = (globalThis.fetch as ReturnType<typeof vi.fn>).mock.calls.length;