SparkBar.tsx79 lines · main
1import { cn } from 'ui'
2
3interface SparkBarProps {
4 value: number
5 max?: number
6 type?: 'horizontal' | 'vertical'
7 labelTop?: string
8 labelTopClass?: string
9 labelBottom?: string
10 labelBottomClass?: string
11 barClass?: string
12 bgClass?: string
13 borderClass?: string
14}
15
16export const SparkBar = ({
17 max = 100,
18 value = 0,
19 barClass = 'bg-foreground',
20 bgClass = '',
21 type = 'vertical',
22 borderClass = '',
23 labelBottom = '',
24 labelBottomClass = 'tabular-nums',
25 labelTop = '',
26 labelTopClass = '',
27}: SparkBarProps) => {
28 if (type === 'horizontal') {
29 const width = Number((value / max) * 100)
30 const widthCss = `${width}%`
31 const hasLabels = labelBottom || labelTop
32
33 return (
34 <div className="flex flex-col w-full">
35 {hasLabels && (
36 <div className="flex align-baseline justify-between pb-1 space-x-8">
37 <p
38 className={cn(
39 'text-foreground text-sm truncate capitalize-sentence',
40 labelTop.length > 0 && 'max-w-[75%]',
41 labelBottomClass
42 )}
43 >
44 {labelBottom}
45 </p>
46 <p className={cn('text-foreground-light text-sm', labelTopClass)}>{labelTop}</p>
47 </div>
48 )}
49 <div
50 className={`relative rounded-sm h-1 overflow-hidden w-full border p-0 ${
51 bgClass ? bgClass : 'bg-surface-400'
52 } ${borderClass ? borderClass : 'border-none'}`}
53 >
54 <div
55 className={`absolute rounded-sm inset-x-0 bottom-0 h-1 ${barClass} transition-all`}
56 style={{ width: widthCss }}
57 ></div>
58 </div>
59 </div>
60 )
61 } else {
62 const totalHeight = 35
63 let height = Number((value / max) * totalHeight)
64 if (height < 2) height = 2
65
66 return (
67 <div
68 className={`relative rounded-sm w-5 overflow-hidden border p-1 ${
69 bgClass ? bgClass : 'bg-gray-400'
70 } ${borderClass ? borderClass : 'border-none'}`}
71 style={{ height: totalHeight }}
72 >
73 <div className={`absolute inset-x-0 bottom-0 w-5 ${barClass}`} style={{ height }}></div>
74 </div>
75 )
76 }
77}
78
79export default SparkBar