feat: Revamp instance page
Chart Release / chart (push) Successful in 22s
Server Deploy / deploy (push) Successful in 37s

This commit is contained in:
2026-08-11 10:32:59 +01:00
parent ed260cd86c
commit a20e165ac2
13 changed files with 253 additions and 107 deletions
+46 -7
View File
@@ -13,12 +13,24 @@ import type { HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from "react";
* The head is the keyed idiom — mono, small, uppercase, widely tracked — which
* is what a column head is: a key above a value, exactly as the record line is
* a key beside one.
*
* MOBILE. `stack` collapses the table into one card per row below sm, each cell
* becoming a label/value pair drawn from TD's `label`. The variants below hang
* off a `stacked` class on the <table>, so a table that does not opt in is
* untouched at every width.
*
* It is opt-in rather than automatic because a stacked row whose cells have no
* labels is worse than a scrolling one — the values lose the only thing naming
* them. Customer screens stack; the staff console's wide registry tables scroll
* sideways instead, which is the right trade for eight columns read at a desk.
*/
export function Table({ className, children, ...props }: HTMLAttributes<HTMLTableElement>) {
const STACK = "max-sm:[.stacked_&]:block";
export function Table({ stack, className, children, ...props }: HTMLAttributes<HTMLTableElement> & { stack?: boolean }) {
return (
<div className="overflow-x-auto">
<table className={clsx("w-full border-collapse text-left text-[0.86rem]", className)} {...props}>
<table className={clsx("w-full border-collapse text-left text-[0.86rem]", stack && "stacked max-sm:block", className)} {...props}>
{children}
</table>
</div>
@@ -27,7 +39,7 @@ export function Table({ className, children, ...props }: HTMLAttributes<HTMLTabl
export function THead({ className, children, ...props }: HTMLAttributes<HTMLTableSectionElement>) {
return (
<thead className={clsx("border-b border-rule", className)} {...props}>
<thead className={clsx("border-b border-rule", "max-sm:[.stacked_&]:hidden", className)} {...props}>
{children}
</thead>
);
@@ -35,7 +47,7 @@ export function THead({ className, children, ...props }: HTMLAttributes<HTMLTabl
export function TBody({ className, children, ...props }: HTMLAttributes<HTMLTableSectionElement>) {
return (
<tbody className={className} {...props}>
<tbody className={clsx(STACK, "max-sm:[.stacked_&]:space-y-3 max-sm:[.stacked_&]:p-3", className)} {...props}>
{children}
</tbody>
);
@@ -43,7 +55,19 @@ export function TBody({ className, children, ...props }: HTMLAttributes<HTMLTabl
export function TR({ className, children, ...props }: HTMLAttributes<HTMLTableRowElement>) {
return (
<tr className={clsx("border-b border-rule-soft last:border-0 hover:bg-panel-2", className)} {...props}>
<tr
className={clsx(
"border-b border-rule-soft last:border-0 hover:bg-panel-2",
STACK,
// Plain bg-panel-2, not an opacity modifier: this app's tokens
// are whole colours rather than RGB channels, so `/40` has
// nothing to drop an alpha into. web/ stores channels precisely
// because it leans on those modifiers; this one must not.
"max-sm:[.stacked_&]:rounded max-sm:[.stacked_&]:border max-sm:[.stacked_&]:border-rule max-sm:[.stacked_&]:bg-panel-2 max-sm:[.stacked_&]:p-3",
className,
)}
{...props}
>
{children}
</tr>
);
@@ -69,9 +93,24 @@ export function TH({ className, numeric, children, ...props }: ThHTMLAttributes<
);
}
export function TD({ className, numeric, children, ...props }: TdHTMLAttributes<HTMLTableCellElement> & CellProps) {
export function TD({ className, numeric, label, children, ...props }: TdHTMLAttributes<HTMLTableCellElement> & CellProps & { label?: string }) {
return (
<td className={clsx("px-4 py-3 align-middle", numeric && "text-right tabular-nums", className)} {...props}>
<td
className={clsx(
"px-4 py-3 align-middle",
numeric && "text-right tabular-nums",
// Stacked, a cell is a label above its value and the right
// alignment that made a money column read down the page is
// meaningless, so it is dropped.
STACK,
"max-sm:[.stacked_&]:px-0 max-sm:[.stacked_&]:py-1 max-sm:[.stacked_&]:text-left",
className,
)}
{...props}
>
{label && (
<span className="mb-0.5 hidden font-mono text-[0.6rem] uppercase tracking-[0.13em] text-ink-3 max-sm:[.stacked_&]:block">{label}</span>
)}
{children}
</td>
);