mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
fix(coach): cap drawer width on lg+ and route sources rail via tray
The drawer's lg:max-w-[1080px] cap left only ~200-286px of underlying /insights visible on common laptop viewports (1280-1366px), turning the "keep dashboard context behind it" sheet into a near-takeover. Drop the lg cap to min(960px,75vw) with the inline sources rail hidden below xl — the rail still surfaces on lg via the existing mobile chevron tab. xl+ restores the full three-column layout. The history rail stays visible inline on lg+ (it's the more frequently referenced of the two). Update the SSR test contract to match: history trigger hides on lg+, sources trigger hides on xl+. Fixes Design-HIGH-1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8479e05a20
commit
f9af100d9d
3 files changed
+35
-14
No files matched your search
@@ -9,10 +9,13 @@ import { CoachDrawerBody } from "../coach-drawer-body";
|
|||||||
*
|
*
|
||||||
* The drawer hides the history + sources rails on `<lg`. B4 adds two
|
* The drawer hides the history + sources rails on `<lg`. B4 adds two
|
||||||
* chevron-button triggers along the edges of the message thread that
|
* chevron-button triggers along the edges of the message thread that
|
||||||
* open side-sheets surfacing the same rails. The triggers live on
|
* open side-sheets surfacing the same rails.
|
||||||
* `<CoachDrawerBody>` so the SSR test can pin their `lg:hidden` class
|
*
|
||||||
* + slot markers without rendering the outer Radix `<Sheet>` portal
|
* Phase D reconcile narrowed the lg drawer cap (was 1080px → now
|
||||||
* (which is client-only).
|
* min(960px,75vw)) so the inline sources rail no longer fits below
|
||||||
|
* xl. The history rail surfaces inline on lg; the sources rail
|
||||||
|
* surfaces inline on xl. Mobile chevron triggers cover the missing
|
||||||
|
* rails: history hidden on lg+, sources hidden on xl+.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function render(node: React.ReactNode, locale: "en" | "de" = "en") {
|
function render(node: React.ReactNode, locale: "en" | "de" = "en") {
|
||||||
@@ -37,7 +40,7 @@ describe("<CoachDrawerBody> — mobile rail trays", () => {
|
|||||||
expect(html).toMatch(/data-slot="coach-drawer-sources-tray-trigger"/);
|
expect(html).toMatch(/data-slot="coach-drawer-sources-tray-trigger"/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("hides both triggers on >=lg via the lg:hidden class", () => {
|
it("hides the history trigger on >=lg and the sources trigger on >=xl", () => {
|
||||||
const html = render(<CoachDrawerBody {...baseProps} />);
|
const html = render(<CoachDrawerBody {...baseProps} />);
|
||||||
const historyTrigger = html.match(
|
const historyTrigger = html.match(
|
||||||
/<button[^>]*data-slot="coach-drawer-history-tray-trigger"[^>]*>/,
|
/<button[^>]*data-slot="coach-drawer-history-tray-trigger"[^>]*>/,
|
||||||
@@ -49,16 +52,16 @@ describe("<CoachDrawerBody> — mobile rail trays", () => {
|
|||||||
/<button[^>]*data-slot="coach-drawer-sources-tray-trigger"[^>]*>/,
|
/<button[^>]*data-slot="coach-drawer-sources-tray-trigger"[^>]*>/,
|
||||||
);
|
);
|
||||||
expect(sourcesTrigger).not.toBeNull();
|
expect(sourcesTrigger).not.toBeNull();
|
||||||
expect(sourcesTrigger?.[0]).toContain("lg:hidden");
|
expect(sourcesTrigger?.[0]).toContain("xl:hidden");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders the desktop history + sources rails (visible on >=lg)", () => {
|
it("renders the desktop history rail (lg+) and sources rail (xl+)", () => {
|
||||||
const html = render(<CoachDrawerBody {...baseProps} />);
|
const html = render(<CoachDrawerBody {...baseProps} />);
|
||||||
expect(html).toMatch(
|
expect(html).toMatch(
|
||||||
/<aside[^>]*data-slot="coach-drawer-history"[^>]*lg:flex/,
|
/<aside[^>]*data-slot="coach-drawer-history"[^>]*lg:flex/,
|
||||||
);
|
);
|
||||||
expect(html).toMatch(
|
expect(html).toMatch(
|
||||||
/<aside[^>]*data-slot="coach-drawer-sources"[^>]*lg:flex/,
|
/<aside[^>]*data-slot="coach-drawer-sources"[^>]*xl:flex/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,11 @@ export function CoachDrawerBody({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="coach-drawer-body"
|
data-slot="coach-drawer-body"
|
||||||
className="grid min-h-0 flex-1 grid-cols-1 lg:grid-cols-[260px_1fr_280px]"
|
// v1.4.20 phase D reconcile — narrower drawer cap at lg means the
|
||||||
|
// sources rail no longer fits inline below xl. lg gets the
|
||||||
|
// history rail + thread (sources surface via the chevron tray);
|
||||||
|
// xl+ restores the full three-column layout.
|
||||||
|
className="grid min-h-0 flex-1 grid-cols-1 lg:grid-cols-[260px_1fr] xl:grid-cols-[260px_1fr_280px]"
|
||||||
>
|
>
|
||||||
{/* History rail — desktop only. Mobile users summon it via the
|
{/* History rail — desktop only. Mobile users summon it via the
|
||||||
tray trigger inside the thread column. */}
|
tray trigger inside the thread column. */}
|
||||||
@@ -71,6 +75,8 @@ export function CoachDrawerBody({
|
|||||||
<ChevronRight className="size-3" aria-hidden="true" />
|
<ChevronRight className="size-3" aria-hidden="true" />
|
||||||
{t("insights.coach.historyTitle")}
|
{t("insights.coach.historyTitle")}
|
||||||
</Button>
|
</Button>
|
||||||
|
{/* Sources tray trigger stays visible up to xl since the
|
||||||
|
inline sources rail is xl+ only. */}
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -78,7 +84,7 @@ export function CoachDrawerBody({
|
|||||||
onClick={onOpenSourcesTray}
|
onClick={onOpenSourcesTray}
|
||||||
data-slot="coach-drawer-sources-tray-trigger"
|
data-slot="coach-drawer-sources-tray-trigger"
|
||||||
aria-label={t("insights.coach.sourcesTitle")}
|
aria-label={t("insights.coach.sourcesTitle")}
|
||||||
className="bg-background/80 border-border/60 absolute right-2 top-2 z-10 h-7 gap-1 border px-2 text-[11px] backdrop-blur lg:hidden"
|
className="bg-background/80 border-border/60 absolute right-2 top-2 z-10 h-7 gap-1 border px-2 text-[11px] backdrop-blur xl:hidden"
|
||||||
>
|
>
|
||||||
{t("insights.coach.sourcesTitle")}
|
{t("insights.coach.sourcesTitle")}
|
||||||
<ChevronLeft className="size-3" aria-hidden="true" />
|
<ChevronLeft className="size-3" aria-hidden="true" />
|
||||||
@@ -94,10 +100,12 @@ export function CoachDrawerBody({
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
{/* Sources rail — desktop only. */}
|
{/* Sources rail — xl+ only. lg viewports surface it via the
|
||||||
|
mobile chevron tray to keep the underlying /insights column
|
||||||
|
readable behind the narrowed drawer cap. */}
|
||||||
<aside
|
<aside
|
||||||
data-slot="coach-drawer-sources"
|
data-slot="coach-drawer-sources"
|
||||||
className="border-border/70 hidden h-full min-h-0 border-l lg:flex lg:flex-col"
|
className="border-border/70 hidden h-full min-h-0 border-l xl:flex xl:flex-col"
|
||||||
>
|
>
|
||||||
{sourcesRail}
|
{sourcesRail}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -134,7 +134,15 @@ export function CoachDrawer({
|
|||||||
showCloseButton
|
showCloseButton
|
||||||
data-slot="coach-drawer"
|
data-slot="coach-drawer"
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full p-0 sm:max-w-[720px] lg:max-w-[1080px]",
|
// Drawer keeps the dashboard context behind it. On laptops
|
||||||
|
// (1280-1366px viewports) the previous lg:max-w-[1080px] cap
|
||||||
|
// left only ~200-286px of underlying /insights visible — a
|
||||||
|
// takeover, not a sheet. Drop the lg cap to min(960px,75vw)
|
||||||
|
// so /insights always retains a readable column; restore
|
||||||
|
// the wider three-column layout at xl+ (≥1280px sources rail
|
||||||
|
// is hidden below xl by the body's lg:hidden chevron rules).
|
||||||
|
"w-full p-0 sm:max-w-[720px]",
|
||||||
|
"lg:!max-w-[min(960px,75vw)] xl:!max-w-[1080px]",
|
||||||
"flex h-[100dvh] flex-col gap-0",
|
"flex h-[100dvh] flex-col gap-0",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -260,7 +268,9 @@ export function CoachDrawer({
|
|||||||
<SheetContent
|
<SheetContent
|
||||||
side="right"
|
side="right"
|
||||||
data-slot="coach-drawer-sources-tray"
|
data-slot="coach-drawer-sources-tray"
|
||||||
className="w-[88vw] max-w-[320px] p-0 lg:hidden"
|
// Sources rail is xl+ inline; on lg it's only available
|
||||||
|
// via this tray to match the narrowed drawer cap.
|
||||||
|
className="w-[88vw] max-w-[320px] p-0 xl:hidden"
|
||||||
>
|
>
|
||||||
<SheetHeader className="border-border/70 border-b p-3">
|
<SheetHeader className="border-border/70 border-b p-3">
|
||||||
<SheetTitle className="text-sm">
|
<SheetTitle className="text-sm">
|
||||||
|
|||||||
Reference in new issue
Block a user