Skip to content

feat(ui): compact bottom search dock on phones everywhere except the home hero#964

Merged
BigSimmo merged 9 commits into
mainfrom
claude/mobile-search-bar-redesign-pxf7b3
Jul 20, 2026
Merged

feat(ui): compact bottom search dock on phones everywhere except the home hero#964
BigSimmo merged 9 commits into
mainfrom
claude/mobile-search-bar-redesign-pxf7b3

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • On phones (<640px), every search surface now uses the compact single-row bottom pill (the style previously reserved for submitted result views): standalone and dashboard mode homes (/services, /forms, /differentials, /dsm, /specifiers, /formulation, /factsheets, /therapy-compass, /tools, /favourites, /?mode=…) stop portaling the composer into the hero below sm and dock it at the bottom edge instead; the answer conversation dock joins the compact treatment whenever its follow-up chip row is absent.
  • The home page (/ answer home, "How can I help?") is the only phone surface that keeps the in-flow hero pill, and it is now also the only phone surface showing the APP-5 "Do not enter patient-identifiable information" notice. Tablet/desktop composers are unchanged (hero from sm up, notice everywhere).
  • MasterSearchHeader gains a heroComposerBreakpoint prop ("all" | "sm-up") gating the hero-portal media query; sm-up hero hosts re-enable the phone bottom dock. Hide-on-scroll, the edge-to-edge blur scrim, safe-area handling, and the 0.75rem hidden pad are unchanged.
  • mobile-composer-reserve dock reserves unified (shellDock/dashboardDock, 5.5rem/5rem + safe-area); answer-dock reserves trimmed to the notice-free pill; the follow-up-row reserve (7.5rem) and differentials Compare reserve are unchanged.

Verification

  • npm run verify:pr-local — format, runtime, unit suite (2973 passed; 1 pre-existing container-only failure in tests/pdf-extraction-budget.test.ts reproduced identically on the unmodified base — Python child-tree termination, unrelated to this diff), plus npm run build + client-bundle secret scan run directly and passing
  • npm run verify:cheap — same single pre-existing failure, all other checks pass
  • UI verification (Chromium, targeted, includes npm run verify:ui spec set for the touched surfaces): ui-tools 84/84, ui-smoke + ui-accessibility + ui-overlap + ui-universal-search 130 passed with only the pre-existing PDF-canvas container failure (also reproduced on unmodified base), ui-formulation + ui-specifiers + ui-route-coverage 23/23. The full multi-browser verify:ui run was executed only for Chromium: this container lacks the pinned Playwright headless shell, so specs ran against /opt/pw-browsers/chromium via PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH.
  • npm run check:production-readiness — passes except expected missing-secret failures in this demo-mode container (no Supabase/OpenAI keys), per repo cloud notes
  • Typecheck and lint pass with zero warnings

Risk and rollout

  • Risk: phone-only layout change to the shared search composer. Main risks are content sliding under the visible dock (covered by updated reserve unit tests and dock-clearance Playwright specs) and the reduced visibility of the privacy notice on non-home phone surfaces (deliberate, per request — see Notes).
  • Rollback: revert this single commit; no data, schema, API, or provider changes.
  • Provider or production effects: None.

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed

Notes

  • Preflight context: answer/citation and source-verification behavior is untouched; no env/config or Supabase changes; no clinical decision-support behavior changed. The APP-5 input notice is now phone-home-only by explicit product request — it remains on the home entry composer, on all tablet/desktop composers, and on /privacy. Flagged here for governance awareness since phone deep links to non-home surfaces no longer show the inline notice.
  • The data-footer-variant="compact" attribute now applies to every phone dock (including the answer dock without follow-ups), so the compact scrim/padding CSS is shared rather than duplicated.
  • Playwright specs encoding the old "hero on phones" design were updated: phone mode homes now assert the compact bottom dock; tablet keeps the hero assertions.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SF3LtSFni9tbBCkBxGazkr

Summary by CodeRabbit

  • New Features
    • Enhanced responsive search/composer behavior with a new breakpoint-controlled “hero vs compact dock” mode for mode-home screens.
    • Non-answer mobile home routes now consistently use the compact bottom search dock, with updated spacing that supports follow-up chips.
  • Bug Fixes
    • Improved privacy notice behavior on phones so it appears in the correct hero area without showing on non-home docks.
    • Adjusted mobile dock padding/reserve so bottom clearance is handled consistently across view modes.
  • Tests
    • Updated and expanded smoke and unit tests to validate mobile/tablet/desktop dock placement, ordering, variants, and follow-up logic.

