Mobile Phase 2: read-only Contacts surface + shared BottomSheet/useIsMobile

Builds the mobile-first Contacts surface (<768px): a read-only A-Z directory
(sticky last-name letter headers) + segmented All/Investors/Prospects tabs +
pinned search -> full-screen detail (info with tap-to-copy email, opportunities,
comm history) -> a sort bottom-sheet. Contacts stays read-only on mobile per
design/BRIEF.md §3b (create/edit live on the Grid).

Lands the shared mobile primitives, deferred from Phase 1 and designed against
this first consumer (no dead code): <BottomSheet> (built on the Phase-1
.bottom-sheet CSS; scrim/Escape/pointer drag-to-dismiss) and useIsMobile()
(768px matchMedia). ContactsPage becomes a rules-of-hooks-safe wrapper that
mounts MobileContactsPage or the renamed-but-untouched DesktopContactsPage, so
desktop is unchanged. New CSS is JS-gated to the mobile component; grew the
:root/mobile var set per DESIGN §9 instead of hand-picking hexes.

Verified: render-smoke green + a throwaway jsdom interaction harness mounting
the real app at 375px (list/grouping/sort-sheet/detail/back, 14/14). Deploy-
pending (folds into the next s9pk with P0/P1/view-reorder).
This commit is contained in:
Keysat
2026-06-19 13:57:05 -05:00
parent 4ed16ca828
commit 984b950f80
3 changed files with 547 additions and 11 deletions
+17 -6
View File
@@ -335,12 +335,23 @@ migration into each surface's build, behind one shared foundation step. No upfro
has no base font-size, so it lands as each surface is re-authored (Phases 25); (c) the
`[data-theme="light"]` block → Phase 6 (dead without the toggle). Browser-interaction (the bar on a real
phone) untested, like view-reorder.
- **Phase 2 — Contacts (pattern-validator spike, BEFORE the Grid).** ~17 inline styles; read-only AZ
list + segmented tabs + search → full-screen read-only detail. Proves the list→detail→sheet pattern
and the per-surface migration mechanics on the lowest-risk surface before the crux. *(Reorders the
earlier "Grid first" draft — de-risk the pattern cheaply, then attack the Grid.)* Also lands the
**`<BottomSheet>` React component + `useIsMobile()` hook** (deferred from Phase 1, first consumed here,
built against the Phase 1 `.bottom-sheet` CSS) and this surface's **15px type bump**.
- **Phase 2 — Contacts (pattern-validator spike, BEFORE the Grid) — BUILT 2026-06-19 (deploy pending).**
Read-only AZ directory (sticky letter headers, sorted/sectioned by last name) + segmented
All/Investors/Prospects tabs + pinned search → **full-screen read-only detail** (`.fs-detail`, promotes
the slide-over: contact info w/ tap-to-copy email, opportunities, communication history) → **sort
BottomSheet** (the sheet primitive's first, read-only consumer: Name AZ / ZA / Recently-contacted —
restores the column-sort the card list loses). Proves the list→detail→sheet pattern + per-surface
migration mechanics on the lowest-risk surface before the crux. *(Reordered ahead of the earlier "Grid
first" draft.)* **Lands the shared primitives** (deferred from Phase 1, designed against this first
consumer — no dead code): **`<BottomSheet>`** (scrim/Escape/**pointer drag-to-dismiss**, mount enter/exit
animation, built on the Phase-1 `.bottom-sheet` CSS) + **`useIsMobile()`** (768px `matchMedia`; surfaces
swap via a rules-of-hooks-safe wrapper — `ContactsPage``Desktop`/`MobileContactsPage`, **zero desktop
change**). This surface's **15px body bump** lands on `.mobile-screen`. Writes: **none** — Contacts is
read-only on mobile per `BRIEF.md` §3b (create/edit live on the Grid). Grew the `:root`/mobile var set
(`--bg-input`, `--accent-light`, mobile card/control radii + card/screen/detail-title fonts) per DESIGN §9.
Verified: render-smoke green + a throwaway jsdom interaction harness (mounted the real app at 375px,
stubbed `/api/contacts` — list/grouping/sort-sheet/detail/back all asserted, 14/14). **No browser/real-phone
check yet** (same deferral as Phase 1 + view-reorder). **Deploy:** folds into the next s9pk build.
- **Phase 3 — Fundraising Grid (the crux).** ~70 inline styles → classes. Card list + bottom-sheet view
picker + search; full-screen detail with per-field bottom-sheet edits (name, contact pills, stage,
reminder, log note) + the `+`-create flow with client-side dedup typeahead. **Writes per `BRIEF.md`