Data

MetricTrend

A value with an up or down arrow and its change, coloured by whether the move is good; it can work the percentage out.

#data#dashboard#no-js

Demo

Preview
Signups this week

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/metric_trend.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/metric_trend.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/metric_trend.qwe
view MetricTrendDemo() =    <div.demo-stack>        <div.demo-row style="gap: 28px">            <MetricTrend id="metric-trend-demo-revenue" label="Revenue" value="$48,210" delta={12.5} suffix="%"/>            <MetricTrend id="metric-trend-demo-latency" label="Latency" value="212 ms" delta={18} suffix=" ms" good="down"/>            <MetricTrend id="metric-trend-demo-users" label="Active users" current={1284} previous={1310}/>            <MetricTrend id="metric-trend-demo-flat" label="Open tickets" value="37" delta={0}/>        </div>        <div.demo-row style="gap: 28px">            <MetricTrend id="metric-trend-demo-pill" label="Conversion" value="3.4%" delta={0.6} suffix=" pts" variant="pill" size="lg"/>            <MetricTrend id="metric-trend-demo-cost" label="Cloud cost" value="$9,120" delta={-8.25} suffix="%" good="down" variant="pill"/>            <MetricTrend label="Storage" value="1.2 TB" delta={4} suffix="%" good="none" size="sm"/>            <span>Signups this week <MetricTrend id="metric-trend-demo-inline" delta={-3} suffix="%" size="sm"/></span>        </div>    </div>

Source

ui/metric_trend.qwe
// MetricTrend: a value with how it moved: an arrow up or down, the change, and a// colour that says whether that is good. Inline, for a table cell, a card's// corner or a sentence.////   <MetricTrend value="$48,210" delta={12.5} suffix="%"/>//   <MetricTrend value="212 ms" delta={18} suffix=" ms" good="down"/>         slower: red//   <MetricTrend current={1284} previous={1310} label="Active users"/>        works out -2%//// value: the number as it should read (format it first); left out, only the// change shows. delta: the change, a number. Or current and previous, numbers: the// change is worked out as a percentage of previous (to one decimal), and value is// current with thousands separators unless value is given.// suffix: after the change ("%", " pts"; "%" when worked out). good: "up"// (default) or "down" when a fall is good (costs, latency, churn); "none" keeps// it neutral. tone: forces "success", "danger" or "neutral" whatever the change.// size: "sm", "md" (default) or "lg". variant: "text" (default) or "pill" (the// change on a soft background). label: what is measured, said to screen readers// with the change in words ("Active users: 1,284, down 2%").import ui/theme.qwe use ui_clslet metric_trend_css = css`.ui-metrictrend { display: inline-flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font: 14px/1.3 var(--ui-font); color: var(--ui-fg);  vertical-align: baseline; --t: var(--ui-muted); }.ui-metrictrend-good { --t: var(--ui-success); }.ui-metrictrend-bad { --t: var(--ui-danger); }.ui-metrictrend-value { font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }.ui-metrictrend-change { display: inline-flex; align-items: center; gap: 3px; color: var(--t); font-weight: 600; font-size: .9em;  font-variant-numeric: tabular-nums; white-space: nowrap; }.ui-metrictrend-change svg { width: .85em; height: .85em; flex: none; }.ui-metrictrend-pill .ui-metrictrend-change { padding: 1px 7px 1px 5px; border-radius: 999px; background: color-mix(in srgb, var(--t) 13%, transparent); }.ui-metrictrend-sm { font-size: 12px; gap: 6px; }.ui-metrictrend-lg { font-size: 22px; gap: 10px; }.ui-metrictrend-lg .ui-metrictrend-change { font-size: 15px; }`// A number to one decimal, without ".0": 2.0 is "2", -2.04 is "-2".fn metric_trend_num(n: num) -> str {    let r = round(n * 10) / 10    r == floor(r) ? str(floor(r)) : str(r)}view MetricTrend(value = null, delta: num? = null, current: num? = null, previous: num? = null, suffix: str? = null,                 good: str = "up", tone: str? = null, size: str = "md", variant: str = "text", label: str? = null,                 id: str? = null, class: str? = null) {    style global metric_trend_css    let worked = delta == null && current != null && previous != null && previous != 0    let change = delta ?? (worked ? round((current - previous) * 1000 / abs(previous)) / 10 : null)    let after = suffix ?? (worked ? "%" : "")    let shown = value ?? (current != null ? format_number(current, "en-US") : null)    let mood = tone == "success" ? "good" : tone == "danger" ? "bad" : tone == "neutral" || change == null || change == 0 || good == "none" ? "flat"        : ((change > 0) == (good != "down") ? "good" : "bad")    let way = change == null ? "" : change > 0 ? "up" : (change < 0 ? "down" : "unchanged")    let words = change == null ? "" : change == 0 ? "unchanged" : `${way} ${metric_trend_num(abs(change))}${after}`    let said = ui_cls([label != null ? `${label}:` : null, shown != null ? `${shown}${change != null ? "," : ""}` : null, words])    <span class={ui_cls(["ui-metrictrend", `ui-metrictrend-${mood}`, size != "md" && `ui-metrictrend-${size}`, variant == "pill" && "ui-metrictrend-pill", class])}          id={id} role="group" aria-label={said} data-way={way}>        {shown != null && <span.ui-metrictrend-value aria-hidden="true">{shown}</span>}        {change != null && <span.ui-metrictrend-change aria-hidden="true">            <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">                <path d={change > 0 ? "M6 10V2M2.5 5.5L6 2l3.5 3.5" : (change < 0 ? "M6 2v8M2.5 6.5L6 10l3.5-3.5" : "M2 6h8M7 3l3 3-3 3")}/>            </svg>            {change > 0 ? "+" : ""}{metric_trend_num(change)}{after}        </span>}    </span>}
Thread
76Useful? Like it, or add to its thread below.

Thread 0 posts

On MetricTrend: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.