diff --git a/docs/search-chrome-behaviour.md b/docs/search-chrome-behaviour.md index 7e64feedcc..10ef2f4ee0 100644 --- a/docs/search-chrome-behaviour.md +++ b/docs/search-chrome-behaviour.md @@ -4,19 +4,19 @@ This repo uses one shared search experience across the global shell, dashboard r ## Page ownership model -| Page state | Composer placement | Reserve owner | -| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| Shared home (`/`, any mode) / standalone mode homes | In-flow hero composer on phones and larger breakpoints | Page content; no fixed phone dock reserve | -| Tools directory (`/tools`) and legacy alias (`/?mode=tools`) | No shared composer or phone dock; browse and filter through page-local catalogue controls | Idle shell padding only | -| Therapy Recommend (`/therapy-compass/recommend`) | In-flow clinical-situation composer; no shared composer or phone dock | Idle shell padding only | -| Submitted/search-result views | Compact bottom dock on phones; in normal page flow on tablets and desktops | Shell/dashboard `--mobile-composer-reserve` on phones; page content on desktop | -| Answer result view | Overlaid glass header plus answer composer dock | Dashboard `#main-content` top/bottom reserves | -| Document detail/source routes | `DocumentViewer` floating composer | `DocumentViewer` content padding | -| Document section navigation | Header row disclosure (phone sheet) + rail index card at `lg` | None — adds no chrome and no reserve | -| Record page breadcrumb header | Same header row without the disclosure or track; view mode inline from `sm` | None — portals into the phone collapse row, sticky at `sm+` | -| Calculators (`/calculators`) | In-flow hero composer at home; shared compact dock after submission | Page content at home; shell reserve for submitted results | -| Info/detail pages with no composer | No fixed composer | Idle shell padding only | -| Guide Centre dialog (`GuideDialog`) | No composer — tour-action dock inside the Sheet footer; Sheet footer band from `sm` | `[data-guide-content]` bottom pad (`guide-tour-dock` reserve owner) | +| Page state | Composer placement | Reserve owner | +| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| Shared home (`/`, any mode) / standalone mode homes | In-flow hero composer on phones and larger breakpoints | Page content; no fixed phone dock reserve | +| Tools directory (`/tools`) and legacy alias (`/?mode=tools`) | No shared composer or phone dock; browse and filter through page-local catalogue controls | Idle shell padding only | +| Therapy Recommend (`/therapy-compass/recommend`) | In-flow clinical-situation composer; no shared composer or phone dock | Idle shell padding only | +| Submitted/search-result views | Compact bottom dock on phones; in normal page flow on tablets and desktops | Shell/dashboard `--mobile-composer-reserve` on phones; page content on desktop | +| Answer result view | Overlaid glass header plus answer composer dock | Dashboard `#main-content` top/bottom reserves | +| Document detail/source routes | `DocumentViewer` floating composer | `DocumentViewer` content padding | +| Document section navigation | Header row disclosure (phone sheet) + rail index card at `lg` | None — adds no chrome and no reserve | +| Record page breadcrumb header | Same header row without the disclosure or track; view mode inline from `sm` | None — portals into the phone collapse row, sticky at `sm+` | +| Calculators (`/calculators`) | In-flow hero composer at home; shared compact dock on `/calculators/search` (browse or submitted) | Page content at home; shell reserve for the catalogue and submitted results | +| Info/detail pages with no composer | No fixed composer | Idle shell padding only | +| Guide Centre dialog (`GuideDialog`) | No composer — tour-action dock inside the Sheet footer; Sheet footer band from `sm` | `[data-guide-content]` bottom pad (`guide-tour-dock` reserve owner) | The Tools row is scoped to the **mounted Tools directory**, not to `resultKind: "tools"`. Factsheets, Dictionary and Therapy Compass borrow that result kind purely as a benign search kind, and on the diff --git a/docs/site-map.md b/docs/site-map.md index 6602ceb5ad..9fbed38f10 100644 --- a/docs/site-map.md +++ b/docs/site-map.md @@ -6,7 +6,7 @@ This file is generated by `npm run docs:update` (or `npm run sitemap:update` dir - `/` - Main Clinical KB shell. Source: `src/app/(search-app)/page.tsx`. - `/calculators` - Compatibility redirect to the shared home at `/?mode=calculators`; a submitted `?q=…&run=1` forwards to `/calculators/search`. Source: `src/app/(search-app)/calculators/page.tsx`. -- `/calculators/search` - Submitted calculators results. An empty query forwards to `/?mode=calculators` so the retired mode home is not rendered a second time. Source: `src/app/(search-app)/calculators/search/page.tsx`. +- `/calculators/search` - Browsable calculator catalogue and scored results. An empty query lists every calculator; a submitted query narrows the same list. Source: `src/app/(search-app)/calculators/search/page.tsx`. - `/caring-contacts` - Caring Contacts workspace — a synthetic, non-clinical demonstration of caring-contact follow-up. Standalone: it owns its own navigation and is entered from the Tools catalogue. Source: `src/app/caring-contacts/page.tsx`. - `/dictionary` - Compatibility redirect to the shared home at `/?mode=dictionary`; a submitted `?q=…&run=1` forwards to `/dictionary/search`. Source: `src/app/(search-app)/dictionary/page.tsx`. - `/dictionary/browse` - Compatibility redirect to `/dictionary/search`, which is now the whole catalogue; the query string is carried across. Source: `src/app/(search-app)/dictionary/browse/page.tsx`. @@ -103,7 +103,7 @@ This file is generated by `npm run docs:update` (or `npm run sitemap:update` dir | Formulation | `/?mode=formulation` | `/formulation/search?q=I+keep+going+over+it&focus=1&run=1` | `/formulation/[slug]`, `/formulation/builder`, `/formulation/compare`, and `/formulation/map`. | | Medication | `/medications` | `/?mode=prescribing&q=acamprosate+renal+dose&focus=1&run=1` | `/medications/[slug]`; submitted searches resolve to `/?mode=prescribing&q=…&run=1`. | | Tools | `/tools` | `/tools?q=medications&focus=1&run=1` | Canonical all-tools results directory at `/tools`; the universal mode picker opens it directly. `/?mode=tools` remains a dashboard-mode alias. | -| Calculators | `/?mode=calculators` | `/calculators/search?q=PHQ-9&focus=1&run=1` | `/calculators/search` scored results; an empty query forwards back to the shared home. | +| Calculators | `/?mode=calculators` | `/calculators/search?q=PHQ-9&focus=1&run=1` | `/calculators/search` is the browsable calculator catalogue and scored-results surface; an empty query lists every calculator. | | Factsheets | `/?mode=factsheets` | `/factsheets/search?q=sertraline&focus=1&run=1` | `/factsheets/search` is also a query-free browse surface linked from the mode nav; `/factsheets/[slug]` records. | | Dictionary | `/?mode=dictionary` | `/dictionary/search?q=MSE&focus=1&run=1` | `/dictionary/search` is one catalogue for both searching and browsing; `/dictionary/browse` redirects to it. Also `/topics`, `/topics/[slug]`, `/compare`, `/sources` and `/dictionary/[slug]` records. | | Therapy Compass | `/?mode=therapy-compass` | `/therapy-compass/search?q=CBT&focus=1&run=1` | Keeps a home of its own at `/therapy-compass`; `/search` (query-free browse), `/recommend`, `/compare`, `/pathways`, `/review`, and `/[slug]` records with `/brief` and `/sheet` outputs. | @@ -1157,6 +1157,7 @@ This file is generated by `npm run docs:update` (or `npm run sitemap:update` dir - `/mockups/calculators-popup-sheet` - Route discovered from app directory Source: `src/app/mockups/calculators-popup-sheet/page.tsx`. - `/mockups/calculators-search` - Route discovered from app directory Source: `src/app/mockups/calculators-search/page.tsx`. - `/mockups/calculators-search-page` - Route discovered from app directory Source: `src/app/mockups/calculators-search-page/page.tsx`. +- `/mockups/calculators-show-all` - Route discovered from app directory Source: `src/app/mockups/calculators-show-all/page.tsx`. - `/mockups/care-plan` - Route discovered from app directory Source: `src/app/mockups/care-plan/page.tsx`. - `/mockups/care-plan/governance` - Route discovered from app directory Source: `src/app/mockups/care-plan/governance/page.tsx`. - `/mockups/care-plan/patients` - Route discovered from app directory Source: `src/app/mockups/care-plan/patients/page.tsx`. diff --git a/mockups/README.md b/mockups/README.md index f8316a5f6c..a8fd2d1ac1 100644 --- a/mockups/README.md +++ b/mockups/README.md @@ -25,6 +25,19 @@ Runnable mockups under `src/app/mockups/*` inherit the shared Clinical KB header - The bottom composer routes live searches to the dashboard with `mode`, `q`, and `run=1`; New chat routes to `/?mode=answer&focus=1`. - If a future mockup must be standalone, move it outside the `/mockups` route shell or add an explicit opt-out route group before implementing it. +## Calculators Show all chip (2026-08-24) + +Three phone homes at [`/mockups/calculators-show-all`](../src/app/mockups/calculators-show-all/page.tsx). The page is +the Tools launcher with Calculators copy. Only the **Show all** chip changes. + +| Style | Chip | +| --------------- | ---------------------------------------------------------------- | +| 01 Recommended | Soft 14% accent tint + hairline well, 36px capsule, 48px tap | +| 02 Soft capsule | Option 2 polished — whisper fill, no well, optical `pl-3.5 pr-4` | +| 03 Quiet well | Option 3 polished — well only, no pill fill | + +Shared mockup chrome is suppressed because each frame draws its own top bar and composer. + ## Production behavior - Ordinary `/mockups/*` prototype routes return 404 in production. Explicit developer-gated subtrees and the isolated diff --git a/scripts/generate-site-map.ts b/scripts/generate-site-map.ts index ef97f97113..16c364a465 100644 --- a/scripts/generate-site-map.ts +++ b/scripts/generate-site-map.ts @@ -57,7 +57,7 @@ const consolidatedRedirectTargets = Object.fromEntries( ); /* - * The four `/search` routes with no browse view. Conditional, not absolute: + * The `/search` routes with no browse view. Conditional, not absolute: * they forward only when the query is empty, and render results otherwise — so * they are described rather than listed as plain redirects. */ @@ -89,6 +89,8 @@ const routeDescriptions: Record = { "/caring-contacts": "Caring Contacts workspace — a synthetic, non-clinical demonstration of caring-contact follow-up. Standalone: it owns its own navigation and is entered from the Tools catalogue.", "/calculators": "Psychiatry rating scale scoring and clinical decision calculators.", + "/calculators/search": + "Browsable calculator catalogue and scored results. An empty query lists every calculator; a submitted query narrows the same list.", "/dictionary": "Clinical dictionary home with term search and category navigation.", "/dictionary/[slug]": "Source-governed clinical term definition, distinction, and reference detail.", "/dictionary/browse": @@ -498,7 +500,8 @@ function renderModePageIndex() { mode: "Calculators", home: appModeHomeHref("calculators"), search: appModeHomeHref("calculators", { query: "PHQ-9", focus: true, run: true }), - detail: "`/calculators/search` scored results; an empty query forwards back to the shared home.", + detail: + "`/calculators/search` is the browsable calculator catalogue and scored-results surface; an empty query lists every calculator.", }, { mode: "Factsheets", diff --git a/src/app/(search-app)/calculators/search/page.tsx b/src/app/(search-app)/calculators/search/page.tsx index 223ad86d0a..e197171f42 100644 --- a/src/app/(search-app)/calculators/search/page.tsx +++ b/src/app/(search-app)/calculators/search/page.tsx @@ -2,8 +2,6 @@ import type { Metadata } from "next"; import { redirect } from "next/navigation"; import { CalculatorsSearchPage } from "@/components/calculators"; -import { appModeSelectionHref } from "@/lib/app-modes"; -import { unsubmittedModeSearchTargetForSearchParams } from "@/lib/consolidated-mode-home-redirect"; export const metadata: Metadata = { title: "Search clinical calculators | Clinical KB", @@ -26,21 +24,21 @@ function toURLSearchParams(params: Awaited) { } /** - * Submitted calculator searches. + * Calculator catalogue and submitted searches. * * Split out of the bare `/calculators` path when that became a redirect onto the * shared home: results need a route of their own, or `appModeHomeHref` would send * a submitted query back through the redirect and loop. * - * The legacy `?query=` canonicalisation moves with the results rather than staying - * behind on the redirect stub, so an old deep link still lands on `?q=` here - * instead of being normalised against a path that no longer renders anything. + * An empty query is now the browsable catalogue (the Tools `/tools` analogue), + * so Show all on the shared Calculators home can land here. The legacy `?query=` + * canonicalisation stays on this route so an old deep link still lands on `?q=`. */ export default async function CalculatorsSearchRoute({ searchParams }: { searchParams: CalculatorsSearchParams }) { const resolvedSearchParams = await searchParams; const primaryQuery = readFirstSearchParam(resolvedSearchParams.q)?.trim(); const legacyQuery = readFirstSearchParam(resolvedSearchParams.query)?.trim(); - const query = primaryQuery || legacyQuery; + const query = primaryQuery || legacyQuery || ""; if (resolvedSearchParams.query !== undefined) { const canonicalSearchParams = toURLSearchParams(resolvedSearchParams); @@ -51,12 +49,5 @@ export default async function CalculatorsSearchRoute({ searchParams }: { searchP redirect(suffix ? `/calculators/search?${suffix}` : "/calculators/search"); } - if (!query) { - redirect( - unsubmittedModeSearchTargetForSearchParams("/calculators/search", resolvedSearchParams) ?? - appModeSelectionHref("calculators"), - ); - } - return ; } diff --git a/src/app/(search-app)/differentials/search/page.tsx b/src/app/(search-app)/differentials/search/page.tsx index 06201fa4a3..0a5f5402b9 100644 --- a/src/app/(search-app)/differentials/search/page.tsx +++ b/src/app/(search-app)/differentials/search/page.tsx @@ -25,7 +25,8 @@ function firstValue(value?: string | string[]) { * home: results need a route of their own, or `appModeHomeHref` would send a * submitted query back through the redirect and loop. An empty query has no * browse view of its own — diagnoses and presentations are separate tabs — so - * it forwards to the shared home the same way `/calculators/search` does. + * it forwards to the shared home. `/calculators/search` is a browse catalogue + * on an empty query and no longer shares this redirect. * The proxy issues the 307; this page-level redirect is the backstop and uses * the same target builder so navigation context is not dropped. */ diff --git a/src/app/mockups/calculators-show-all/page.tsx b/src/app/mockups/calculators-show-all/page.tsx new file mode 100644 index 0000000000..2fb4a04a25 --- /dev/null +++ b/src/app/mockups/calculators-show-all/page.tsx @@ -0,0 +1,13 @@ +import type { Metadata } from "next"; + +import { CalculatorsShowAllDirectionsMockup } from "@/components/calculator-mockups"; + +export const metadata: Metadata = { + title: "Calculators Show all buttons - Clinical KB", + description: + "Recommended Show all chip plus two polished phone alternatives. The homes are identical except the chip.", +}; + +export default function CalculatorsShowAllMockupRoute() { + return ; +} diff --git a/src/app/mockups/mockups-layout-client.tsx b/src/app/mockups/mockups-layout-client.tsx index 010a9f93fe..4671e72144 100644 --- a/src/app/mockups/mockups-layout-client.tsx +++ b/src/app/mockups/mockups-layout-client.tsx @@ -81,6 +81,9 @@ export function MockupsLayoutClient({ children }: { children: ReactNode }) { // at the bottom on phones), so the shared universal composer is suppressed here // to avoid a second, floating search bar. const isCalculatorsSearchPageMockup = pathname === "/mockups/calculators-search-page"; + // Draws its own phone chrome, hero, Show all chip, and composer inside every + // frame. Shared header + composer would read as a second live home over the study. + const isCalculatorsShowAllMockup = pathname === "/mockups/calculators-show-all"; // Draws its own top bar, composer and results band inside every device frame, because two of // the three directions restructure that band. Shared chrome above them would read as a second, // real header and a second real composer over the study. @@ -121,6 +124,7 @@ export function MockupsLayoutClient({ children }: { children: ReactNode }) { !isDocumentNavigationContractMockup && !isUniversalSearchRedesignMockup && !isCalculatorsSearchPageMockup && + !isCalculatorsShowAllMockup && !isPhoneInPageNavigationMockup && !isSearchBandDirectionsMockup && !isServicesFilterRefinedMockup && @@ -145,6 +149,7 @@ export function MockupsLayoutClient({ children }: { children: ReactNode }) { chromeVisible={ !isSourceOverlayRedesignMockup && !isToolsSearchDirectionsMockup && + !isCalculatorsShowAllMockup && !isSearchHeadingMockup && !isSearchRefineAdaptiveMockup && !isSearchBandDirectionsMockup && diff --git a/src/components/applications-launcher-page.tsx b/src/components/applications-launcher-page.tsx index f2f1e58b44..cdbbde1ce6 100644 --- a/src/components/applications-launcher-page.tsx +++ b/src/components/applications-launcher-page.tsx @@ -20,6 +20,7 @@ import { cardInteractive, cardSelected, cardSelectedDanger, focusRing } from "@/ import { CategoryIconTile } from "@/components/category-icon-tile"; import { DesktopComposerPortalSlot } from "@/components/desktop-composer-portal-slot"; import { ModeHomeHero } from "@/components/mode-home-template"; +import { ShowAllChip } from "@/components/show-all-chip"; import { SearchResultsHeaderBand } from "@/components/clinical-dashboard/search-results-header-band"; import { ResultFilterSheet, @@ -834,18 +835,13 @@ export function ApplicationsLauncherWorkspace({ headingLevel={1} /> - -