feat(dash): Revamp dashboard UI with glassmorphism and real bot data
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user