…home hero

On phones (<640px) every search surface now uses the compact single-row
bottom pill (the submitted-results dock style): standalone and dashboard
mode homes stop portaling the composer into the hero below sm and dock it
at the bottom edge instead, and the answer conversation dock drops to the
compact treatment whenever its follow-up chip row is absent. The home page
("How can I help?") is the only phone surface that keeps the in-flow hero
pill, and it is now also the only phone surface showing the APP-5
"Do not enter patient-identifiable information" notice; tablet/desktop
composers keep the notice everywhere as before.

- MasterSearchHeader: new heroComposerBreakpoint prop ("all" | "sm-up")
  gates the hero portal media query and re-enables the phone dock for
  sm-up hero hosts; phone privacy notice scoped to the home hero; answer
  dock joins the compact styling when no follow-up row renders
- Hosts: GlobalSearchShell and ClinicalDashboard always pass the compact
  dock variant, reserve dock clearance on phone mode homes, and keep the
  answer home on the "all" hero breakpoint
- mobile-composer-reserve: dock reserves unified (shellDock/dashboardDock,
  5.5rem/5rem + safe-area); answer reserves trimmed to the notice-free
  dock, follow-up row reserve unchanged
- Hide-on-scroll, edge-to-edge scrim, safe-area handling, and the hidden
  0.75rem pad are unchanged and covered by the updated Playwright specs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SF3LtSFni9tbBCkBxGazkr
@supabase

supabase Bot commented Jul 20, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 696b745e-495f-40f6-8ecd-a37b40c73be1

📥 Commits

Reviewing files that changed from the base of the PR and between e0092be and 7eab9a7.

📒 Files selected for processing (4)
  • src/app/globals.css
  • src/components/ClinicalDashboard.tsx
  • tests/ui-smoke.spec.ts
  • tests/ui-tools.spec.ts
💤 Files with no reviewable changes (1)
  • src/components/ClinicalDashboard.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/globals.css
  • tests/ui-tools.spec.ts

📝 Walkthrough

Walkthrough

Mobile composer behavior distinguishes phone docks from tablet/desktop hero composers. Reserve calculations, responsive header placement, page spacing, edge-to-edge styling, and UI tests are updated for answer and non-answer mode homes.

Changes

Mobile composer docking

Layer / File(s) Summary
Composer reserve contract
src/components/clinical-dashboard/mobile-composer-reserve.ts, tests/mobile-composer-reserve.test.ts
Reserve values and resolver inputs are standardized around shell and dashboard dock clearances, with coverage for answer follow-ups and differentials.
Responsive header composition
src/components/clinical-dashboard/master-search-header.tsx
MasterSearchHeader adds breakpoint-aware hero ownership, compact phone docking, follow-up row handling, and phone-specific privacy notice behavior.
Route spacing and validation
src/components/ClinicalDashboard.tsx, src/components/clinical-dashboard/global-search-shell.tsx, src/app/globals.css, tests/ui-tools.spec.ts, tests/ui-smoke.spec.ts
Dashboard and standalone routes use compact dock reserves and spacing, edge-to-edge styling covers dashboard docks, and responsive tests verify phone/tablet placement and clearance.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ClinicalDashboard
  participant GlobalStandaloneSearchShellClient
  participant MobileComposerReserve
  participant MasterSearchHeader
  ClinicalDashboard->>MobileComposerReserve: resolve dashboard dock reserve
  GlobalStandaloneSearchShellClient->>MobileComposerReserve: resolve shell dock reserve
  ClinicalDashboard->>MasterSearchHeader: configure answer or mode-home breakpoint
  GlobalStandaloneSearchShellClient->>MasterSearchHeader: configure sm-up hero and compact phone dock
  MasterSearchHeader->>MasterSearchHeader: render hero composer or bottom dock
Loading

Possibly related PRs

Suggested labels: codex

Suggested reviewers: claude, copilot, cursoragent

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main UI change: compact phone search dock behavior except the home hero.
Description check ✅ Passed The description follows the template with Summary, Verification, Risk and rollout, Clinical Governance Preflight, and Notes sections filled in.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/mobile-search-bar-redesign-pxf7b3

