Files
pad/web
xarmian 5c491b78b5 feat(web): mobile bottom navigation (PLAN-1694) (#692)
* feat(web): mobile bottom navigation + quick-capture (PLAN-1694)

Add a mobile-only persistent bottom navigation bar that coexists with the
existing TopBar. Five slots: Dashboard, Search, Quick-capture (center +),
Activity, More. The "More" slot opens a BottomSheet with the sidebar's
overflow destinations + collections; the center action opens a quick-capture
sheet that creates an item via the existing API.

- New shared nav source (lib/nav/destinations.ts) consumed by both the
  desktop Sidebar and the new BottomNav/More sheet so the two can't drift;
  Sidebar refactored to derive active-state from it (lossless).
- BottomNav mounts in the workspace layout (workspace-only), shows only on
  mobile (uiStore.isMobile, ≤768px), and toggles body.has-bottom-nav so
  app.css reflows .main-content above the fixed bar.
- iOS: app.html viewport-fit=cover + env(safe-area-inset-bottom) padding.
- z-index 40 (above TopBar/sidebar, below sheets).

Header retirement + full "You" (workspace/account) consolidation are
deliberately deferred to a human design checkpoint (DR-3).

Verify: web npm run check (0 errors) + npm run build (✓). Codex review loop
clean (1 P2 fixed: quick-capture re-defaults a stale collection slug).

Refs PLAN-1694 (TASK-1695, TASK-1696, TASK-1697, TASK-1698); parent ROADM-28.

* feat(web): retire mobile header in-workspace, add You sheet + contextual bar (PLAN-1694)

Complete the mobile nav vision on top of the bottom bar: inside a workspace
the global mobile header is gone, replaced by the BottomNav + a "You" sheet +
a contextual back/title bar on detail screens.

- BottomNav 5th slot More → You (👤). New YouSheet composes the workspace
  switcher, the nav overflow, and the full account menu carried over from the
  retired TopBar (Workspaces/Settings/Billing/Admin/theme/Resources/Connect/
  Sign out) so nothing is lost.
- Root layout gates <TopBar mobile /> on !inWorkspace (page.params.workspace),
  keeping it for the non-workspace picker/home which has no BottomNav; the
  .app-layout top offset now applies only via body.has-mobile-topbar.
- New MobileContextBar: fixed back+title bar shown only on detail screens
  (path depth ≥2); body.has-context-bar reflows .main-content top. Root/tab
  screens render full-height (reclaimed space).

Codex consensus + review clean (no P1). P2s fixed: safe in-app-history check
via afterNavigate (deep-link fallback to parent URL), humanized title fallback
for pages that don't wire titleStore, and the You sheet closes on navigation
so a workspace switch dismisses it.

Verify: web npm run check (0 errors) + npm run build (✓).

Refs PLAN-1694 (TASK-1699, TASK-1700); parent ROADM-28.

* feat(web): redesign mobile nav into Workspace + You docked sheets (PLAN-1694)

Address design feedback: the previous "You" sheet reused common/BottomSheet
(covered the nav bar) and embedded the old WorkspaceSwitcher (plain, unadapted).
Replace it with two purpose-built surfaces that dock ABOVE the nav.

- DockedSheet (new): bottom sheet anchored above the bottom nav — backdrop
  stops at the nav's top edge so the bar stays visible + tappable and the
  active slot stays lit. ~2/3 height, grab handle, slide-up, swipe-down /
  tap-out / Escape to dismiss. No more full-screen overlay covering the nav.
- Bottom-nav slot 1 Dashboard → Workspace (icon = current workspace avatar),
  opening WorkspaceSheet: a designed switcher card (inline-expand list) +
  Navigate tile grid + Collections.
- "You" slot → YouSheet, now account-only: profile header, theme toggle,
  account Settings / Workspaces / Billing / Admin / Connect / Resources /
  Sign out. Search / + / Activity unchanged.
- New avatar util (avatarColor/avatarInitial) for workspace + user avatars.

Splits the overstuffed single sheet into two focused surfaces (where-am-I vs
me) and removes the reused WorkspaceSwitcher/BottomSheet. Codex review CLEAN.

Verify: web npm run check (0 errors) + npm run build (✓).

Refs PLAN-1694 (TASK-1701); parent ROADM-28.

* feat(web): toggle Workspace/You sheets on repeat nav tap (PLAN-1694)

Tapping the Workspace or You nav slot a second time now closes its open
sheet (tap to open, tap again to close). Opening one still closes the other.
The docked backdrop stops above the nav, so the slot button stays tappable
while its sheet is open.

Refs PLAN-1694 (TASK-1701).

* feat(web): dock mobile search to match the nav sheets (PLAN-1694)

The CommandPalette was the last mobile surface that didn't match — a
full-screen takeover (square, no handle, hid the nav). Give its mobile
presentation the same docked treatment as the Workspace/You sheets;
desktop ⌘K is untouched.

- Mobile: dock the palette above the bottom nav (backdrop stops at the nav's
  top edge so the bar stays visible), rounded top, grab handle with
  swipe-down-to-dismiss, tap-outside to close, no X. Lift above the nav only
  when it's present (:global(body.has-bottom-nav)); flush to bottom on the
  non-workspace picker. Keyboard handling preserved: input stays at the sheet
  top, .results is the sole scroll area, min-height keeps the input clear of
  the keyboard when empty.
- BottomNav: Search slot toggles (tap to open, tap again to close) and lights
  up while open; the three surfaces (Workspace / You / Search) are now
  mutually exclusive.

Codex review CLEAN. Verify: web npm run check (0 errors) + build (✓).
Note: on-screen-keyboard feel should get an on-device smoke test.

Refs PLAN-1694 (TASK-1701); parent ROADM-28.
2026-06-02 08:41:54 -04:00
..
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00

Pad Web UI

SvelteKit 2 + Svelte 5 frontend for Pad, compiled to static files and embedded into the Go binary.

Development

npm install
npm run dev          # Dev server at localhost:5173 (proxies API to localhost:7777)
npm run build        # Production build to build/
npm run check        # Type checking with svelte-check

When developing, run the Go backend separately with make dev from the project root.

Building for Production

Do not build in isolation. Always use make build from the project root — this builds the web frontend, then compiles the Go binary with the build output embedded via //go:embed.

Stack

  • Svelte 5 with runes ($state, $derived, $effect)
  • SvelteKit 2 with adapter-static (SPA mode)
  • Tiptap block editor with markdown round-trip
  • svelte-dnd-action for drag-and-drop in board/list views
  • SSE for real-time updates
  • TypeScript throughout

Structure

src/
  routes/                    SvelteKit pages
    +layout.svelte           App shell (sidebar + main)
    +page.svelte             Landing/redirect
    [workspace]/
      +page.svelte           Dashboard (collections, phases, activity)
      +layout.svelte         SSE connection per workspace
      [collection]/
        +page.svelte         Collection view (board/list)
      [collection]/[item]/
        +page.svelte         Item detail + editor
      conventions/            Purpose-built conventions page
      playbooks/              Purpose-built playbooks page
      settings/               Workspace settings
  lib/
    api/client.ts            HTTP API client
    components/
      layout/                Sidebar, navigation
      editor/                Tiptap editor, raw markdown editor
      fields/                FieldEditor, relation picker
      items/                 ItemCard, ItemDetail
      collections/           BoardView, ListView
      common/                StatusBadge, badges, modals
      search/                CommandPalette
      activity/              ActivityFeed
    stores/                  Svelte 5 reactive stores
      workspace.svelte.ts    Workspace state
      collections.svelte.ts  Collection + item state
      ui.svelte.ts           Sidebar, mobile state
    types/index.ts           TypeScript types and constants
  app.css                    Global styles and design tokens