From 7dfccbaefec8bb9686697d39d470e6f270bbe32a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Jul 2026 19:12:30 +0000 Subject: [PATCH 1/3] feat(search): collapse cross-mode matches into a phone toggle and tidy sort control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On phones the "Also matches in other modes" panel now renders as a collapsible disclosure (collapsed by default) with a count badge and a rotating chevron so it reads clearly as a toggle instead of consuming a full stacked grid. Desktop keeps the always-open four-column grid, so the toggle state only governs the narrow-viewport layout. Also restyles the results sort control: the native onChange(readResultSort(event.target.value))} - className="bg-transparent text-xs font-bold text-[color:var(--text)] outline-none" + className="cursor-pointer appearance-none bg-transparent text-xs font-bold text-[color:var(--text)] outline-none [-webkit-appearance:none]" aria-label="Sort results" > + ); } diff --git a/src/components/clinical-dashboard/universal-search-also-matches.tsx b/src/components/clinical-dashboard/universal-search-also-matches.tsx index aacee86ba..ccc8b392b 100644 --- a/src/components/clinical-dashboard/universal-search-also-matches.tsx +++ b/src/components/clinical-dashboard/universal-search-also-matches.tsx @@ -1,6 +1,8 @@ "use client"; import Link from "next/link"; +import { ChevronDown } from "lucide-react"; +import { useId, useState } from "react"; import { useUniversalSearch } from "@/components/clinical-dashboard/use-universal-search"; import { cn } from "@/components/ui-primitives"; @@ -25,6 +27,11 @@ export function UniversalSearchAlsoMatches({ excludeDomains: universalSearchPreferredDomains(modeId), limitPerDomain: 2, }); + const panelId = useId(); + // Collapsed by default on phones so this cross-mode panel does not push the + // primary results down; desktop always shows the grid (see the sm: rules below), + // so the toggle state only governs the narrow-viewport disclosure. + const [expanded, setExpanded] = useState(false); const preferred = new Set(universal.preferredDomains ?? []); const groups = (() => { const groupByDomain = new Map(universal.groups.map((group) => [group.kind, group])); @@ -63,11 +70,40 @@ export function UniversalSearchAlsoMatches({ aria-label="Matches in other modes" data-testid="universal-also-matches" > -
-

Also matches in other modes

- Across Clinical KB -
-
+ +
{groups.map((group) => { const targetModeId = group.modeId; const targetMode = appModeDefinition(targetModeId); From 92174f25871ea3fc2e34715324ff6790812f36a0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Jul 2026 19:14:57 +0000 Subject: [PATCH 2/3] style: apply prettier formatting to cross-mode matches panel Collapse the single-line className cn() call flagged by prettier --check in CI (Static PR checks / format:check). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01H8VhDNjeDXJaVnwufhRKLV --- .../clinical-dashboard/universal-search-also-matches.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/clinical-dashboard/universal-search-also-matches.tsx b/src/components/clinical-dashboard/universal-search-also-matches.tsx index ccc8b392b..f79b6903a 100644 --- a/src/components/clinical-dashboard/universal-search-also-matches.tsx +++ b/src/components/clinical-dashboard/universal-search-also-matches.tsx @@ -99,10 +99,7 @@ export function UniversalSearchAlsoMatches({
{groups.map((group) => { const targetModeId = group.modeId; From d27c4568088a003a69896650f6f4515c46fc050d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Jul 2026 19:42:58 +0000 Subject: [PATCH 3/3] a11y(search): make cross-mode header inert on desktop where panel is always open The disclosure button reported aria-expanded=false on desktop even though the sm:grid panel is always visible, and stayed clickable/focusable with no visible effect. Track the sm breakpoint via matchMedia and, on desktop, report aria-expanded=true, drop the button from the tab order (tabIndex -1), and add sm:pointer-events-none so screen-reader and keyboard users see the header as static copy rather than a collapsed control. Phone behaviour is unchanged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01H8VhDNjeDXJaVnwufhRKLV --- .../universal-search-also-matches.tsx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/clinical-dashboard/universal-search-also-matches.tsx b/src/components/clinical-dashboard/universal-search-also-matches.tsx index f79b6903a..8cf330151 100644 --- a/src/components/clinical-dashboard/universal-search-also-matches.tsx +++ b/src/components/clinical-dashboard/universal-search-also-matches.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { ChevronDown } from "lucide-react"; -import { useId, useState } from "react"; +import { useEffect, useId, useState } from "react"; import { useUniversalSearch } from "@/components/clinical-dashboard/use-universal-search"; import { cn } from "@/components/ui-primitives"; @@ -32,6 +32,18 @@ export function UniversalSearchAlsoMatches({ // primary results down; desktop always shows the grid (see the sm: rules below), // so the toggle state only governs the narrow-viewport disclosure. const [expanded, setExpanded] = useState(false); + // Track the sm breakpoint (640px) so the header's disclosure semantics match + // reality: on desktop the grid is always visible, so the button reports + // expanded and drops out of the interaction/tab flow rather than claiming to + // be a collapsed control the user can toggle to no effect. + const [isWide, setIsWide] = useState(false); + useEffect(() => { + const query = window.matchMedia("(min-width: 640px)"); + const sync = () => setIsWide(query.matches); + sync(); + query.addEventListener("change", sync); + return () => query.removeEventListener("change", sync); + }, []); const preferred = new Set(universal.preferredDomains ?? []); const groups = (() => { const groupByDomain = new Map(universal.groups.map((group) => [group.kind, group])); @@ -72,14 +84,17 @@ export function UniversalSearchAlsoMatches({ >