Slider reading in a tile: a line under the value in every look, row and fader; Beside it on every dashboard; tile geometry in the docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
84071ee106
commit
a6a1f2a2c3
@@ -511,7 +511,7 @@ export function WidgetPanel({
|
||||
onChange({ config: { ...cfg, ...changes } })
|
||||
|
||||
const series = seriesOf(widget)
|
||||
// What a slider on a round face reads beside its own value.
|
||||
// What a slider reads beside its own value.
|
||||
const reading = (cfg.reading ?? {}) as Series
|
||||
const runsPick = (cfg.runs ?? {}) as RunsPick
|
||||
const setSeries = (next: Series[]) => set({ series: next })
|
||||
@@ -1133,9 +1133,9 @@ export function WidgetPanel({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{widget.type === "slider" && round ? (
|
||||
{widget.type === "slider" ? (
|
||||
<div className="grid gap-1.5">
|
||||
<FieldLabel help="A reading drawn large in the middle of the face — the room's temperature beside the setpoint this sets. The slider's own value then moves to the line at the bottom. Written in the slider's unit and to its step's decimals.">
|
||||
<FieldLabel help="A reading shown with the value this sets, such as the room's temperature beside its setpoint, in the slider's unit and to its step's decimals. A tile writes it under the value; a round face draws it large in the middle.">
|
||||
Beside it
|
||||
</FieldLabel>
|
||||
<div className="flex items-end gap-1.5">
|
||||
|
||||
@@ -19,7 +19,14 @@ import { PlayerWidget } from "./PlayerWidget"
|
||||
import { usePublish } from "./publish"
|
||||
import { useUi } from "./ui"
|
||||
import { COLOR_DTYPES, colorFormatOf } from "./ui/core/color"
|
||||
import { buttonsOf, config, num, rowsOf, text } from "./ui/core/config"
|
||||
import {
|
||||
buttonsOf,
|
||||
config,
|
||||
decimalsOf,
|
||||
num,
|
||||
rowsOf,
|
||||
text,
|
||||
} from "./ui/core/config"
|
||||
|
||||
/** Widget types that put a value into the graph rather than read one. */
|
||||
export const INPUT_WIDGETS = new Set([
|
||||
@@ -659,6 +666,9 @@ function SliderWidget({ widget, dashboard }: WidgetProps) {
|
||||
const cfg = config(widget)
|
||||
const { target, value, send, pulse, locked } = usePublish(widget, dashboard)
|
||||
const min = num(cfg.min, 0)
|
||||
// What it sets against: a room's temperature beside its setpoint.
|
||||
const beside = (cfg.reading ?? {}) as Series
|
||||
const read = useBoundValue(beside.message || undefined)
|
||||
if (!target) return <Unbound />
|
||||
|
||||
const unit = cfg.unit ? text(cfg.unit) : undefined
|
||||
@@ -686,6 +696,30 @@ function SliderWidget({ widget, dashboard }: WidgetProps) {
|
||||
const readout = (
|
||||
<Readout value={reading} precision={null} unit={unit} size="inline" />
|
||||
)
|
||||
// A line under the value, smaller, so the value being set is still the one
|
||||
// that reads. In the slider's unit and to its step's decimals, as a round
|
||||
// face writes it: the two are read against each other.
|
||||
const against = beside.message ? (
|
||||
<span
|
||||
data-testid="slider-reading"
|
||||
className="flex h-4 max-w-full items-center gap-1.5 text-xs"
|
||||
>
|
||||
{beside.label ? (
|
||||
<span className="min-w-0 max-w-24 truncate text-muted-foreground">
|
||||
{beside.label}
|
||||
</span>
|
||||
) : null}
|
||||
{/* The label gives way first: the number is what the line is for. */}
|
||||
<span className="shrink-0">
|
||||
<Readout
|
||||
value={read?.value}
|
||||
precision={decimalsOf(num(cfg.step, 1))}
|
||||
unit={unit}
|
||||
size="inline"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
) : null
|
||||
|
||||
// A column takes the tile's height and puts the reading under it, which is
|
||||
// what a fader looks like. A volume control is the case it exists for: it is
|
||||
@@ -695,7 +729,10 @@ function SliderWidget({ widget, dashboard }: WidgetProps) {
|
||||
<div className="flex h-full min-h-0 flex-col items-center gap-2">
|
||||
{pulse}
|
||||
{control}
|
||||
<div className="shrink-0">{readout}</div>
|
||||
<div className="flex max-w-full shrink-0 flex-col items-center">
|
||||
{readout}
|
||||
{against}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -706,10 +743,21 @@ function SliderWidget({ widget, dashboard }: WidgetProps) {
|
||||
<div className="flex items-start gap-3">
|
||||
{pulse}
|
||||
<div className="min-w-0 flex-1">{control}</div>
|
||||
{/* Held to the control's own height, so the value sits on the track's
|
||||
midline whether or not there is a row of ticks under it. */}
|
||||
<div className="flex h-[var(--dui-control)] shrink-0 items-center">
|
||||
{readout}
|
||||
{/* The reading, if any, under the value: in the ticks' row when there
|
||||
is one, so it costs the tile no height. Held to half the row, so a
|
||||
long label in a small tile cannot squeeze the track to nothing. */}
|
||||
<div
|
||||
className={cn(
|
||||
"flex shrink-0 flex-col items-end",
|
||||
against && "max-w-1/2",
|
||||
)}
|
||||
>
|
||||
{/* Held to the control's own height, so the value sits on the track's
|
||||
midline whether or not there is a row of ticks under it. */}
|
||||
<div className="flex h-[var(--dui-control)] items-center">
|
||||
{readout}
|
||||
</div>
|
||||
{against}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user