Top bar (app-header):
- Removed the Contribute button. It stays reachable from the footer.
- Removed the theme selector; it moves to the sidebar footer.
- Removed the mobile sheet for signed-in users: it duplicated the bottom tab
bar for navigation and the avatar menu for identity. Signed-out visitors
keep it, since auth pages have no tab bar.
The header is now brand on the left, account on the right.
Footer:
- Rebuilt as a slim single bar. A logged-in user is already converted, so the
app does not need the marketing site's multi-column link farm. It borrows
that footer's visual language (muted surface, muted-to-foreground hovers,
green status pill) so the two still read as one product.
- Fixed the "cut by the side nav" bug. The footer was rendered in
(app)/layout.tsx as a sibling of <main>, so it spanned the full viewport
while the dashboard's fixed sidebar painted over its left 240px, and the
fixed mobile tab bar covered its bottom edge. It is now rendered per
section, inside each content column, with the dashboard copy padded clear
of the tab bar.
Theme control:
- Moved to the sidebar footer and restyled from a dropdown into a three-way
Light/Dark/System segmented control, which now has room to show all three
states at once.
Sidebar icon:
- Dashboard uses LayoutDashboard instead of Home, matching the icon the
avatar menu already uses for the same destination.
E2e harness, two real fixes found while verifying:
- The suite ran against `next dev`, which compiles routes on demand, so
parallel workers hitting cold routes timed out at random. Switched to a
production build; the suite went from 1.3m to ~31s.
- The survey modal (a Math.random() coin flip) and the update-app prompt
(whenever a mocked device reports an old version) could open over any page.
A Radix dialog marks the rest of the page aria-hidden while open, so every
getByRole query found nothing and a different test failed each run. Both are
now suppressed deterministically in the session helper.
Full suite: 16/16 on four consecutive runs.
New chrome.spec.ts guards the footer geometry against both the sidebar and
the mobile tab bar, asserts the top bar stays reduced, and asserts the
sidebar theme control actually toggles the dark class.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Establish the testing safety net for the web dashboard before refactoring.
- Vitest + React Testing Library + jsdom for unit/component tests
- MSW node server mocks the API; unhandled requests throw so tests can
never reach a real backend
- Playwright e2e boots the real Next app but intercepts every /api/v1 call
with shared fixtures, and mints a NextAuth session cookie to run authed
- Shared fixtures in test/fixtures.ts back both layers
- Seed tests: Button unit tests, MSW sanity checks, and a dashboard e2e
happy path plus an auth-guard redirect
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>