54 lines
1.4 KiB
JavaScript
54 lines
1.4 KiB
JavaScript
export function MiniStat({ item }) {
|
|
const caption = parseCaption(item.caption);
|
|
const deltaTone = item.deltaTone || (caption.delta.startsWith("-") ? "down" : "up");
|
|
return (
|
|
<article className="mini-stat">
|
|
<span>{item.label}</span>
|
|
<strong>{item.value}</strong>
|
|
<small className={`mini-stat-delta mini-stat-delta--${deltaTone}`}>
|
|
<span>{caption.label}</span>
|
|
{caption.delta ? <b>{`${deltaTone === "down" ? "↓" : "↑"} ${caption.delta.replace(/^[-+]/, "")}`}</b> : null}
|
|
</small>
|
|
</article>
|
|
);
|
|
}
|
|
|
|
function parseCaption(caption = "") {
|
|
const normalized = String(caption).trim().replace(/\s+/g, " ");
|
|
const match = normalized.match(/^(.*)\s([+-][\d.]+(?:%|pp)?)$/);
|
|
if (!match) {
|
|
return { delta: "", label: normalized };
|
|
}
|
|
return { delta: match[2], label: match[1] };
|
|
}
|
|
|
|
export function TwoMetricRow({ items }) {
|
|
return (
|
|
<div className="two-metric-row">
|
|
{items.map((item) => (
|
|
<MiniStat item={item} key={item.label} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function FourMetricRow({ items }) {
|
|
return (
|
|
<div className="four-metric-row">
|
|
{items.map((item) => (
|
|
<MiniStat item={item} key={item.label} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function FiveMetricRow({ items }) {
|
|
return (
|
|
<div className="five-metric-row">
|
|
{items.map((item) => (
|
|
<MiniStat item={item} key={item.label} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|