Meter
A measurement within a range, coloured green, amber or red by whether it is where it should be, as segments or one bar.
Demo
Get it
It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/meter.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/meter.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/meter.qwe
view MeterDemo() = <div.demo-stack.demo-narrow> <Meter label="Disk used" value={72} unit=" GB" high={80} optimum={0}/> <Meter label="Disk used" value={91} unit=" GB" low={60} high={80} optimum={0}/> <Meter label="Battery" value={18} unit="%" low={20} high={60} optimum={100}/> <Meter label="Room temperature" value={21.5} unit=" °C" min={10} max={35} low={18} high={24} optimum={21}/> <Meter label="Password strength" value={3} max={4} segments={4} value_text="Good" low={2} optimum={4}/> <Meter label="Seats taken" value={7} max={10} value_text="7 of 10" tone="info" size="sm"/> </div>Source
ui/meter.qwe
// Meter: a measurement within a known range, as a labelled bar coloured by whether// the value is good, so-so or bad, as the HTML <meter> does (role="meter").// For how far a task has got, use Progress.//// <Meter label="Disk used" value={72} unit=" GB" max={100} high={80} optimum={0}/>// <Meter label="Battery" value={18} unit="%" low={20} high={60} optimum={100}/>// <Meter label="Password strength" value={3} max={4} segments={4} value_text="Good"/>//// value: the measurement, between min (0) and max (100). low and high split the// range in three, and optimum says which part is best: the value is green there,// amber in the part next to it and red in the part furthest from it (a value// between low and high is amber on either side when the best part is an end). With// none of the three, it takes tone: "accent" (default), "neutral", "success",// "warning", "danger" or "info". unit: after the value ("%", " GB");// value_text: what to show and say instead ("Good", "72 of 100 GB").// show_value: the value beside the label (true). label: what it measures.// segments: the bar cut into that many pieces (for a score of 4, say). marks: thin// lines on the bar at low and high (true when they are given). size: "sm", "md"// (default) or "lg".import ui/theme.qwe use ui_clslet meter_css = css`.ui-meter { display: grid; gap: 6px; min-width: 0; font: 13px/1.4 var(--ui-font); color: var(--ui-fg); --t: var(--ui-accent); }.ui-meter-neutral { --t: var(--ui-muted); }.ui-meter-success, .ui-meter-good { --t: var(--ui-success); }.ui-meter-warning, .ui-meter-fair { --t: var(--ui-warning); }.ui-meter-danger, .ui-meter-poor { --t: var(--ui-danger); }.ui-meter-info { --t: var(--ui-info); }.ui-meter-head { display: flex; justify-content: space-between; gap: 12px; }.ui-meter-value { color: var(--ui-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }.ui-meter-good .ui-meter-value, .ui-meter-fair .ui-meter-value, .ui-meter-poor .ui-meter-value { color: var(--t); font-weight: 600; }.ui-meter-track { position: relative; display: flex; gap: 3px; height: 8px; }.ui-meter-sm .ui-meter-track { height: 4px; }.ui-meter-lg .ui-meter-track { height: 12px; }.ui-meter-seg { position: relative; flex: 1; overflow: hidden; border-radius: 999px; background: var(--ui-subtle); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-border) 60%, transparent); }.ui-meter-fill { display: block; height: 100%; border-radius: inherit; background: var(--t); transition: width .3s ease; }.ui-meter-mark { position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px; background: var(--ui-bg); }@media (prefers-reduced-motion: reduce) { .ui-meter-fill { transition: none; } }`// A number as text, whole ones without ".0", to two decimals at most.fn meter_num(n: num) -> str { let r = round(n * 100) / 100 r == floor(r) ? str(floor(r)) : str(r)}// Which part of the range v is in: 0 below low, 1 between, 2 above high.fn meter_part(v: num, low: num, high: num) -> int = v < low ? 0 : (v > high ? 2 : 1)view Meter(value: num, min: num = 0, max: num = 100, low: num? = null, high: num? = null, optimum: num? = null, label: str? = null, unit: str = "", value_text: str? = null, show_value: bool = true, segments: int = 1, marks: bool = true, tone: str = "accent", size: str = "md", class: str? = null) { style global meter_css let span = max - min > 0 ? max - min : 1 let v = value < min ? min : (value > max ? max : value) let lo = low ?? min let hi = high ?? max let judged = low != null || high != null || optimum != null let best = meter_part(optimum ?? (min + max) / 2, lo, hi) let here = meter_part(v, lo, hi) let mood = !judged ? null : (here == best ? "good" : ((best == 1 || abs(here - best) == 1) ? "fair" : "poor")) let pct = (v - min) * 100 / span let n = segments < 1 ? 1 : segments let text = value_text ?? `${meter_num(value)}${unit}` let at = (x) => meter_num((x - min) * 100 / span) <div class={ui_cls(["ui-meter", mood != null ? `ui-meter-${mood}` : `ui-meter-${tone}`, size != "md" && `ui-meter-${size}`, class])}> {(label != null || show_value) && <div.ui-meter-head aria-hidden="true"> <span>{label}</span> {show_value && <span.ui-meter-value>{text}</span>} </div>} <div.ui-meter-track role="meter" aria-label={label} aria-valuemin={meter_num(min)} aria-valuemax={meter_num(max)} aria-valuenow={meter_num(v)} aria-valuetext={text}> {for i in range(n) => { let part = pct * n - i * 100 <span.ui-meter-seg> <span.ui-meter-fill style={`width: ${meter_num(part < 0 ? 0 : (part > 100 ? 100 : part))}%`}></span> </span> }} {marks && n == 1 && low != null && low > min && low < max && <span.ui-meter-mark style={`left: ${at(low)}%`}></span>} {marks && n == 1 && high != null && high > min && high < max && <span.ui-meter-mark style={`left: ${at(high)}%`}></span>} </div> </div>}Related
ProgressHow far along something is, as a bar or a ring, with its percentage, or indeterminate.5 views · 6 downloadsProgressRingCircular progress in four sizes, with its percentage or a value of your own in the middle, or turning while not known.6 views · 7 downloadsUploadProgressOne file's upload: name, bytes sent of its size, speed, time left, a bar, and Cancel; done, paused and error states.4 views · 7 downloadsAlertA message in the page in six tones and three variants, with an icon, announced to screen readers, and dismissable.5 views · 9 downloadsBadgeA small pill for a status or a count: six tones, soft, solid or outline, a status dot, and 99+.8 views · 6 downloadsBannerAn announcement across the top of the page in six tones, with a link, closed for the session once dismissed.7 views · 6 downloads
Thread
Thread 0 posts
On Meter: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.