- sparklines get start/end date and max-value footers - vitals rating shown by value color instead of badges - error rows use plain counts, subtle resolve button, terse empty state - telemetry tab order: usage, players, functions, events, errors; usage is default
61 lines
1.3 KiB
TypeScript
61 lines
1.3 KiB
TypeScript
import { ReactNode } from "react";
|
|
import { Box, Group, Stack, Text, UnstyledButton } from "@mantine/core";
|
|
import Sparkline, { SparklineScale } from "./sparkline";
|
|
|
|
interface StatTileProps {
|
|
label: ReactNode;
|
|
value: ReactNode;
|
|
valueColor?: string;
|
|
delta?: number;
|
|
spark?: number[];
|
|
sparkScale?: SparklineScale;
|
|
caption?: ReactNode;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
export const StatTile = ({
|
|
label,
|
|
value,
|
|
valueColor,
|
|
delta,
|
|
spark,
|
|
sparkScale,
|
|
caption,
|
|
onClick,
|
|
}: StatTileProps) => {
|
|
const content = (
|
|
<Stack gap={2}>
|
|
<Group gap="xs" align="baseline" wrap="nowrap">
|
|
<Text fz="xl" fw={700} lh={1.2} c={valueColor}>
|
|
{value}
|
|
</Text>
|
|
{delta !== undefined && delta !== 0 && (
|
|
<Text size="xs" c={delta > 0 ? "green" : "red"}>
|
|
{delta > 0 ? "+" : ""}
|
|
{delta.toLocaleString()}
|
|
</Text>
|
|
)}
|
|
</Group>
|
|
<Text size="xs" c="dimmed">
|
|
{label}
|
|
</Text>
|
|
{caption && <Box>{caption}</Box>}
|
|
{spark && spark.length > 0 && (
|
|
<Sparkline data={spark} height={28} scale={sparkScale} />
|
|
)}
|
|
</Stack>
|
|
);
|
|
|
|
if (onClick) {
|
|
return (
|
|
<UnstyledButton className="flxn-press" onClick={onClick} w="100%">
|
|
{content}
|
|
</UnstyledButton>
|
|
);
|
|
}
|
|
|
|
return content;
|
|
};
|
|
|
|
export default StatTile;
|