feat(dash): Revamp dashboard UI with glassmorphism and real bot data

This commit is contained in:
syntaxbullet
2026-01-08 20:58:57 +01:00
parent 8ebaf7b4ee
commit fff90804c0
14 changed files with 376 additions and 213 deletions

View File

@@ -50,119 +50,115 @@ export function Dashboard() {
}
return (
<div className="space-y-6">
<div>
<h2 className="text-3xl font-bold tracking-tight">Dashboard</h2>
<p className="text-muted-foreground">Overview of your bot's activity and performance.</p>
<div className="space-y-8 animate-in fade-in duration-700">
<div className="flex flex-col gap-2">
<h2 className="text-4xl font-extrabold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-white via-white to-white/40">
{stats.bot.name} Overview
</h2>
<p className="text-white/40 font-medium">Monitoring real-time activity and core bot metrics.</p>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{/* Metric Cards */}
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Servers</CardTitle>
<Server className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stats.guilds.count}</div>
<p className="text-xs text-muted-foreground">Active guilds</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Active Users</CardTitle>
<Users className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stats.users.active.toLocaleString()}</div>
<p className="text-xs text-muted-foreground">
{stats.users.total.toLocaleString()} total registered
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Commands</CardTitle>
<Zap className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stats.commands.total}</div>
<p className="text-xs text-muted-foreground">Registered commands</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Avg Ping</CardTitle>
<Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stats.ping.avg}ms</div>
<p className="text-xs text-muted-foreground">WebSocket latency</p>
</CardContent>
</Card>
{[
{ title: "Active Users", value: stats.users.active.toLocaleString(), label: `${stats.users.total.toLocaleString()} total registered`, icon: Users, color: "from-purple-500 to-pink-500" },
{ title: "Commands registered", value: stats.commands.total, label: "Total system capabilities", icon: Zap, color: "from-yellow-500 to-orange-500" },
{ title: "Avg Latency", value: `${stats.ping.avg}ms`, label: "WebSocket heartbeat", icon: Activity, color: "from-emerald-500 to-teal-500" },
].map((metric, i) => (
<Card key={i} className="glass group hover:border-primary/50 transition-all duration-300 hover:scale-[1.02]">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-xs font-bold uppercase tracking-widest text-white/50">{metric.title}</CardTitle>
<div className={`p-2 rounded-lg bg-gradient-to-br ${metric.color} bg-opacity-10 group-hover:scale-110 transition-transform duration-300`}>
<metric.icon className="h-4 w-4 text-white" />
</div>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold tracking-tight mb-1">{metric.value}</div>
<p className="text-xs font-medium text-white/30">{metric.label}</p>
</CardContent>
</Card>
))}
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7">
<Card className="col-span-4">
<CardHeader>
<CardTitle>Economy Overview</CardTitle>
<CardDescription>Server economy statistics</CardDescription>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-7">
<Card className="col-span-4 glass border-white/5">
<CardHeader className="flex flex-row items-start justify-between">
<div>
<CardTitle className="text-xl font-bold flex items-center gap-2">
<div className="h-5 w-1 bg-primary rounded-full" />
Economy Overview
</CardTitle>
<CardDescription className="text-white/40">Global wealth and progression statistics</CardDescription>
</div>
<div className="bg-white/5 px-3 py-1.5 rounded-full border border-white/10 flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse" />
<span className="text-[10px] font-bold uppercase tracking-widest text-white/50">
Uptime: {Math.floor(stats.uptime / 3600)}h {Math.floor((stats.uptime % 3600) / 60)}m
</span>
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<p className="text-sm font-medium">Total Wealth</p>
<p className="text-2xl font-bold">{BigInt(stats.economy.totalWealth).toLocaleString()} AU</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-sm font-medium">Average Level</p>
<p className="text-xl font-bold">{stats.economy.avgLevel}</p>
<div className="grid gap-8">
<div className="relative group">
<div className="absolute -inset-1 bg-gradient-to-r from-primary/20 to-purple-500/20 rounded-2xl blur opacity-0 group-hover:opacity-100 transition duration-1000"></div>
<div className="relative bg-white/5 rounded-xl p-6 border border-white/10">
<p className="text-sm font-bold uppercase tracking-wider text-white/30 mb-1">Total Distributed Wealth</p>
<p className="text-4xl font-black text-glow bg-clip-text text-transparent bg-gradient-to-r from-primary to-purple-400">
{BigInt(stats.economy.totalWealth).toLocaleString()} <span className="text-xl font-bold text-white/20">AU</span>
</p>
</div>
<div>
<p className="text-sm font-medium">Top Streak</p>
<p className="text-xl font-bold">{stats.economy.topStreak} days</p>
</div>
<div className="grid grid-cols-2 gap-6">
<div className="bg-white/5 rounded-xl p-4 border border-white/5">
<p className="text-xs font-bold text-white/30 uppercase tracking-widest mb-1">Avg Level</p>
<p className="text-2xl font-bold">{stats.economy.avgLevel}</p>
</div>
<div className="bg-white/5 rounded-xl p-4 border border-white/5">
<p className="text-xs font-bold text-white/30 uppercase tracking-widest mb-1">Peak Streak</p>
<p className="text-2xl font-bold">{stats.economy.topStreak} <span className="text-sm text-white/20">days</span></p>
</div>
</div>
</div>
</CardContent>
</Card>
<Card className="col-span-3">
<CardHeader>
<CardTitle>Recent Events</CardTitle>
<CardDescription>Latest system and bot events.</CardDescription>
<Card className="col-span-3 glass border-white/5 overflow-hidden">
<CardHeader className="bg-white/[0.02] border-b border-white/5">
<CardTitle className="text-xl font-bold">Recent Events</CardTitle>
<CardDescription className="text-white/30">Live system activity feed</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<CardContent className="p-0">
<div className="divide-y divide-white/5">
{stats.recentEvents.length === 0 ? (
<p className="text-sm text-muted-foreground">No recent events</p>
<div className="p-8 text-center bg-transparent">
<p className="text-sm text-white/20 font-medium">No activity recorded</p>
</div>
) : (
stats.recentEvents.slice(0, 5).map((event, i) => (
<div key={i} className="flex items-center">
<div
className={`w-2 h-2 rounded-full mr-2 ${event.type === 'success'
? 'bg-emerald-500'
: event.type === 'error'
? 'bg-destructive'
: 'bg-blue-500'
}`}
/>
stats.recentEvents.slice(0, 6).map((event, i) => (
<div key={i} className="flex items-start gap-4 p-4 hover:bg-white/[0.03] transition-colors group">
<div className={`mt-1 p-2 rounded-lg ${event.type === 'success' ? 'bg-emerald-500/10 text-emerald-500' :
event.type === 'error' ? 'bg-red-500/10 text-red-500' :
'bg-blue-500/10 text-blue-500'
} group-hover:scale-110 transition-transform`}>
<div className="text-lg leading-none">{event.icon}</div>
</div>
<div className="space-y-1 flex-1">
<p className="text-sm font-medium leading-none">
{event.icon} {event.message}
<p className="text-sm font-semibold text-white/90 leading-tight">
{event.message}
</p>
<p className="text-sm text-muted-foreground">
{new Date(event.timestamp).toLocaleString()}
<p className="text-[10px] font-bold text-white/20 uppercase tracking-wider">
{new Date(event.timestamp).toLocaleTimeString()}
</p>
</div>
</div>
))
)}
</div>
{stats.recentEvents.length > 0 && (
<button className="w-full py-3 text-[10px] font-bold uppercase tracking-[0.2em] text-white/20 hover:text-primary hover:bg-white/[0.02] transition-all border-t border-white/5">
View Event Logs
</button>
)}
</CardContent>
</Card>
</div>