Edit the whole dashboard, and let the grid follow its canvas

The editor only ever arranged the first section, so the demo's Home
dashboard lost 16 of its 25 widgets the moment it was edited. A page's
sections are now read as one arrangement — each pushed below the one
before it — and written back as one, which is the shape a dashboard was
already heading for: one dashboard, one canvas, and the panel rail for
the several-dashboards story. The page tabs that story made dead are
gone; PageDef/SectionDef stay in the schema and a page the editor does
not show round-trips untouched.

The row height derives from the canvas as the column width already did,
so the same arrangement is the same picture on a 7" panel as on a 4K
one. The uPlot rules move beside UplotChart, where a chart on Health is
styled without a dashboard having been visited first, and the bar's
readout travels on one property instead of jumping sides at 30%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tULRZJUkZsw7rMJ3h4xvu
This commit is contained in:
2026-08-22 12:22:37 +02:00
co-authored by Claude Opus 5
parent 6be6f18dc2
commit 9e3093bd72
6 changed files with 216 additions and 162 deletions
@@ -146,16 +146,19 @@ export function BarWidget({ widget }: WidgetProps) {
}}
/>
))}
{/* Always anchored to the end of the fill by `left`, so the whole
travel is one interpolating property. Which side of that anchor the
reading sits on is the translate: pulled back onto the fill while
there is room for it, left where it is once there is not. */}
<span
className={cn(
"absolute inset-y-0 flex items-center px-2 text-sm tabular-nums motion-safe:transition-[left,right] motion-safe:duration-200 motion-safe:ease-[var(--ease-standard)]",
"absolute inset-y-0 flex items-center px-2 text-sm tabular-nums motion-safe:transition-[left,transform] motion-safe:duration-200 motion-safe:ease-[var(--ease-standard)]",
fits ? "text-primary-foreground" : "text-foreground",
)}
style={
fits
? { right: `${(1 - fraction) * 100}%` }
: { left: `${fraction * 100}%` }
}
style={{
left: `${fraction * 100}%`,
transform: fits ? "translateX(-100%)" : "translateX(0)",
}}
>
{write(value)}
</span>