initial commit
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/* ============================================================================
|
||||
Card.Stat - Figma 25:792 (260 x 166)
|
||||
----------------------------------------------------------------------------
|
||||
The figure card used by the home page stats strip: a large accent number,
|
||||
an optional trend chip, the label it counts, a rule and a caption. Never a
|
||||
link - a number is not a destination.
|
||||
|
||||
USAGE
|
||||
-----
|
||||
<ul className="grid gap-lg sm:grid-cols-2 lg:grid-cols-4">
|
||||
<Card.Stat
|
||||
as="li"
|
||||
value="2,450"
|
||||
label="Participants reached"
|
||||
caption="Cumulative regional outreach, updated each quarter."
|
||||
trend={{ label: "12%", direction: "up", description: "up 12% on last quarter" }}
|
||||
/>
|
||||
<Card.Stat as="li" value="18" label="Municipalities engaged" />
|
||||
</ul>
|
||||
|
||||
// Arabic - Eastern Arabic numerals belong in the value string itself.
|
||||
<Card.Stat value="٢٬٤٥٠" label="عدد المشاركين" />
|
||||
========================================================================= */
|
||||
|
||||
import { CardIcon, CardShell, cx } from "./CardShell";
|
||||
import type { CardElement } from "./types";
|
||||
|
||||
export interface CardStatTrend {
|
||||
/** Visible text, e.g. "12%". */
|
||||
label: string;
|
||||
/** Up is the accent fill, down the danger fill. Defaults to up. */
|
||||
direction?: "up" | "down";
|
||||
/**
|
||||
* Spoken instead of the bare figure, e.g. "up 12% on last quarter". The
|
||||
* arrow is decorative, so without this a screen reader hears only "12%".
|
||||
*/
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface CardStatProps {
|
||||
/** Pre-formatted for the locale - the card never formats a number itself. */
|
||||
value: string;
|
||||
label: string;
|
||||
caption?: string;
|
||||
trend?: CardStatTrend;
|
||||
as?: CardElement;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function CardStat({
|
||||
value,
|
||||
label,
|
||||
caption,
|
||||
trend,
|
||||
as = "article",
|
||||
className,
|
||||
}: CardStatProps) {
|
||||
const isDown = trend?.direction === "down";
|
||||
|
||||
return (
|
||||
<CardShell
|
||||
as={as}
|
||||
className={cx("flex-col items-start gap-md p-lg", className)}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between gap-sm">
|
||||
<p className="display-sm tabular-nums text-text-accent">{value}</p>
|
||||
|
||||
{trend ? (
|
||||
/* Figma paints the chip label in text/accent on a background/accent
|
||||
fill - green on green, invisible. Kept as the accent fill with the
|
||||
always-white on-accent label, and the danger fill when the figure
|
||||
is falling. */
|
||||
<span
|
||||
className={cx(
|
||||
"inline-flex shrink-0 items-center gap-2xs rounded-control-lg px-xs py-2xs",
|
||||
"label-md text-text-on-accent",
|
||||
isDown ? "bg-surface-danger" : "bg-surface-accent",
|
||||
)}
|
||||
>
|
||||
<CardIcon
|
||||
name="arrow-up"
|
||||
size={10}
|
||||
className={isDown ? "rotate-180" : undefined}
|
||||
/>
|
||||
{trend.description ? (
|
||||
<>
|
||||
<span aria-hidden="true">{trend.label}</span>
|
||||
<span className="sr-only">{trend.description}</span>
|
||||
</>
|
||||
) : (
|
||||
trend.label
|
||||
)}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<p className="body-md-bold text-text-primary">{label}</p>
|
||||
|
||||
<div aria-hidden="true" className="w-full border-t border-border-subtle" />
|
||||
|
||||
{caption ? (
|
||||
<p className="body-sm text-text-secondary">{caption}</p>
|
||||
) : null}
|
||||
</CardShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user