Source: apps/oshun/web/src/app/layout.tsx, apps/oshun/web/src/components/
Global chrome that wraps every view in the customer surface. If a check here fails, it fails everywhere. Walk this once per release.
Root layout composition#
The root layout (layout.tsx) mounts the following providers and shell
components, in this order:
OshunProviders— runtime config, experimentation, auth, query, profile syncToastProvider— toast queueLilithThemeBootstrap— cream-paper / dark-paper theme selectionPwaBootstrap— service worker registration, update prompt, install promptQueryErrorHandler— react-query global error sinkOfflineBanner— top-of-viewport offline indicatorPwaOfflineFallback— fallback view when SW can't serveAccessibilityShell— wraps{children}with skip links + keyboard shortcutsCookieConsentBanner— first-visit consent, bottom-of-viewport
States#
- First paint (cold cache) — fonts load with
display: swap; no FOUC; theme color applied before paint - Returning visit (warm cache) — instant paint; theme persisted
- Cookie consent not yet given — banner visible; PWA update prompt suppressed until consent resolves
- Offline —
<OfflineBanner>visible;<PwaOfflineFallback>ready for non-cached navigation - PWA update available —
<PwaUpdatePrompt>appears bottom-right (after consent); never competes with cookie banner - Standalone PWA mode — launched from home-screen icon; URL bar absent;
safe-area insets respected;
display: standalonehonored
Fonts#
The root layout loads three Google fonts and exposes them as CSS variables.
-
Cormorant_Garamond→--l-serif-loaded(weights 400/500/600, italic) -
Inter→--l-sans-loaded(weights 400/500/600/700) -
JetBrains_Mono→--l-mono-loaded(weights 400/500) -
display: 'swap'on all three — no blocking - Variables present on
<html>element
Metadata and SEO#
Set by export const metadata in layout.tsx.
- Title template — pages set
title: '…'and shell appends| OSHUN - Description — default copy mentions all six domains
- Manifest —
<link rel="manifest" href="/manifest.json"> - Icons — favicon.svg + 192px PNG + 180px apple-touch
-
metadataBase—https://oshun.app; canonical resolves correctly -
apple-mobile-web-app-*meta tags — capable=yes, status-bar=black-translucent, title=OSHUN - OpenGraph —
og:title,og:description,og:imageat/opengraph-image - Twitter card — summary_large_image at
/twitter-image - JSON-LD WebApplication — schema.org/WebApplication; six domain
featureListentries
Viewport / theme color#
- Light mode theme color —
#f1ebdd(cream paper) - Dark mode theme color —
#241c12(dark paper) -
width=device-width, initial-scale=1— present - Browser tab color matches active theme on Chromium/Safari
- iOS status bar matches theme (black-translucent in PWA mode)
Header#
The top-of-viewport shell header (mounted inside the page or a layout group, not the root layout). Variants:
-
Shell header — primary nav: Home, Explore, Activity, Library, Profile
-
Domain header — domain switcher + crumb when inside a domain
-
Minimal header — public/marketing routes (
/welcome,/landing, legal) -
Hidden — onboarding flow; some scene/atelier modes
-
Shell header renders on all five primary shell routes
-
Active route is indicated visually + via
aria-current="page" -
Search affordance opens
/search(or in-place search) via⌘K/Ctrl+K -
Profile menu opens with chevron + avatar; closes on outside click + Esc
-
Domain switcher lists 6 domains; current domain disabled
-
Notifications bell opens
<NotificationsCenterPanel>; unread count visible -
Assistant trigger opens assistant overlay via
dispatchOshunAssistantOpen
Footer#
- Legal links — Privacy, Terms, Cookies, Accessibility, CCPA, DPA
- Status link —
/status - Mobile: footer collapses or is replaced by
<MobileBottomNav>
Mobile bottom nav#
apps/oshun/web/src/components/MobileBottomNav.tsx
- Visible only on coarse pointer + viewport ≤ 640 px
- Five tabs matching
WEB_SHELL_ROUTE_PATHS - Active tab highlighted; safe-area inset honored
- Persists across navigation (no remount flash)
Breakpoints#
Walk each at: 320 px, 390 px, 640 px, 768 px, 1024 px, 1440 px, 1920 px.
- 320 px — no horizontal scroll; one-column layout
- 390 px (iPhone 14) — mobile bottom nav visible; safe area honored
- 640 px — transition between mobile and tablet layouts
- 768 px — tablet; aside panels appear where designed
- 1024 px — desktop layouts complete
- 1440 px — content reaches max-width; gutters balanced
- 1920 px — content doesn't stretch beyond design max-width
Theming#
@/design-system/lilith and globals-v2.css.
- System preference respected on first visit (no stored choice)
- Manual override persists across reload (
localStorage) - Token consistency — paper/cream/terracotta tokens on all surfaces
- Forced-colors mode (Windows high contrast) — text readable, borders visible
Cross-references#
- 02-routing-layouts.md — how routes mount under this shell
- 03-pwa-behavior.md — PWA install / SW behavior
- 04-auth-session.md — what gates the header's role-specific items
- 06-keyboard-a11y.md — keyboard shortcuts, skip links, focus
- Feature spec:
V1/features.md - Architecture:
V1/ARCHITECTURE.md
Open questions / known gaps#
-
/lilith-studio/*may run under a different header variant — confirm whether it inherits the shell header or uses Studio's own header -
/atelier/*and/scene/*likely use a focus-mode header — note which routes hide the global header entirely