调整首页页面布局

This commit is contained in:
Eamon
2026-06-01 16:02:27 +08:00
parent e0bdcabbfe
commit 9f74483345
11 changed files with 967 additions and 553 deletions

View File

@@ -0,0 +1,101 @@
"use client"
import { useMemo } from "react"
interface SimpleHorizontalBarChartProps {
data: Record<string, string | number>[]
dataKey: string
labelKey: string
fill?: string
width?: number
}
export function SimpleHorizontalBarChart({
data,
dataKey,
labelKey,
fill = "#6366f1",
width = 300,
}: SimpleHorizontalBarChartProps) {
const chartWidth = width
const chartHeight = Math.max(data.length * 40 + 20, 120)
const padding = { top: 10, right: 10, bottom: 10, left: 80 }
const innerWidth = chartWidth - padding.left - padding.right
const bars = useMemo(() => {
if (data.length === 0) return []
const values = data.map(d => Number(d[dataKey]) || 0)
const maxVal = Math.max(...values, 1)
return data.map((d, i) => {
const val = Number(d[dataKey]) || 0
const barWidth = (val / maxVal) * innerWidth * 0.9
const y =
padding.top +
(i * (chartHeight - padding.top - padding.bottom)) / data.length
return {
x: padding.left,
y,
width: barWidth,
height: Math.min(
24,
(chartHeight - padding.top - padding.bottom) / data.length - 4,
),
label: String(d[labelKey] ?? ""),
value: val,
}
})
}, [data, dataKey, labelKey, innerWidth, chartHeight])
if (data.length === 0) {
return (
<div
className="flex items-center justify-center text-muted-foreground text-sm"
style={{ height: 120 }}
>
</div>
)
}
return (
<svg
viewBox={`0 0 ${chartWidth} ${chartHeight}`}
className="w-full"
preserveAspectRatio="xMidYMid meet"
style={{ height: chartHeight }}
>
{bars.map((bar, i) => (
<g key={i}>
<text
x={padding.left - 8}
y={bar.y + bar.height / 2 + 4}
textAnchor="end"
className="fill-muted-foreground"
fontSize={12}
>
{bar.label.length > 6 ? `${bar.label.slice(0, 6)}...` : bar.label}
</text>
<rect
x={bar.x}
y={bar.y}
width={bar.width}
height={bar.height}
rx={4}
fill={fill}
opacity={0.8}
/>
<text
x={bar.x + bar.width + 6}
y={bar.y + bar.height / 2 + 4}
className="fill-muted-foreground"
fontSize={11}
>
{bar.value}
</text>
</g>
))}
</svg>
)
}