Mobile: make the Sites table fit 375px without losing the VAT split

The /sites table showed seven columns and needed roughly 493px of a 343px
viewport once the page padding is taken off, so at phone width the row was a
sideways scroll with the sticky Site column sitting on top of the figures —
the same trap the invoice table had.

Below sm it now shows Site, Total incl VAT and Unbooked. The ex-VAT and VAT
columns hide, but their split is not dropped: it moves under the total as two
stacked lines, "ex 161 367,50" and "VAT 24 205,13", which is the same
information the columns carried without the width.

The split is stacked rather than on one line because "161 367,50 + 24 205,13"
is wider than the total it annotates, which pushed the row back over the
viewport. The unbooked badge drops its word on mobile for the same reason — the
row is already tinted, and the count plus icon carry the meaning.

Width budget for the three visible columns: 154 + 102 + 60 = 316px of 343px.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
David 2026-10-02 16:28:07 +02:00
parent 14ec899ca9
commit 4e3f1ac7d7

View file

@ -71,7 +71,7 @@ export default async function SitesPage() {
<table className="w-full text-sm sm:min-w-[820px]">
<thead>
<tr className="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider border-b border-gray-100 dark:border-white/5 bg-gray-50/50 dark:bg-white/[0.02]">
<th className="text-left py-3 px-4 font-medium sticky left-0 z-10 bg-gray-50/95 dark:bg-surface-muted/95 backdrop-blur">
<th className="text-left py-3 px-3 sm:px-4 font-medium sticky left-0 z-10 bg-gray-50/95 dark:bg-surface-muted/95 backdrop-blur">
Site
</th>
<th className="text-right py-3 px-3 font-medium whitespace-nowrap hidden sm:table-cell">
@ -80,12 +80,12 @@ export default async function SitesPage() {
<th className="text-right py-3 px-3 font-medium whitespace-nowrap hidden sm:table-cell">
Machines
</th>
<th className="text-right py-3 px-3 font-medium whitespace-nowrap">Revenue ex VAT</th>
<th className="hidden sm:table-cell text-right py-3 px-3 font-medium whitespace-nowrap">Revenue ex VAT</th>
<th className="text-right py-3 px-3 font-medium whitespace-nowrap hidden sm:table-cell">
VAT
</th>
<th className="text-right py-3 px-3 font-medium whitespace-nowrap">Total incl VAT</th>
<th className="text-left py-3 px-4 font-medium whitespace-nowrap">Unbooked</th>
<th className="text-left py-3 px-2 sm:px-4 font-medium whitespace-nowrap">Unbooked</th>
</tr>
</thead>
<tbody>
@ -96,7 +96,7 @@ export default async function SitesPage() {
r.unbookedCount ? "bg-[#D1495B]/[0.04]" : "hover:bg-gray-50/60 dark:hover:bg-white/[0.02]"
}`}
>
<td className="py-3 px-4 sticky left-0 z-10 bg-white dark:bg-[#131a21]">
<td className="py-3 px-3 sm:px-4 sticky left-0 z-10 bg-white dark:bg-[#131a21]">
<a
href={`/sites/${r.id}`}
className="group inline-flex items-center gap-2 min-h-[44px] font-medium text-[#003D5B] dark:text-white hover:text-[#00798C] transition"
@ -112,20 +112,32 @@ export default async function SitesPage() {
<td className="hidden sm:table-cell py-3 px-3 text-right tabular-nums text-gray-600 dark:text-gray-300">
{r.machineCount}
</td>
<td className="py-3 px-3 text-right tabular-nums font-medium text-[#003D5B] dark:text-white whitespace-nowrap">
<td className="hidden sm:table-cell py-3 px-3 text-right tabular-nums font-medium text-[#003D5B] dark:text-white whitespace-nowrap">
{ZAR2(r.revenueExcl)}
</td>
<td className="hidden sm:table-cell py-3 px-3 text-right tabular-nums text-gray-500 dark:text-gray-400 whitespace-nowrap">
{ZAR2(r.vat)}
</td>
<td className="py-3 px-3 text-right tabular-nums font-semibold text-[#003D5B] dark:text-white whitespace-nowrap">
{ZAR2(r.revenueIncl)}
<td className="py-3 px-2 sm:px-3 text-right tabular-nums font-semibold text-[#003D5B] dark:text-white whitespace-nowrap">
<div>{ZAR2(r.revenueIncl)}</div>
{/* The ex-VAT/VAT split stays visible on mobile, but as two short
stacked lines — "161 367,50 + 24 205,13" on one line is wider
than the total it annotates, which pushed the row back over the
375px viewport. */}
<div className="sm:hidden text-xs font-normal leading-tight text-gray-500 dark:text-gray-400">
<div>ex {ZAR2(r.revenueExcl)}</div>
<div>VAT {ZAR2(r.vat)}</div>
</div>
</td>
<td className="py-3 px-4 whitespace-nowrap">
<td className="py-3 px-2 sm:px-4 whitespace-nowrap">
{r.unbookedCount > 0 ? (
<span className="inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg bg-[#D1495B]/10 text-[#D1495B] text-xs font-semibold">
<span
title={`${r.unbookedCount} line(s) still unbooked`}
className="inline-flex items-center gap-1.5 px-2 py-1.5 rounded-lg bg-[#D1495B]/10 text-[#D1495B] text-xs font-semibold"
>
<AlertTriangle className="w-3.5 h-3.5 shrink-0" />
{r.unbookedCount} unbooked
{r.unbookedCount}
<span className="hidden sm:inline">unbooked</span>
</span>
) : (
<span className="text-sm text-gray-400 dark:text-gray-500">—</span>