forked from
slices.network/slices
Highly ambitious ATProtocol AppView service and sdks
1import { graphql, useFragment } from "react-relay";
2import type { Sparkline_sparklines$key } from "../__generated__/Sparkline_sparklines.graphql.ts";
3
4interface SparklineProps {
5 sparklines: Sparkline_sparklines$key;
6 width?: number;
7 height?: number;
8 className?: string;
9}
10
11export function Sparkline({
12 sparklines,
13 width = 200,
14 height = 40,
15 className = "",
16}: SparklineProps) {
17 const data = useFragment(
18 graphql`
19 fragment Sparkline_sparklines on SparklinePoint @relay(plural: true) {
20 timestamp
21 count
22 }
23 `,
24 sparklines
25 );
26
27 if (!data || data.length === 0) {
28 return null;
29 }
30
31 // Calculate min/max for scaling
32 const counts = data.map((d) => d.count);
33 const max = Math.max(...counts, 1);
34 const min = Math.min(...counts, 0);
35 const range = max - min || 1;
36
37 // Max height is 75% of the available height
38 const maxHeight = height * 0.75;
39
40 // Generate SVG path
41 const points = data
42 .map((point, index) => {
43 const x = (index / (data.length - 1 || 1)) * width;
44 const y = height - ((point.count - min) / range) * maxHeight;
45 return `${x},${y}`;
46 })
47 .join(" ");
48
49 // Create area path for gradient fill
50 const areaPath = `M 0,${height} L ${points} L ${width},${height} Z`;
51
52 return (
53 <svg
54 width={width}
55 height={height}
56 className={className}
57 viewBox={`0 0 ${width} ${height}`}
58 preserveAspectRatio="none"
59 >
60 {/* Gradient definition */}
61 <defs>
62 <linearGradient
63 id="sparklineGradient"
64 x1="0%"
65 y1="0%"
66 x2="0%"
67 y2="100%"
68 >
69 <stop
70 offset="0%"
71 style={{ stopColor: "#22d3ee", stopOpacity: 0.5 }}
72 />
73 <stop
74 offset="100%"
75 style={{ stopColor: "#22d3ee", stopOpacity: 0.1 }}
76 />
77 </linearGradient>
78 </defs>
79
80 {/* Area fill */}
81 <path d={areaPath} fill="url(#sparklineGradient)" strokeWidth="0" />
82
83 {/* Line */}
84 <polyline
85 points={points}
86 fill="none"
87 stroke="#22d3ee"
88 strokeWidth="2"
89 strokeLinecap="round"
90 strokeLinejoin="round"
91 />
92 </svg>
93 );
94}