Comment @coderabbitai help to get the list of available commands.

@BigSimmo
BigSimmo marked this pull request as ready for review July 20, 2026 07:43
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@BigSimmo
BigSimmo enabled auto-merge (squash) July 20, 2026 07:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/clinical-dashboard/mobile-composer-reserve.ts (1)

23-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate literal reserve values risk silent drift.

shellAnswer/shellDock share the exact same string ("calc(5.5rem + var(--safe-area-bottom))"), and dashboardAnswer/dashboardDock share "calc(5rem + var(--safe-area-bottom))". This is intentional today (per the comment, the answer dock without follow-ups is supposed to match the generic compact dock), but master-search-header.tsx's usesCompactMobileBottomStyle relies on this equality holding implicitly — nothing in code enforces it. If either pair diverges later (e.g. tuning dashboardDock for a redesign but forgetting dashboardAnswer), the CSS-driven compact height and the JS-computed content reserve would silently disagree, causing overlap/gap bugs that are easy to miss in review.

Consider deriving the "answer, no follow-ups" values from the dock constants instead of duplicating the literal:

♻️ Suggested refactor
+const shellCompactSingleRowReserve = "calc(5.5rem + var(--safe-area-bottom))";
+const dashboardCompactSingleRowReserve = "calc(5rem + var(--safe-area-bottom))";
+
 export const mobileComposerVisibleReserve = {
-  shellAnswer: "calc(5.5rem + var(--safe-area-bottom))",
-  shellDock: "calc(5.5rem + var(--safe-area-bottom))",
+  shellAnswer: shellCompactSingleRowReserve,
+  shellDock: shellCompactSingleRowReserve,
   dashboardAnswerWithFollowUps: "calc(7.5rem + var(--safe-area-bottom))",
-  dashboardAnswer: "calc(5rem + var(--safe-area-bottom))",
-  dashboardDock: "calc(5rem + var(--safe-area-bottom))",
+  dashboardAnswer: dashboardCompactSingleRowReserve,
+  dashboardDock: dashboardCompactSingleRowReserve,
   differentialsCompare: mobileComposerDifferentialsCompareReserve,
 } as const;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/clinical-dashboard/mobile-composer-reserve.ts` around lines 23
- 30, Derive shellAnswer from shellDock and dashboardAnswer from dashboardDock
within mobileComposerVisibleReserve instead of repeating their literal reserve
strings. Preserve the existing equality between each answer/dock pair so
usesCompactMobileBottomStyle and the computed content reserve cannot silently
diverge.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/ui-tools.spec.ts`:
- Around line 1918-1919: Update the reserve assertion in the mobile composer
test to use a greater-than-or-equal comparison at 80px, allowing the documented
80px floor when the safe-area inset is zero.

---

Nitpick comments:
In `@src/components/clinical-dashboard/mobile-composer-reserve.ts`:
- Around line 23-30: Derive shellAnswer from shellDock and dashboardAnswer from
dashboardDock within mobileComposerVisibleReserve instead of repeating their
literal reserve strings. Preserve the existing equality between each answer/dock
pair so usesCompactMobileBottomStyle and the computed content reserve cannot
silently diverge.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 994f99cc-c113-4328-9595-5e490093c132

📥 Commits

Reviewing files that changed from the base of the PR and between 51e747e and d14b1aa.

📒 Files selected for processing (8)
  • src/app/globals.css
  • src/components/ClinicalDashboard.tsx
  • src/components/clinical-dashboard/global-search-shell.tsx
  • src/components/clinical-dashboard/master-search-header.tsx
  • src/components/clinical-dashboard/mobile-composer-reserve.ts
  • tests/mobile-composer-reserve.test.ts
  • tests/ui-smoke.spec.ts
  • tests/ui-tools.spec.ts

Comment thread tests/ui-tools.spec.ts Outdated
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

⚠️ Branch updated during autofix.

The branch was updated while autofix was in progress. Please try again.

claude and others added 4 commits July 20, 2026 07:56
… reserve assertions

Address CodeRabbit review: share one constant per shell/dashboard compact
reserve so the answer/dock pairs cannot silently diverge, and assert the
dock reserve with >= so a zero safe-area inset landing exactly on the
5rem/5.5rem floor cannot flake the service-detail clearance spec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SF3LtSFni9tbBCkBxGazkr
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found.

