refactor: 重构页面布局,样式

This commit is contained in:
Blizzard
2026-03-02 15:00:37 +08:00
parent da7ac70eeb
commit 4dfd7f87c7
18 changed files with 2875 additions and 965 deletions
+257 -75
View File
@@ -7,98 +7,280 @@ import {
Users,
Activity,
ArrowUpRight,
ArrowDownRight
ArrowDownRight,
Play,
Zap
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
import { motion } from 'framer-motion';
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from 'recharts';
const chartData = [
{ name: '06:00', morning: 400, evening: 240 },
{ name: '09:00', morning: 700, evening: 300 },
{ name: '12:00', morning: 600, evening: 450 },
{ name: '15:00', morning: 800, evening: 500 },
{ name: '18:00', morning: 500, evening: 900 },
{ name: '21:00', morning: 300, evening: 1200 },
{ name: '00:00', morning: 200, evening: 800 },
];
export default function Dashboard() {
const stats = [
{ name: '总分类数', value: '12', icon: ListMusic, change: '+2', trend: 'up' },
{ name: '活跃频道', value: '45', icon: Mic2, change: '+5', trend: 'up' },
{ name: '节目总数', value: '3,284', icon: Disc3, change: '+124', trend: 'up' },
{ name: '订阅用户', value: '12.4K', icon: Users, change: '-24', trend: 'down' },
{
name: '总分类数',
value: '12',
icon: ListMusic,
change: '+2',
trend: 'up',
color: 'from-[#D28F4F] to-[#A64452]',
iconColor: 'text-[#D28F4F]'
},
{
name: '活跃频道',
value: '45',
icon: Mic2,
change: '+5',
trend: 'up',
color: 'from-[#6C5CE7] to-[#A64452]',
iconColor: 'text-[#6C5CE7]'
},
{
name: '节目总数',
value: '3,284',
icon: Disc3,
change: '+124',
trend: 'up',
color: 'from-[#D28F4F] to-[#E29A66]',
iconColor: 'text-[#D28F4F]'
},
{
name: '订阅用户',
value: '12.4K',
icon: Users,
change: '-24',
trend: 'down',
color: 'from-[#8C7E6C] to-[#4A3A2C]',
iconColor: 'text-[#4A3A2C]'
},
];
return (
<div className="space-y-8 animate-in fade-in duration-500">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div className="space-y-10 pb-10">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="flex flex-col md:flex-row md:items-center justify-between gap-6"
>
<div>
<h1 className="text-3xl font-extrabold tracking-tight text-slate-900 dark:text-slate-100"></h1>
<p className="text-slate-500 mt-1"></p>
<h1 className="text-4xl font-black tracking-tight text-[#4A3A2C] flex items-center gap-4">
<span className="text-3xl animate-bounce"></span>
</h1>
<p className="text-[#8C7E6C] font-medium mt-3 flex items-center gap-3">
<div className="w-8 h-8 rounded-xl bg-[#FAF5E6] flex items-center justify-center shadow-sm border border-[#D28F4F]/10">
<Zap className="w-4 h-4 text-[#D28F4F] fill-[#D28F4F]" />
</div>
<span className="text-[#D28F4F] font-black underline decoration-2 underline-offset-4">1,248</span>
</p>
</div>
<div className="flex items-center space-x-2 bg-white dark:bg-slate-900 border px-4 py-2 rounded-2xl shadow-sm self-start">
<Activity className="w-4 h-4 text-emerald-500 animate-pulse" />
<span className="text-sm font-medium text-slate-600 dark:text-slate-400 uppercase tracking-widest">线</span>
<div className="flex items-center space-x-4 bg-white/40 backdrop-blur-3xl border border-[#D28F4F]/10 px-8 py-4 rounded-[2.5rem] shadow-glass self-start relative group">
<div className="relative">
<Activity className="w-5 h-5 text-emerald-500" />
<div className="absolute inset-0 bg-emerald-500 blur-md opacity-40 animate-pulse" />
</div>
<span className="text-[11px] font-black text-[#8C7E6C] uppercase tracking-[0.3em]">广</span>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-[#D28F4F] rounded-full shadow-[0_0_10px_#D28F4F]" />
</div>
</div>
</motion.div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
{stats.map((stat) => (
<Card key={stat.name} className="border-none shadow-sm hover:shadow-md transition-shadow group rounded-3xl overflow-hidden bg-white dark:bg-slate-900">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-semibold text-slate-500 uppercase tracking-wider">{stat.name}</CardTitle>
<div className={`p-2 rounded-xl group-hover:scale-110 transition-transform ${stat.trend === 'up' ? 'bg-emerald-50 text-emerald-600' : 'bg-rose-50 text-rose-600'
}`}>
<stat.icon className="h-5 w-5" />
</div>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold tracking-tight text-slate-900 dark:text-white mt-1">{stat.value}</div>
<p className="text-xs text-slate-500 mt-2 flex items-center">
<span className={`flex items-center font-medium mr-1 ${stat.trend === 'up' ? 'text-emerald-500' : 'text-rose-500'
}`}>
{stat.trend === 'up' ? <ArrowUpRight className="w-3 h-3 mr-0.5" /> : <ArrowDownRight className="w-3 h-3 mr-0.5" />}
{stat.change}
</span>
</p>
</CardContent>
</Card>
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-4">
{stats.map((stat, index) => (
<motion.div
key={stat.name}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: index * 0.1, type: "spring", stiffness: 100 }}
>
<Card className="glass-card warm-noise border-none group relative overflow-hidden h-full rounded-[2.5rem] p-4">
<div className={`absolute -top-10 -right-10 w-40 h-40 bg-gradient-to-br ${stat.color} opacity-0 group-hover:opacity-10 blur-3xl transition-opacity duration-700`} />
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-6">
<CardTitle className="text-[11px] font-black text-[#8C7E6C] uppercase tracking-[0.2em]">{stat.name}</CardTitle>
<div className={`p-4 rounded-[1.5rem] transition-all duration-700 shadow-sm border border-white/40 bg-white/90 ${stat.iconColor} group-hover:rotate-12 group-hover:scale-110 group-hover:shadow-[0_20px_40px_rgba(0,0,0,0.05)]`}>
<stat.icon className="h-6 w-6" />
</div>
</CardHeader>
<CardContent>
<div className="text-4xl font-black tracking-tight text-[#4A3A2C] mb-4">{stat.value}</div>
<div className="flex items-center justify-between">
<div className="flex items-center bg-white/60 px-3 py-1.5 rounded-full border border-white/40 backdrop-blur-md shadow-sm">
<span className={`flex items-center text-[11px] font-black ${stat.trend === 'up' ? 'text-emerald-600' : 'text-rose-600'}`}>
{stat.trend === 'up' ? <ArrowUpRight className="w-3.5 h-3.5 mr-1" /> : <ArrowDownRight className="w-3.5 h-3.5 mr-1" />}
{stat.change}
</span>
</div>
<span className="text-[10px] font-black text-[#8C7E6C]/40 uppercase tracking-[0.2em]"></span>
</div>
</CardContent>
</Card>
</motion.div>
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="lg:col-span-2 border-none shadow-sm rounded-3xl bg-white dark:bg-slate-900">
<CardHeader className="pb-0">
<CardTitle className="text-lg font-bold flex items-center">
<TrendingUp className="w-5 h-5 mr-2 text-primary" />
</CardTitle>
</CardHeader>
<CardContent className="h-[300px] flex items-center justify-center text-slate-400 bg-slate-50/50 dark:bg-slate-950/20 m-6 rounded-2xl border-2 border-dashed">
(Growth data visualization)
</CardContent>
</Card>
<Card className="border-none shadow-sm rounded-3xl bg-white dark:bg-slate-900">
<CardHeader className="pb-0">
<CardTitle className="text-lg font-bold flex items-center">
<Radio className="w-5 h-5 mr-2 text-primary" />
</CardTitle>
</CardHeader>
<CardContent className="pt-6">
<div className="space-y-4">
{[1, 2, 3, 4, 5].map(i => (
<div key={i} className="flex items-center justify-between p-3 rounded-2xl hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors cursor-pointer group">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 rounded-xl bg-slate-100 dark:bg-slate-800 flex items-center justify-center font-bold text-slate-500 group-hover:bg-primary group-hover:text-white transition-colors">
#{i}
</div>
<div>
<p className="text-sm font-bold text-slate-900 dark:text-slate-100"> #{i}</p>
<p className="text-xs text-slate-400"></p>
</div>
</div>
<div className="text-right">
<p className="text-sm font-bold text-slate-900 dark:text-slate-100">{(1000 / i).toFixed(0)}</p>
<p className="text-[10px] text-slate-400 uppercase tracking-tighter"></p>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<motion.div
className="lg:col-span-2"
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.4 }}
>
<Card className="glass-card warm-noise border-none h-full overflow-hidden rounded-[3rem] p-6 relative z-10">
<CardHeader className="p-10 border-b border-[#4A3A2C]/5 flex flex-row items-center justify-between bg-[#FAF5E6]/40 rounded-t-[2.5rem]">
<div>
<CardTitle className="text-2xl font-black flex items-center tracking-tight text-[#4A3A2C]">
<div className="w-10 h-10 rounded-[1.2rem] bg-[#D28F4F] flex items-center justify-center mr-4 shadow-lg shadow-[#D28F4F]/20">
<TrendingUp className="w-5 h-5 text-white" />
</div>
</CardTitle>
<p className="text-[#8C7E6C] text-sm mt-2 font-medium"></p>
</div>
<div className="flex gap-6">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rounded-full bg-[#D28F4F] shadow-[0_0_12px_#D28F4F]" />
<span className="text-xs font-black text-[#8C7E6C] uppercase underline decoration-[#D28F4F]/20 underline-offset-4"></span>
</div>
))}
</div>
</CardContent>
</Card>
<div className="flex items-center gap-3">
<div className="w-3 h-3 rounded-full bg-[#A64452] shadow-[0_0_12px_#A64452]" />
<span className="text-xs font-black text-[#8C7E6C] uppercase underline decoration-[#A64452]/20 underline-offset-4"></span>
</div>
</div>
</CardHeader>
<CardContent className="p-10">
<div className="h-[400px] w-full">
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={chartData}>
<defs>
<linearGradient id="colorMorning" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#D28F4F" stopOpacity={0.3} />
<stop offset="95%" stopColor="#D28F4F" stopOpacity={0} />
</linearGradient>
<linearGradient id="colorEvening" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#A64452" stopOpacity={0.3} />
<stop offset="95%" stopColor="#A64452" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#4A3A2C" strokeOpacity={0.05} />
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
tick={{ fill: '#8C7E6C', fontSize: 11, fontWeight: 900 }}
dy={15}
/>
<YAxis hide />
<Tooltip
contentStyle={{
borderRadius: '24px',
border: 'none',
boxShadow: '0 20px 50px rgba(74, 58, 44, 0.1)',
background: 'rgba(255, 253, 235, 0.9)',
backdropFilter: 'blur(20px)',
padding: '16px',
color: '#4A3A2C'
}}
/>
<Area
type="monotone"
dataKey="morning"
stroke="#D28F4F"
strokeWidth={5}
fillOpacity={1}
fill="url(#colorMorning)"
animationDuration={2000}
/>
<Area
type="monotone"
dataKey="evening"
stroke="#A64452"
strokeWidth={5}
fillOpacity={1}
fill="url(#colorEvening)"
animationDuration={2000}
/>
</AreaChart>
</ResponsiveContainer>
</div>
</CardContent>
</Card>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.5 }}
>
<Card className="glass-card warm-noise border-none h-full overflow-hidden rounded-[3rem] p-6 relative z-10">
<CardHeader className="p-8 border-b border-[#4A3A2C]/5 bg-[#FAF5E6]/40 rounded-t-[2.5rem]">
<CardTitle className="text-xl font-black flex items-center tracking-tight text-[#4A3A2C] uppercase tracking-widest">
<div className="w-10 h-10 rounded-[1.2rem] bg-white flex items-center justify-center mr-4 shadow-sm">
<Radio className="w-5 h-5 text-[#D28F4F]" />
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-8">
<div className="space-y-6">
{[1, 2, 3, 4, 5].map(i => (
<div
key={i}
className={`flex items-center justify-between p-5 rounded-[2rem] transition-all cursor-pointer group hover:scale-[1.03] border border-[#D28F4F]/5 relative overflow-hidden ${i === 1 ? 'bg-gradient-to-r from-[#D28F4F]/10 to-[#A64452]/5 border-[#D28F4F]/20 shadow-sm' : 'hover:bg-white/60'
}`}
>
<div className="flex items-center space-x-6 relative z-10">
<div className="w-14 h-14 rounded-2xl overflow-hidden relative shadow-md ring-4 ring-white">
<img src={`https://picsum.photos/seed/radio${i}/100/100`} alt="" className="object-cover w-full h-full group-hover:scale-125 transition-transform duration-1000" />
<div className="absolute inset-0 bg-[#4A3A2C]/20 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
<Play className="w-6 h-6 text-white fill-white" />
</div>
</div>
<div>
<div className="flex items-center gap-3">
<p className="text-base font-black text-[#4A3A2C]"> #{i}</p>
{i <= 3 && (
<div className={`w-2 h-2 rounded-full ${i === 1 ? 'bg-[#D28F4F]' : i === 2 ? 'bg-[#8C7E6C]' : 'bg-[#E29A66]'} shadow-[0_0_10px_currentColor]`} />
)}
</div>
<div className="audio-wave mt-2 opacity-40 group-hover:opacity-100 transition-opacity flex gap-0.5">
<span className="w-1 h-3 bg-[#D28F4F] rounded-full animate-wave" />
<span className="w-1 h-5 bg-[#D28F4F] rounded-full animate-wave-slow" />
<span className="w-1 h-2 bg-[#D28F4F] rounded-full animate-wave" />
<span className="w-1 h-4 bg-[#D28F4F] rounded-full animate-wave-slow" />
</div>
</div>
</div>
<div className="text-right relative z-10">
<p className="text-lg font-black text-[#4A3A2C]">{(1240 / i).toFixed(0)}</p>
<p className="text-[10px] text-[#8C7E6C] font-black uppercase tracking-widest"></p>
</div>
</div>
))}
</div>
<Button variant="ghost" className="w-full mt-10 rounded-[1.5rem] h-14 font-black text-xs uppercase tracking-[0.3em] text-[#8C7E6C] hover:text-[#D28F4F] hover:bg-white transition-all">
</Button>
</CardContent>
</Card>
</motion.div>
</div>
</div>
);