Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #452.
This commit is contained in:
99
packages/ui/src/components/MetricsStrip.tsx
Normal file
99
packages/ui/src/components/MetricsStrip.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import { useState } from "react";
|
||||
import type { ReactElement } from "react";
|
||||
|
||||
export interface MetricCell {
|
||||
label: string;
|
||||
value: string;
|
||||
color: string; // CSS color, e.g., "var(--ms-blue-400)"
|
||||
trend?: {
|
||||
direction: "up" | "down" | "neutral";
|
||||
text: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MetricsStripProps {
|
||||
cells: MetricCell[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function MetricCellItem({ cell, isFirst }: { cell: MetricCell; isFirst: boolean }): ReactElement {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
|
||||
const trendColor =
|
||||
cell.trend?.direction === "up"
|
||||
? "var(--success)"
|
||||
: cell.trend?.direction === "down"
|
||||
? "var(--danger)"
|
||||
: "var(--muted)";
|
||||
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={(): void => {
|
||||
setHovered(true);
|
||||
}}
|
||||
onMouseLeave={(): void => {
|
||||
setHovered(false);
|
||||
}}
|
||||
style={{
|
||||
padding: "14px 16px",
|
||||
background: hovered ? "var(--surface-2)" : "var(--surface)",
|
||||
borderLeft: isFirst ? "none" : "1px solid var(--border)",
|
||||
borderTop: `2px solid ${cell.color}`,
|
||||
transition: "background 0.15s ease",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "1.4rem",
|
||||
fontWeight: 800,
|
||||
fontFamily: "var(--mono)",
|
||||
lineHeight: 1.1,
|
||||
color: cell.color,
|
||||
}}
|
||||
>
|
||||
{cell.value}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.72rem",
|
||||
color: "var(--muted)",
|
||||
marginTop: 3,
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{cell.label}
|
||||
</div>
|
||||
{cell.trend && (
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.68rem",
|
||||
fontFamily: "var(--mono)",
|
||||
marginTop: 4,
|
||||
color: trendColor,
|
||||
}}
|
||||
>
|
||||
{cell.trend.text}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function MetricsStrip({ cells, className = "" }: MetricsStripProps): ReactElement {
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${String(cells.length)}, 1fr)`,
|
||||
borderRadius: "var(--r-lg)",
|
||||
overflow: "hidden",
|
||||
border: "1px solid var(--border)",
|
||||
}}
|
||||
>
|
||||
{cells.map((cell, index) => (
|
||||
<MetricCellItem key={cell.label} cell={cell} isFirst={index === 0} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user