…bar-redesign-pxf7b3

# Conflicts:
#	tests/ui-tools.spec.ts
@BigSimmo

Copy link
Copy Markdown
Owner Author

@coderabbitai please resolve the merge conflict here for me.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

No merge conflicts detected when merging into main.

Your branch is good to go!

@BigSimmo
BigSimmo merged commit 6d11e53 into main Jul 20, 2026
17 checks passed
@BigSimmo
BigSimmo deleted the claude/mobile-search-bar-redesign-pxf7b3 branch July 20, 2026 08:44
BigSimmo added a commit that referenced this pull request Jul 20, 2026
…pse-budget gate) (#993)

* fix(ui): stop phone scroll locking to the bottom on mode homes (collapse-budget gate)

Since #964 docked the compact composer on phone mode homes, one hide-on-scroll
event releases ~180-260px of scroll geometry (72-130px header grid collapse +
~110px reserve-pad shrink, both animated). Mode-home content is short, so the
release exceeds the remaining scroll runway: scrollTop clamps straight onto the
new bottom edge, a 12px upward drag re-reveals and snaps the geometry back
under the finger, and the hide/reveal loop reads as "scroll locks to the
bottom" with a blank band below the content (reported on /formulation, iOS
installed PWA; reproduced and quantified in Chromium: runway 266->84 on hide,
2 chrome flips in a single gesture).

Fix: a collapse-budget gate in computeScrollHideUpdate. Hosts report how much
layout the chrome would release if it hid right now (readChromeCollapseBudget:
collapsible header strip + every dock-clearance pad above the shared 0.75rem
hidden size - shell reserve pad, DocumentViewer content pad, scroller-padding
fallback), and hiding is refused unless the remaining runway can absorb the
release plus the reveal-intent distance and slack. Short pages keep their
chrome and scroll plainly; long pages hide mid-scroll exactly as before but
can no longer start a hide at the bottom edge. The existing one-sided
bottom-clamp guard is untouched. Consumers that report no budget keep today's
behavior.

Also fixes a latent DocumentViewer bug the new sweep exposed: its one-shot
#main-content lookup could permanently hold a detached node when the shell
remounts the scroller, silently killing the viewer's hide-on-scroll. The
discovery observer now stays alive for the viewer's lifetime (childList-only,
deduped setState).

Guardrails:
- tests/ui-phone-scroll.spec.ts: 18-test sweep over all 10 standalone mode
  homes, the 3 dashboard modes, and 4 long routes at phone viewports with
  reducedMotion "no-preference" (the suite-wide "reduce" default disables the
  very transitions that caused this bug - that is how #964 shipped green) and
  simulated PWA safe-area insets. Asserts sole-scrollport, no horizontal
  overflow, true-bottom reachability, and bottom-edge nudge stability (at most
  one chrome flip). Verified to fail red against the pre-fix behavior.
- tests/use-hide-on-scroll.test.ts: oscillation reproduction harness plus
  runway-refusal, ample-runway, boundary, and budget-omitted back-compat cases.
- ui-smoke: bottom-hide scenario updated to the gate contract (hide with
  runway remaining, then ride the geometry clamp to the bottom while hidden).

Verified: vitest focused suites, ui-phone-scroll + ui-formulation + ui-tools +
ui-smoke (chromium), webkit advisory sweep, verify:cheap, verify:ui (264
passed), verify:pr-local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: record claude/phone-scroll-fix review in branch ledger

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ui): clear shell scroll container on remount; fail flip counter loudly

Addresses two CodeRabbit findings on #993:
- DocumentViewer kept a detached #main-content node across a two-step
  shell remount, leaving useHideOnScroll subscribed to a scroller that
  never fires. Syncing null lets it fall back to window.
- installFlipCounter returned early when the header selector missed,
  pinning the counter at 0 so flip assertions passed vacuously.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(ci): overlay-aware flip counter + restore DocumentViewer line budget

The answer home hides its glass header via the overlay strategy (header#search
carries data-scroll-hidden; no collapse wrapper exists), so the fail-loudly
flip counter must observe whichever chrome element the route renders.
Condense the DocumentViewer discovery comments back under the 3166-line
no-growth maintainability budget while keeping the remount rationale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants