feat: (ui) new design

This commit is contained in:
syntaxbullet
2026-01-09 15:12:35 +01:00
parent a5b8d922e3
commit 1b84dbd36d
23 changed files with 1023 additions and 1536 deletions

View File

@@ -1,278 +1,67 @@
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Activity, Server, Users, Zap, Package, Trophy, Coins } from "lucide-react";
import { useDashboardStats } from "@/hooks/use-dashboard-stats";
import { useActivityStats } from "@/hooks/use-activity-stats";
import { ControlPanel } from "@/components/ControlPanel";
import { ActivityChart } from "@/components/ActivityChart";
import React from "react";
import { Link } from "react-router-dom";
import { useSocket } from "../hooks/use-socket";
import { Badge } from "../components/ui/badge";
export function Dashboard() {
const { stats, loading, error } = useDashboardStats();
const { data: activityData, loading: activityLoading } = useActivityStats();
if (loading && !stats) {
return (
<div className="space-y-6">
<div>
<h2 className="text-3xl font-bold tracking-tight">Dashboard</h2>
<p className="text-muted-foreground">Loading dashboard data...</p>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
{[1, 2, 3, 4].map((i) => (
<Card key={i}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Loading...</CardTitle>
</CardHeader>
<CardContent>
<div className="h-8 w-20 bg-muted animate-pulse rounded" />
</CardContent>
</Card>
))}
</div>
</div>
);
}
if (error) {
return (
<div className="space-y-6">
<div>
<h2 className="text-3xl font-bold tracking-tight">Dashboard</h2>
<p className="text-destructive">Error loading dashboard: {error}</p>
</div>
</div>
);
}
if (!stats) {
return null;
}
const { isConnected, stats } = useSocket();
return (
<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-6 md:grid-cols-2 lg:grid-cols-4">
{/* Metric Cards */}
{[
{ 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: "Items in Circulation", value: stats.economy.totalItems.toLocaleString(), label: "Total items owned", icon: Package, color: "from-blue-500 to-cyan-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>
{/* Activity Chart Section */}
<Card className="glass border-white/5 overflow-hidden">
<CardHeader className="pb-2">
<CardTitle className="text-xl font-bold flex items-center gap-2">
<div className="h-5 w-1 bg-emerald-500 rounded-full" />
Live Activity Analytics
</CardTitle>
<CardDescription className="text-white/40 font-medium tracking-tight">Hourly command and transaction volume across the network (last 24h)</CardDescription>
</CardHeader>
<CardContent>
<ActivityChart data={activityData} loading={activityLoading} />
</CardContent>
</Card>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-7">
<Card className="col-span-4 glass border-white/5 h-full">
<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="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>
<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>
<div className="col-span-3 flex flex-col gap-6">
{/* Administrative Control Panel */}
<ControlPanel maintenanceMode={stats.maintenanceMode} />
{/* Active Lootdrop Alert */}
{stats.activeLootdrops && stats.activeLootdrops.length > 0 && (
<Card className="bg-gradient-to-br from-red-500/10 to-orange-500/10 border-red-500/20 overflow-hidden relative">
<div className="absolute top-0 right-0 p-4 opacity-10">
<Zap className="w-24 h-24 text-red-500" />
</div>
<CardHeader className="pb-2">
<CardTitle className="text-lg font-bold text-red-400 flex items-center gap-2">
<span className="relative flex h-3 w-3">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
</span>
ACTIVE LOOTDROP
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-col gap-1">
<p className="text-2xl font-black text-white/90">
{stats.activeLootdrops[0]?.rewardAmount} {stats.activeLootdrops[0]?.currency}
</p>
<p className="text-xs font-medium text-white/50">
Expires <span className="text-red-300">{stats.activeLootdrops[0]?.expiresAt ? new Date(stats.activeLootdrops[0].expiresAt).toLocaleTimeString() : 'Never'}</span>
</p>
</div>
</CardContent>
</Card>
<div className="min-h-screen bg-aurora-page text-foreground font-outfit overflow-x-hidden">
{/* Navigation */}
<nav className="fixed top-0 w-full z-50 glass-card border-b border-border/50 py-4 px-8 flex justify-between items-center">
<div className="flex items-center gap-3">
{/* Bot Avatar */}
{stats?.bot?.avatarUrl ? (
<img
src={stats.bot.avatarUrl}
alt="Aurora Avatar"
className="w-8 h-8 rounded-full border border-primary/20 shadow-sm object-cover"
/>
) : (
<div className="w-8 h-8 rounded-full bg-aurora sun-flare shadow-sm" />
)}
{/* Recent Events Feed */}
<Card className="glass border-white/5 overflow-hidden flex-1">
<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 className="p-0">
<div className="divide-y divide-white/5">
{stats.recentEvents.length === 0 ? (
<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, 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' :
event.type === 'warn' ? 'bg-yellow-500/10 text-yellow-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-semibold text-white/90 leading-tight">
{event.message}
</p>
<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>
<span className="text-xl font-bold tracking-tight text-primary">Aurora</span>
{/* Live Status Badge */}
<div className={`flex items-center gap-1.5 px-2 py-0.5 rounded-full border transition-colors duration-500 ${isConnected
? "bg-emerald-500/10 border-emerald-500/20 text-emerald-500"
: "bg-red-500/10 border-red-500/20 text-red-500"
}`}>
<div className="relative flex h-2 w-2">
{isConnected && (
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-500 opacity-75"></span>
)}
</CardContent>
</Card>
<span className={`relative inline-flex rounded-full h-2 w-2 ${isConnected ? "bg-emerald-500" : "bg-red-500"}`}></span>
</div>
<span className="text-[10px] font-bold tracking-wider uppercase">
{isConnected ? "Live" : "Offline"}
</span>
</div>
</div>
</div>
{/* Leaderboards Section */}
<div className="grid gap-6 md:grid-cols-2">
<Card className="glass border-white/5">
<CardHeader className="flex flex-row items-center gap-4">
<div className="p-2 bg-yellow-500/10 rounded-lg">
<Trophy className="w-5 h-5 text-yellow-500" />
</div>
<div>
<CardTitle className="text-lg font-bold">Top Levels</CardTitle>
<CardDescription className="text-white/40">Highest ranked users</CardDescription>
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
{stats.leaderboards?.topLevels.map((user, i) => (
<div key={i} className="flex items-center justify-between p-3 rounded-lg bg-white/5 border border-white/5">
<div className="flex items-center gap-3">
<div className={`w-8 h-8 rounded-full flex items-center justify-center font-bold text-sm ${i === 0 ? 'bg-yellow-500/20 text-yellow-500' : i === 1 ? 'bg-gray-400/20 text-gray-400' : i === 2 ? 'bg-orange-700/20 text-orange-700' : 'bg-white/5 text-white/40'}`}>
{i + 1}
</div>
<span className="font-semibold">{user.username}</span>
</div>
<span className="font-mono text-sm text-white/60">Lvl {user.level}</span>
</div>
)) || <p className="text-white/20 text-sm">No data available</p>}
</div>
</CardContent>
</Card>
<div className="flex items-center gap-6">
<Link to="/" className="text-step--1 font-medium text-muted-foreground hover:text-primary transition-colors">
Home
</Link>
<Link to="/design-system" className="text-step--1 font-medium text-muted-foreground hover:text-primary transition-colors">
Design System
</Link>
</div>
</nav>
<Card className="glass border-white/5">
<CardHeader className="flex flex-row items-center gap-4">
<div className="p-2 bg-emerald-500/10 rounded-lg">
<Coins className="w-5 h-5 text-emerald-500" />
</div>
<div>
<CardTitle className="text-lg font-bold">Richest Users</CardTitle>
<CardDescription className="text-white/40">Highest net worth</CardDescription>
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
{stats.leaderboards?.topWealth.map((user, i) => (
<div key={i} className="flex items-center justify-between p-3 rounded-lg bg-white/5 border border-white/5">
<div className="flex items-center gap-3">
<div className={`w-8 h-8 rounded-full flex items-center justify-center font-bold text-sm ${i === 0 ? 'bg-yellow-500/20 text-yellow-500' : i === 1 ? 'bg-gray-400/20 text-gray-400' : i === 2 ? 'bg-orange-700/20 text-orange-700' : 'bg-white/5 text-white/40'}`}>
{i + 1}
</div>
<span className="font-semibold">{user.username}</span>
</div>
<span className="font-mono text-sm text-white/60">{BigInt(user.balance).toLocaleString()} AU</span>
</div>
)) || <p className="text-white/20 text-sm">No data available</p>}
</div>
</CardContent>
</Card>
</div>
{/* Content Placeholder */}
<main className="pt-32 px-8 max-w-7xl mx-auto">
<div className="glass-card p-6 rounded-lg border border-border/50">
<h1 className="text-2xl font-bold text-primary mb-2">Dashboard Overview</h1>
<p className="text-muted-foreground">
Real-time connection status: <span className={isConnected ? "text-emerald-500 font-medium" : "text-red-500 font-medium"}>
{isConnected ? "Connected" : "Disconnected"}
</span>
</p>
</div>
</main>
</div>
);
}