Skip to content
Merged
26 changes: 13 additions & 13 deletions docs/search-chrome-behaviour.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -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
Expand Down
5 changes: 3 additions & 2 deletions docs/site-map.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -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`.
Expand DownExpand Up@@ -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. |
Expand DownExpand Up@@ -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`.
Expand Down
13 changes: 13 additions & 0 deletions mockups/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -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
Expand Down
7 changes: 5 additions & 2 deletions scripts/generate-site-map.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,7 @@ const consolidatedRedirectTargets = Object.fromEntries(
);

/*
* The four `<mode>/search` routes with no browse view. Conditional, not absolute:
* The `<mode>/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.
*/
Expand DownExpand Up@@ -89,6 +89,8 @@ const routeDescriptions: Record<string, string> = {
"/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":
Expand DownExpand Up@@ -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",
Expand Down
19 changes: 5 additions & 14 deletions src/app/(search-app)/calculators/search/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -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",
Expand All@@ -26,21 +24,21 @@ function toURLSearchParams(params: Awaited<CalculatorsSearchParams>) {
}

/**
* 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);
Expand All@@ -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 <CalculatorsSearchPage initialQuery={query} />;
}
3 changes: 2 additions & 1 deletion src/app/(search-app)/differentials/search/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -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.
*/
Expand Down
13 changes: 13 additions & 0 deletions src/app/mockups/calculators-show-all/page.tsx
Original file line numberDiff line numberDiff line change
@@ -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 <CalculatorsShowAllDirectionsMockup />;
}
5 changes: 5 additions & 0 deletions src/app/mockups/mockups-layout-client.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -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.
Expand DownExpand Up@@ -121,6 +124,7 @@ export function MockupsLayoutClient({ children }: { children: ReactNode }) {
!isDocumentNavigationContractMockup &&
!isUniversalSearchRedesignMockup &&
!isCalculatorsSearchPageMockup &&
!isCalculatorsShowAllMockup &&
!isPhoneInPageNavigationMockup &&
!isSearchBandDirectionsMockup &&
!isServicesFilterRefinedMockup &&
Expand All@@ -145,6 +149,7 @@ export function MockupsLayoutClient({ children }: { children: ReactNode }) {
chromeVisible={
!isSourceOverlayRedesignMockup &&
!isToolsSearchDirectionsMockup &&
!isCalculatorsShowAllMockup &&
!isSearchHeadingMockup &&
!isSearchRefineAdaptiveMockup &&
!isSearchBandDirectionsMockup &&
Expand Down
Loading
Loading