Files
flvx/vite-frontend/src/pages/dashboard/components/flow-chart-card.tsx
T
sagit 938e9ff4fd feat(ui): redesign with transparent liquid glass (#414)
* docs: add design spec for iOS 26 Liquid Glass UI redesign

* docs: add implementation plan for iOS 26 Liquid Glass UI redesign

* feat(ui): add liquid glass CSS variables and update root layouts

* feat(ui): update Card and Modal components to iOS 26 Liquid Glass style

* feat(ui): redesign dashboard page to Liquid Glass style

* feat(ui): redesign node management page cards and charts

* feat(ui): redesign monitor page to Liquid Glass style

* feat(ui): redesign group and panel-sharing cards to Liquid Glass

* feat(ui): redesign settings and user components to Liquid Glass

* feat(ui): redesign profile and auth pages to Liquid Glass

* fix(ui): revert to LineChart to fix compilation issues

* refactor(ui): extract dashboard user header and cleanup admin layout

* feat(ui): refine monitor page hero metrics and fix build

* fix(ui): real data for monitor hero metrics and card padding adjustments

* fix(ui): apply global card padding and fix index layouts

* feat(ui): implement liquid-glass-react for all Card components

* fix(ui): resolve liquid-glass-react rendering issues causing invisible text and broken layout

* fix(ui): native CSS liquid-glass effect replacing NPM package

* fix(ui): cleanup duplicate closing tags and complete liquid glass tables

* fix(ui): apply perfect rounded corners to list views and table headers in non-compact mode

* fix(ui): apply liquid glass styling to grouped rules view in forward page

* fix(ui): re-implement liquid-glass natively to prevent text distortion and remove package dependency

* fix(ui): remove mouse distortion and preserve proper liquid glass texture

* fix(ui): remove svg filter causing text distortion and replace with pure css liquid glass

* fix(ui): apply properly scoped border radius to table headers

* fix(ui): remove hardcoded bg-default-50/60 from TableHeader

* fix(ui): apply global liquid glass styling and transparent overlays to all modals and dialogs

* fix(ui): remove absolute/relative class conflicts hiding Dialog modales and implement pure transparent layout

* feat(ui): apply global liquid glass styling to cards, buttons, and diagnosis modals
2026-04-05 13:22:12 +08:00

122 lines
4.1 KiB
TypeScript

import {
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import { Card, CardBody, CardHeader } from "@/shadcn-bridge/heroui/card";
import { PageEmptyState } from "@/components/page-state";
interface FlowChartPoint {
time: string;
flow: number;
}
interface FlowChartCardProps {
statisticsFlowsCount: number;
chartData: FlowChartPoint[];
formatFlow: (value: number, unit?: string) => string;
}
export const FlowChartCard = ({
statisticsFlowsCount,
chartData,
formatFlow,
}: FlowChartCardProps) => {
return (
<Card className="mb-6 lg:mb-8">
<CardHeader className="pb-3">
<div className="flex items-center gap-2">
<svg
aria-hidden="true"
className="w-5 h-5 text-primary"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z" />
<path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z" />
</svg>
<h2 className="text-lg lg:text-xl font-semibold text-foreground">
24小时流量统计
</h2>
</div>
</CardHeader>
<CardBody className="pt-0">
{statisticsFlowsCount === 0 ? (
<PageEmptyState className="h-48" message="暂无流量统计数据" />
) : (
<div className="h-64 lg:h-80 w-full">
<ResponsiveContainer height="100%" width="100%">
<LineChart data={chartData} margin={{ top: 20, right: 0, left: -20, bottom: 0 }}>
<XAxis
axisLine={false}
dataKey="time"
tick={{ fill: "currentColor", opacity: 0.5, fontSize: 12 }}
tickLine={false}
/>
<YAxis
axisLine={false}
tick={{ fill: "currentColor", opacity: 0.5, fontSize: 12 }}
tickFormatter={(value: number | string) => {
const v = typeof value === "number" ? value : Number(value);
if (!Number.isFinite(v)) return String(value);
if (v === 0) return "0";
if (v < 1024) return `${v}B`;
if (v < 1024 * 1024) return `${(v / 1024).toFixed(1)}K`;
if (v < 1024 * 1024 * 1024)
return `${(v / (1024 * 1024)).toFixed(1)}M`;
return `${(v / (1024 * 1024 * 1024)).toFixed(1)}G`;
}}
tickLine={false}
/>
<Tooltip
content={({
active,
payload,
label,
}: {
active?: boolean;
payload?: Array<{ value?: number | string }>;
label?: string | number;
}) => {
if (active && payload && payload.length) {
const firstValue = payload[0]?.value;
const numericValue =
typeof firstValue === "number"
? firstValue
: Number(firstValue);
const flowValue = Number.isFinite(numericValue)
? numericValue
: 0;
return (
<div className="bg-white/70 dark:bg-zinc-900/70 backdrop-blur-xl border border-white/50 rounded-2xl shadow-[0_10px_30px_rgba(0,0,0,0.1)] p-4">
<p className="font-medium text-foreground">{`时间: ${label ?? ""}`}</p>
<p className="text-primary font-semibold mt-1">{`流量: ${formatFlow(flowValue)}`}</p>
</div>
);
}
return null;
}}
cursor={{ fill: "rgba(0, 122, 255, 0.05)" }}
/>
<Line
dataKey="flow"
stroke="#007aff"
type="monotone"
/>
</LineChart>
</ResponsiveContainer>
</div>
)}
</CardBody>
</Card>
);
};