[WIP] Tools-mockup + services-navigator design exploration - #247
Conversation
Rebuilds the stray design exploration originally rescued in claude/mockup-wip-rescue, cleanly on top of current main instead of its old, regressed base. Adds three new mockup concepts (tools-action-workbench, tools-clinical-lanes, services-navigator-preview) plus rectangle-direction-mockups and the supporting edits to master-search-header/document-search-live-opener/ tools-page-mockup-page. Dropped from the original rescue (verified against current main): - ClinicalDashboard.tsx / dashboard-shell.tsx: the only real edits (two arbitrary text-size values replaced with type-scale tokens) are already on main independently; the rest of those files' rescue content was built on a since-regressed intermediate commit and would have deleted functionality main has since gained. - global-mockup-search-shell.tsx, globals.css: already identical to main. Unreviewed exploratory work — needs a decision on whether to fold into feature/tools-page-mockups (#225), develop further standalone, or drop. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 185d96b4c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f5effb1d5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…xploration # Conflicts: # .gitignore # src/components/tools-page-mockups/tools-page-mockup-page.tsx
… view The "Evidence-linked" trust chip on the universal mobile footer wired to differentials-evidence, whose only handler (onOpenEvidence) opens the answer-mode evidence drawer — leaving differentials context instead of reviewing differential evidence. No differential-specific evidence view exists yet, so omit the chip rather than route somewhere misleading; differentials still gets a working footer action via the "Criteria" secondary chip. Scoped to the new footer only — mode-action-popup.tsx's pre-existing "+" menu entry for differentials-evidence is untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e716a02b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const [query, setQuery] = useState(defaultQuery); | ||
| const matches = useMemo(() => { | ||
| const ranked = searchServiceRecords(query); | ||
| return ranked.length ? ranked.map((match) => match.service) : serviceRecords; |
There was a problem hiding this comment.
Preserve empty service search results
When a non-empty query has no matching service records, searchServiceRecords(query) returns [], but this fallback treats that the same as the empty-query state and displays every service. On /services-navigator-preview, typing an unmatched term therefore reports all referral matches and shows unrelated contacts instead of an empty/no-match state; only fall back to serviceRecords when the trimmed query is empty.
Useful? React with 👍 / 👎.
| onQueryChange, | ||
| matches, | ||
| selectedSlugs, | ||
| onToggleSelected, |
There was a problem hiding this comment.
Remove the duplicate PhonePreview prop binding
This destructuring lists onToggleSelected twice in the same parameter binding, so TypeScript/Next cannot parse this new preview component and the app build fails before /services-navigator-preview can render. Keep only one binding for the prop.
Useful? React with 👍 / 👎.
…sign Four conflicts, resolved as the trial merge recorded in the PR body predicted. `search-screen.tsx` reduced to the handler alone, exactly as forecast: both sides had independently arrived at `--text-muted`, so the only disagreement left was `clearSearchFilters` (here) versus `clearSearch` (main). Kept this branch's — #1616 branched before defect #1611's sibling was fixed, and `clearSearch` on a control labelled `Clear` inside a filter row deletes the query the reader is looking at. `search-results-header-band.tsx` (2 hunks) took this branch: main's side is the pre-restructure shelf carrying only the token migration this branch had already applied. `document-search-results.tsx` (3 hunks): the two empty-state hunks took this branch's shared `SearchResultsEmptyState`. The import hunk is a genuine merge — v2 renamed `metadataPill` to `metadataPillDensity`, and the auto-merged body now calls `metadataPillDensity.roomyCompact`, so the import must follow. `EmptyState` is dropped from it because both of v2's call sites are the ones this branch replaced. `docs/outstanding-issues.md`: #1616 minted its own #237 and #238 from the same `next-id`, so both sides landed rows under both numbers. Renumbered *this* branch's to #246 and #247 and bumped the marker to 248, rather than taking one side wholesale — main's rows are already landed and referenced. This is the collision `#156` and `#168` predict; the guard caught it. Two v2 gates then failed on the merged tree and are now satisfied: - `check:design-system-contract` ratchets `textSoftConsumers` per file, and v2 had driven both of these to zero. The four remaining usages here are icons and glyphs, which this branch had deliberately left on `--text-soft` because v1 defined no decoration token. v2 defines `--decoration-soft`, so that constraint is gone and they move there — the tier v2 itself uses for the same nodes. - The generated adoption manifest and COMPONENTS.md maturity section went stale as a result; regenerated with `design-system:adoption:update`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qm3i3eLCDcwytzge1sKM4a
…tap floor Two sessions resolved the #1616 merge independently. The pushed one (`5c0fe4d`) failed `Static PR checks` on the outstanding-issues guard: #1616 minted its own #237 and #238 from the same `next-id`, and that resolution kept both sides under both numbers. This merge keeps the resolution that renumbers *this* branch's rows to #246/#247 and bumps the marker to 248 — main's are already landed and referenced, so they keep their numbers. The guard now passes: 245 rows, unique ids, next-id above the highest, no ids dropped from base 08595cc. The only other conflict was a duplicated comment block on the therapy quick-filter `Clear`; both sides already agreed on `--text-muted` and `clearSearchFilters`. Also fixes a review finding, which is a real inconsistency this branch introduced: the find-a-filter field shipped at `min-h-10` — 40px — in the very commit that raised the facets, the disclosure headings, the shelf `Clear` and the sheet footer to `min-h-tap` (48px). On the surface that exists for phones, the one control added to make a long filter list usable was the smallest target in the sheet. It now matches the facets exactly (`min-h-tap sm:min-h-9`). `decoration-on-text.contract.test.ts` had pinned that field by slicing 600 characters after its testid, so documenting the line broke the guard. It now walks forward to the element's own `className`, and additionally pins the tap floor so the 40px version cannot come back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qm3i3eLCDcwytzge1sKM4a
Six search modes plus the tools launcher shipped a `w-full` native `<select>` as their phone filter — formulation and specifiers passed two, in a two-column grid. That control cost the results band a whole second row, could not report how many filters were active, and, because the iOS anti-zoom rule in globals.css pins every native select to 16px below `sm`, rendered its value at the same size as the query heading above it. All seven now pass the badged trigger documents already used, so the one-line phone band is universal rather than a documents/therapy-compass exception. Verified in a real browser: the differentials band is geometrically identical to the documents band at 390px (89px), 414px and 430px (60px). The idiom is now shared rather than copied. `result-filter-control.tsx` holds `ResultFilterTrigger`, lifted verbatim from `DocumentFilterTrigger` so the control is the same component everywhere, and `ResultFilterSheet`, which renders one `role="radiogroup"` per dimension — real radio semantics, because these dimensions are one-of-N and a bank of `aria-pressed` toggles asserts they are not. Documents keeps its own panel: multi-select facet groups with counts, a find-a-filter field and collapse-by-default are not expressible as radios. Desktop is untouched. The ribbon renders `filterControls` from `sm` up and `mobileControls` below it, never both, so every mode keeps the chip row or tab strip it already had on a wide screen. `MobileResultFilterControl` is deleted; no caller remains. `mobileControlsPlacement` still defaults to `row` — nothing relies on that fallback now, and it stays so a mode that forgets the prop degrades to a second row rather than to an unreadable line. Closes outstanding-issues #247. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013mcqh46SDdiR5KxScihkFQ
Resolved docs/outstanding-issues.md conflict by keeping both sides' resolutions (#167, #247, #255 resolved; both removed from the open queue) and taking main's newer #253 text (reflects #247's resolution). Fixed TS errors surfaced by the merged main tsconfig: NODE_ENV missing from partial env objects in check-playwright-browser-revision.test.ts and verify-phone-chrome.test.ts, and a non-const shard array losing its literal type in playwright-pr-shards.test.ts.
Summary
tools-action-workbench,tools-clinical-lanes,services-navigator-preview, plusrectangle-direction-mockupsmaster-search-header.tsx,document-search-live-opener.tsx,tools-page-mockup-page.tsxContext
This is design exploration that was found stranded, uncommitted, in a shared checkout being used for an unrelated CI-fix task — not something I authored or was asked to build. I rebuilt it cleanly on top of current
main(the original had drifted onto a since-regressed intermediate commit) and verified it introduces no regressions:I dropped the parts of the original that were either already superseded on
main(a couple of type-scale token fixes, a.gitignorerule,global-mockup-search-shell.tsx/globals.csschanges — all landed independently elsewhere already) or built on regressed code (ClinicalDashboard.tsx/dashboard-shell.tsx).This is marked WIP deliberately. I'm not the design owner and have no basis to judge whether these concepts should ship, get folded into something else, or be closed — that call belongs to whoever was originally driving this exploration. Opening this as a PR is just to give it a visible, reviewable home instead of sitting as an easily-lost dangling branch.
Test plan
npm run typecheck— cleannpm run lint— 0 errorsnpm run format:check— clean🤖 Generated with Claude Code