fix(quotes): stop the detail page's tab strips colliding

Moving the admin panels below the items table left them at a third of
the row each (~186px of tab strip), which is too narrow for the labels
they carry. "Outbound" plus its count needs ~71px against the ~58px it
was given, so the three Attachments labels overlapped each other; the
same squeeze hit "Email Status" on the Activity card.

Lays the panels out two-up instead: Attachments spans both columns on
its own row (its three tabs, dropzone and file list want the space),
with Linked Orders and Activity sharing the row beneath at half width.
Both strips now have several times the headroom they need, measured at
a 1044px viewport, and mobile is unchanged (single column, no
page-level horizontal scroll).

Also drops the `ml-1.5` from the attachment count spans — TabsTrigger
already applies `gap-1.5` between its children, so the margin was
double-spacing and contributed to the overflow — and adds
`tabular-nums` so the tab widths stay steady as counts tick past 9.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-08-29 09:25:45 +02:00
parent 53f9aaaee4
commit fd5c3c8510

View file

@ -2465,17 +2465,25 @@ export default function QuoteDetailPage({ params }: { params: Promise<{ id: stri
)}
</div>
{/* ADMIN PANELS — reference / config, laid out 3-up BELOW the
items table rather than beside it, so the table gets the
page's full width. The eye still lands on the items first
because these now come after it in the flow.
`items-start` stops the three cards stretching to a shared
height when one has far more content than the others.
Three cards (down from six):
1. Attachments — tabbed (Outbound / Internal)
{/* ADMIN PANELS — reference / config, laid out BELOW the items
table rather than beside it, so the table gets the page's
full width. The eye still lands on the items first because
these now come after it in the flow.
Two columns, not three: each card owns a tab strip, and
thirds of this row (~186px of strip) are too narrow for
their labels — "Outbound"+count and "Email Status" both
overflowed and collided. Attachments spans both columns
(its own row); Linked Orders and Activity share the row
below at half width each, which clears both strips
comfortably.
`items-start` stops the cards stretching to a shared height
when one has far more content than the others.
1. Attachments — tabbed (Outbound / Internal / Inbound)
2. Linked Orders — its own card (specific, deserves focus)
3. Activity — tabbed (History / Email Status) */}
<div className="grid gap-6 lg:grid-cols-3 items-start">
3. Activity — tabbed (Email Status / History) */}
<div className="grid gap-6 lg:grid-cols-2 items-start">
{/*
Attachments — single tabbed card with Outbound and Internal
tabs. Both write to the same `quote_attachments` PB
@ -2488,7 +2496,14 @@ export default function QuoteDetailPage({ params }: { params: Promise<{ id: stri
office uses to justify the prices (never sent to the
buyer)
*/}
<Card>
{/* Attachments spans both columns, so it gets a full-width
row of its own with Linked Orders + Activity sharing the
row beneath. It carries the most content of the three —
three tabs, a dropzone and a file list — and its tab
labels ("Outbound" / "Internal" / "Inbound", each with a
count) need ~213px of strip. At a third of the row they
only got ~186px and collided into each other. */}
<Card className="lg:col-span-2">
<CardHeader className="pb-3">
<CardTitle className="text-sm flex items-center gap-2">
<Paperclip className="h-4 w-4 text-muted-foreground" />
@ -2497,22 +2512,29 @@ export default function QuoteDetailPage({ params }: { params: Promise<{ id: stri
</CardHeader>
<CardContent className="pt-0">
<Tabs defaultValue="outbound" className="w-full">
{/* The count spans deliberately have no `ml-*`:
TabsTrigger already puts `gap-1.5` between its
children, so a margin on top of that double-spaced
them and helped push the labels into each other
back when this card was only a third of the row
wide. `tabular-nums` keeps the tab widths steady as
counts tick over 9. */}
<TabsList className="w-full grid grid-cols-3">
<TabsTrigger value="outbound" data-testid="tab-outbound-attachments">
Outbound
<span className="ml-1.5 text-[10px] font-normal text-muted-foreground">
<span className="text-[10px] font-normal text-muted-foreground tabular-nums">
{outboundAttachments.length}
</span>
</TabsTrigger>
<TabsTrigger value="internal" data-testid="tab-internal-attachments">
Internal
<span className="ml-1.5 text-[10px] font-normal text-muted-foreground">
<span className="text-[10px] font-normal text-muted-foreground tabular-nums">
{internalAttachments.length}
</span>
</TabsTrigger>
<TabsTrigger value="inbound" data-testid="tab-inbound-attachments">
Inbound
<span className="ml-1.5 text-[10px] font-normal text-muted-foreground">
<span className="text-[10px] font-normal text-muted-foreground tabular-nums">
{attachments.filter((a) => a.direction === "inbound").length}
</span>
</TabsTrigger>