Panels for a ten-inch screen, and a motor button that says where it is
Both screens the house is looked at on are 1280x800, so that is what the three dashboards are laid out for: twelve columns of 96px, twelve rows of 51px, and nothing past the bottom, because a panel does not scroll. The motors are one control each instead of three buttons. A button could only publish; a segmented control reads back as well — so the motor writes what it is doing to the same message the control sets, and the segment that is held is the direction it actually went. Up, Stop, Down for the shutters; Close/Open for the window and In/Out for the awning, which is what those two are for. A run stopped part way now leaves the position unknown rather than claiming the target it never reached, so the next command in either direction moves it. The preflight gained the two checks this needed. One runs each sample shape past the port that would receive it. The other is arithmetic: every tile inside the panel and none on top of another — both silent failures on a screen with no scrollbar, and both caught before anything is written. Sizes were settled by looking. A slider needs three rows or its tick labels fall off; a status icon needs three or it loses the word under the glyph; a gauge in two rows has no arc worth reading, so the battery is a bar on Home and a gauge on Energy where there is height for one. A chart spends eighty pixels on its chrome whatever it is given, so two of them read on this panel and three did not — the temperature history is the one that went, and `history` still answers for it. `capture-panels.mjs` is how that was checked: the three panels at the screen's own pixels, in both themes, reporting whether anything spilled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,7 @@ export const MAX_SEGMENTS = 3
|
||||
/** Outer fill left around a segment, as `inset-y-1` leaves it above and below. */
|
||||
const GUTTER = "2px"
|
||||
|
||||
export type Segment = { message?: string; dtype?: string }
|
||||
export type Segment = { message?: string; dtype?: string; label?: string }
|
||||
|
||||
/** A segment as drawn: where it runs on the fill, and what it reads. */
|
||||
type Band = { start: number; end: number; level: number; name: string }
|
||||
@@ -48,7 +48,13 @@ export const segmentsOf = (widget: WidgetProps["widget"]): Segment[] => {
|
||||
if (Array.isArray(cfg.inner))
|
||||
return (cfg.inner as Segment[]).slice(0, MAX_SEGMENTS)
|
||||
return cfg.inner
|
||||
? [{ message: text(cfg.inner), dtype: text(cfg.inner_dtype) }]
|
||||
? [
|
||||
{
|
||||
message: text(cfg.inner),
|
||||
dtype: text(cfg.inner_dtype),
|
||||
label: text(cfg.inner_label),
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
|
||||
@@ -108,8 +114,10 @@ export function BarWidget({ widget }: WidgetProps) {
|
||||
end: cursor,
|
||||
level,
|
||||
// The panel already carries the widget's title, so the caption names the
|
||||
// reading by its port rather than repeating the flow it comes from.
|
||||
name: displayName(flowOf(name), name),
|
||||
// reading by its port rather than repeating the flow it comes from — or
|
||||
// by whatever the author called it, since a port name is chosen for the
|
||||
// graph and not for somebody reading it across a room.
|
||||
name: text(segment.label) || displayName(flowOf(name), name),
|
||||
})
|
||||
}
|
||||
const detail = drawn
|
||||
|
||||
Reference in New Issue
Block a user