Files
flxn-app/src/features/telemetry/components/charts/stat-tile.tsx
T
kyle fd0489a22f refactor(telemetry): chart scale labels, calmer vitals and error styling, usage-first tabs
- 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
2026-08-25 22:35:16 -07:00

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;