#230

Build the phone's navigation shell and sessions home

Opencalledforthwants to merge intofrom

What this does

The phone's shell after the agreed mockups (docs/ui-prototypes/mobile/01-home-and-session.html, 04 for inbox and search):

  • Floating pill nav as the tab bar. Sessions · Inbox · Settings are an expo-router Tabs group (src/app/(tabs)/) whose tab bar is the glass pill, with search detached beside it. Each tab is one instance that keeps its own state and scroll. A tap goes through the navigator (tabPress, then navigate), so switching never stacks screens, re-tapping does nothing, and Android back goes to Sessions and then out. The Inbox badge counts the sessions waiting on you, and screen readers hear it too ("Inbox, 2 need you").
  • Sessions home. Big title with the environment line (live dot, label, route kind) and tabs All · Active · Drafts. Active is grouped as Needs you · Working · Failed · Recent, and empty groups are left out. All is grouped by day (Today, Yesterday, weekday, "Earlier this month", then the month). A tree is ranked by its most urgent member and dated by its newest one, so live work in a child is never buried under a quiet parent. A child session nests under its parent with a connector. Each row shows one status glyph per state, then the title, project chip, what the session is doing, and its age. A draft row shows the first line, the project, the tool as its mark (never its name), the image count, and "Not synced" or "Sending".
  • Inbox. Needs you (Permissions / Questions / Plans) · Done · Failed, with an all-clear state. "Mark all seen" waits until it can acknowledge on the server.
  • Search. A modal in the root stack, with the field and projects shown before you type. Matching is word-wise across title and project ("tool pay" finds "Tool Call Payloads"), and results show as the standard rows, then projects.
  • Placeholders with working back controls. There is a session page frame, a "New session" page behind the compose button, and a draft page behind each draft row. Back and close return to the previous screen, or to the home when a cold deep link left nothing to go back to.

Design system (apps/mobile/src/ui)

  • Glass: expo-blur under the scheme's translucent floating surface plus the float shadow, fed by the theme tokens.
  • StatusMark: one glyph per state. The glyph ink comes from the theme: inkOn / statusInk pick the canvas or the ink by WCAG contrast.
  • ProviderMark: the web provider marks.
  • ProjectChip: a project's square, in a colour picked from the theme's documented project palette by the project's name.
  • Rows and chrome: SessionRow, DraftRow, SegmentedTabs, BigTitle, SectionLabel, FadeOut, IconButton.

Fills, not borders. The home and inbox lists are SectionLists.

Data

The home reads through src/home/source.ts. Until the phone speaks the environment protocol, that returns a fixture (src/home/fixture.ts) in the shared sidebar's own shapes (SidebarSessionEntry, SidebarDraft, WorkspaceEntry). The sessions-list work swaps the hook for the shared sidebar providers without touching the screens.

Status marks use the web sidebar's own mapping. sessionBusyTone moved into a pure, import-free app-core module (packages/app-core/src/components/sidebar/session-busy-tone.ts). It is exported from the logic graph and as a package subpath, and SessionBusyLoader re-exports it, so web is unchanged. done, busy, ready and idle read the same on both, and a status with no glyph shows the ring at rest. Nothing here invents, merges or changes server state.

src/home/rows.ts and src/home/search.ts are pure and unit-tested.

Also

  • Every screen paints the theme canvas, so the navigator's default white never shows.
  • The Convex-era session page stays behind its provider when EXPO_PUBLIC_CONVEX_URL is set. Otherwise the page frame shows, so the app runs with no Convex at all.
  • New native modules: expo-blur, expo-haptics, expo-linear-gradient (SDK-pinned).
  • README: a Shell section.
  • Android glass (a BlurView inside the BlurTargetView it blurs) still needs a check on a device.

Verification

CheckResult
mobile typecheck, root pnpm -r typecheckclean
mobile vitest38 pass
app-core lint / tests0 errors / 523 pass
npx expo export --platform androidok
web export + headless Chrome22 screens across dark and light, 0 page or console errors. Tab switching keeps one instance per tab and history stops growing. The home's Drafts tab survives a trip to Inbox and back. Cold deep links return home.

🤖 Generated with Claude Code

Activity

13
cloudflare-workers-and-pages[bot]9d ago

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

StatusDeployment URLCommitUpdated (UTC)See this deployment's details
  • Build: Failed ❌

View logs ↗
a04c9a42026-10-21T20:24:23.250ZView logs ↗
  • Build: Failed ❌

View logs ↗
2d716512026-10-21T20:12:25.156ZView logs ↗
  • Build: Failed ❌

View logs ↗
93ea4be2026-10-21T12:37:43.346ZView logs ↗
  • Build: Failed ❌

View logs ↗
e7d6a242026-10-21T12:23:18.749ZView logs ↗
greptile-apps[bot]9d ago


[Medium impact] The changes since the last review appear safe to merge.

Summary

Builds the phone’s navigation shell with Sessions, Inbox, Settings, search, and placeholder detail pages.

  • Sessions, Inbox, and Settings stay in a floating tab shell.
  • Sessions groups work by urgency, date, and draft status.
  • Inbox groups sessions that need attention, finished, or failed.
  • Search finds sessions and projects by the words you type.
  • Session and draft rows open pages with a working way back.
  • Mobile and web read session states from one shared mapping.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  Root[Root stack] --> Tabs[Tab navigator]
  Tabs --> Sessions[Sessions]
  Tabs --> Inbox[Inbox]
  Tabs --> Settings[Settings]
  Root --> Search[Search modal]
  Root --> Session[Session page]
  Root --> Draft[Draft page]
  Source[Fixture source] --> Sessions
  Source --> Inbox
  Source --> Search

Reviews (5) · Last reviewed commit: "Anchor cold deep links on the tabs with ..." · Reviewed by Greptile

greptile-apps[bot]reviewed9d ago
greptile-apps[bot]reviewed9d ago
greptile-apps[bot]reviewed9d ago
greptile-apps[bot]reviewed9d ago
calledforthreviewed9d ago
calledforthreviewed9d ago
calledforthreviewed9d ago
calledforthreviewed9d ago
calledforthreviewed9d ago
calledforthreviewed9d ago