V1 Web PWA · Surface walkthrough

Shell: App shell

A per-surface walkthrough of the V1 Web PWA: layout, states, interactions, data, and cross-references.

unspecified
12sections4 minread

On this page

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:

  1. OshunProviders — runtime config, experimentation, auth, query, profile sync
  2. ToastProvider — toast queue
  3. LilithThemeBootstrap — cream-paper / dark-paper theme selection
  4. PwaBootstrap — service worker registration, update prompt, install prompt
  5. QueryErrorHandler — react-query global error sink
  6. OfflineBanner — top-of-viewport offline indicator
  7. PwaOfflineFallback — fallback view when SW can't serve
  8. AccessibilityShell — wraps {children} with skip links + keyboard shortcuts
  9. CookieConsentBanner — 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: standalone honored

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
  • metadataBasehttps://oshun.app; canonical resolves correctly
  • apple-mobile-web-app-* meta tags — capable=yes, status-bar=black-translucent, title=OSHUN
  • OpenGraphog:title, og:description, og:image at /opengraph-image
  • Twitter card — summary_large_image at /twitter-image
  • JSON-LD WebApplication — schema.org/WebApplication; six domain featureList entries

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)

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

  • 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#

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