mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-05 17:46:37 +08:00
938e9ff4fd
* 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
122 lines
4.1 KiB
TypeScript
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>
|
|
);
|
|
};
|