Draw the panel as a panel

Five things a wall panel showed that a wall panel should not.

**A tile's body no longer clips.** It scrolled, and a box that scrolls
also cuts whatever crosses its edge — which took the glow off a lit
button at exactly the width where the button filled its tile, and off a
gauge's arc at exactly the height where the dial filled its own. Only
what is written or listed asks for a scroller now; everything else is a
picture drawn to fit, and what overflows is left to the frame, which
clips at the tile's edge where a shadow has already faded out. The
slider's phantom scrollbar goes with it.

**The selector is a selector.** Named for what it does rather than what
it is, and the choice it is holding is held in the dashboard's own
primary — a pill that slides between the options rather than a grey one
that had to be looked for. The stored type is untouched, so no document
changes meaning.

**The arrangement is held off the panel's edges**, by the same distance
it holds between two widgets. The ground is not held off with it: a
background covers the whole panel, and only what is arranged on it has
a margin. No stored panel loses a row to it.

**The rail is drawn on the panel.** It was chrome bolted to the edge of
the screen beside the canvas — in the app's own design rather than the
dashboard's, and on a scaled canvas not even lined up with it. It now
takes a column out of the canvas the way the margin does, scaled with
it and wearing its look. Which cell each widget sits in is unchanged;
only how big a cell is.

Two of these were the same mistake twice: an unlayered rule stating
`position` for everything wearing a class — `.gl-surface` on a rail
placed by a utility, and a blanket lift over every child of a pressable
on a pill placed by `layoutId`. Both now say it one element at a time.
This commit is contained in:
2026-08-24 10:44:53 +02:00
parent fea57064f9
commit 6238728dce
18 changed files with 389 additions and 173 deletions
+21 -17
View File
@@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query"
import { createFileRoute, redirect } from "@tanstack/react-router"
import type { Dashboard } from "@/components/Dashboard/DashboardView"
import { PanelRail, RAIL_INSET } from "@/components/Dashboard/PanelRail"
import { PanelRail } from "@/components/Dashboard/PanelRail"
import { PanelSurface } from "@/components/Dashboard/PanelSurface"
import {
dashboardQueryOptions,
@@ -85,25 +85,29 @@ function PanelRoute() {
root.className,
stacked ? "overflow-y-auto" : "overflow-hidden",
)}
style={{
...root.style,
...(rail ? { paddingLeft: RAIL_INSET } : {}),
}}
style={root.style}
>
<LookProvider dashboard={dashboard as Dashboard | undefined}>
{rail && current ? (
<PanelRail
dashboards={dashboards}
current={current}
linkFor={(name) => ({
to: "/panel/$id",
params: { id },
search: { d: name },
})}
/>
) : null}
{dashboard ? (
<PanelSurface dashboard={dashboard as Dashboard} stacked={stacked} />
<PanelSurface
dashboard={dashboard as Dashboard}
stacked={stacked}
// Drawn on the panel rather than beside it: a screen showing four
// dashboards shows the way between them too.
rail={
rail && current ? (
<PanelRail
dashboards={dashboards}
current={current}
linkFor={(name) => ({
to: "/panel/$id",
params: { id },
search: { d: name },
})}
/>
) : null
}
/>
) : null}
</LookProvider>
</main>