mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 12:22:03 +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
|
||||
* chevron-button triggers along the edges of the message thread that
|
||||
* open side-sheets surfacing the same rails. The triggers live on
|
||||
* `<CoachDrawerBody>` so the SSR test can pin their `lg:hidden` class
|
||||
* + slot markers without rendering the outer Radix `<Sheet>` portal
|
||||
* (which is client-only).
|
||||
* open side-sheets surfacing the same rails.
|
||||
*
|
||||
* Phase D reconcile narrowed the lg drawer cap (was 1080px → now
|
||||
* 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") {
|
||||
@@ -37,7 +40,7 @@ describe("<CoachDrawerBody> — mobile rail trays", () => {
|
||||
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 historyTrigger = html.match(
|
||||
/<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"[^>]*>/,
|
||||
);
|
||||
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} />);
|
||||
expect(html).toMatch(
|
||||
/<aside[^>]*data-slot="coach-drawer-history"[^>]*lg:flex/,
|
||||
);
|
||||
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 (
|
||||
<div
|
||||
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
|
||||
tray trigger inside the thread column. */}
|
||||
@@ -71,6 +75,8 @@ export function CoachDrawerBody({
|
||||
<ChevronRight className="size-3" aria-hidden="true" />
|
||||
{t("insights.coach.historyTitle")}
|
||||
</Button>
|
||||
{/* Sources tray trigger stays visible up to xl since the
|
||||
inline sources rail is xl+ only. */}
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
@@ -78,7 +84,7 @@ export function CoachDrawerBody({
|
||||
onClick={onOpenSourcesTray}
|
||||
data-slot="coach-drawer-sources-tray-trigger"
|
||||
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")}
|
||||
<ChevronLeft className="size-3" aria-hidden="true" />
|
||||
@@ -94,10 +100,12 @@ export function CoachDrawerBody({
|
||||
</div>
|
||||
</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
|
||||
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}
|
||||
</aside>
|
||||
|
||||
@@ -134,7 +134,15 @@ export function CoachDrawer({
|
||||
showCloseButton
|
||||
data-slot="coach-drawer"
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -260,7 +268,9 @@ export function CoachDrawer({
|
||||
<SheetContent
|
||||
side="right"
|
||||
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">
|
||||
<SheetTitle className="text-sm">
|
||||
|
||||
Reference in new issue
Block a user