Profile
This commit is contained in:
@@ -9,7 +9,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||
|
||||
const Problems = () => {
|
||||
export default function Problems() {
|
||||
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
|
||||
|
||||
const categories = ["All", "Arrays", "Trees", "Graphs", "DP", "Strings"];
|
||||
@@ -90,9 +90,7 @@ const Problems = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Problems;
|
||||
}
|
||||
|
||||
/* ---------------- data ---------------- */
|
||||
|
||||
|
||||
+207
-232
@@ -1,15 +1,15 @@
|
||||
import {
|
||||
Trophy,
|
||||
Timer,
|
||||
Zap,
|
||||
Target,
|
||||
Calendar,
|
||||
TrendingUp,
|
||||
Award,
|
||||
} from "lucide-react";
|
||||
"use client";
|
||||
|
||||
import { Trophy, Timer, Zap, Target, Calendar, Award } from "lucide-react";
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
|
||||
import StatCard from "@/components/app/StatCard";
|
||||
|
||||
const Profile = () => {
|
||||
export default function Profile() {
|
||||
const user = {
|
||||
username: "speedmaster_x",
|
||||
joinDate: "Jan 2024",
|
||||
@@ -21,139 +21,49 @@ const Profile = () => {
|
||||
favoriteCategory: "Any%",
|
||||
};
|
||||
|
||||
const recentRuns = [
|
||||
{
|
||||
id: 1,
|
||||
category: "Any%",
|
||||
time: "2:38.54",
|
||||
date: "2 hours ago",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
category: "Any%",
|
||||
time: "2:45.12",
|
||||
date: "3 hours ago",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
category: "Easy Only",
|
||||
time: "1:23.45",
|
||||
date: "5 hours ago",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
category: "Any%",
|
||||
time: "--:--",
|
||||
date: "5 hours ago",
|
||||
status: "reset",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
category: "Any%",
|
||||
time: "2:51.33",
|
||||
date: "Yesterday",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
category: "No DP",
|
||||
time: "3:45.67",
|
||||
date: "Yesterday",
|
||||
status: "clean",
|
||||
},
|
||||
];
|
||||
|
||||
const achievements = [
|
||||
{
|
||||
name: "First Blood",
|
||||
description: "Complete your first run",
|
||||
icon: Zap,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "Sub-3 Club",
|
||||
description: "Finish a run under 3 minutes",
|
||||
icon: Timer,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "World Record",
|
||||
description: "Hold a world record",
|
||||
icon: Trophy,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "Century",
|
||||
description: "Complete 100 runs",
|
||||
icon: Target,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "Perfectionist",
|
||||
description: "100 clean runs",
|
||||
icon: Award,
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
name: "Marathon",
|
||||
description: "10 hours of running",
|
||||
icon: Calendar,
|
||||
unlocked: true,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen pt-24 pb-16">
|
||||
<div className="container mx-auto px-6">
|
||||
<div className="container mx-auto px-6 space-y-8">
|
||||
{/* Profile Header */}
|
||||
<div className="bg-card border border-border rounded-2xl p-8 mb-8 relative overflow-hidden">
|
||||
{/* Background gradient */}
|
||||
<div className="absolute inset-0 bg-linear-to-r from-primary/10 via-transparent to-transparent pointer-events-none" />
|
||||
<Card className="relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-linear-to-r from-primary/10 via-transparent to-transparent" />
|
||||
|
||||
<div className="relative flex flex-col md:flex-row items-start md:items-center gap-6">
|
||||
<CardContent className="relative p-8 flex flex-col md:flex-row gap-6">
|
||||
{/* Avatar */}
|
||||
<div className="relative">
|
||||
<div className="w-24 h-24 rounded-2xl bg-linear-to-br from-primary to-primary/50 flex items-center justify-center text-3xl font-bold text-primary-foreground glow-purple">
|
||||
{user.username.charAt(0).toUpperCase()}
|
||||
<div className="w-24 h-24 rounded-2xl bg-linear-to-br from-primary to-primary/60 flex items-center justify-center text-3xl font-bold text-primary-foreground glow-purple">
|
||||
{user.username[0].toUpperCase()}
|
||||
</div>
|
||||
<div className="absolute -bottom-2 -right-2 w-8 h-8 rounded-lg rank-gold flex items-center justify-center text-sm font-bold glow-gold">
|
||||
#1
|
||||
#{user.rank}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* User Info */}
|
||||
<div className="flex-1">
|
||||
<h1 className="text-3xl font-bold text-foreground mb-1">
|
||||
{user.username}
|
||||
</h1>
|
||||
<h1 className="text-3xl font-bold">{user.username}</h1>
|
||||
<p className="text-muted-foreground mb-3">
|
||||
Runner since {user.joinDate}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<span className="px-3 py-1 rounded-lg bg-primary/10 text-primary text-sm font-medium border border-primary/30">
|
||||
World Record Holder
|
||||
</span>
|
||||
<span className="px-3 py-1 rounded-lg bg-secondary text-secondary-foreground text-sm">
|
||||
{user.favoriteCategory} Main
|
||||
</span>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Badge>World Record Holder</Badge>
|
||||
<Badge variant="secondary">{user.favoriteCategory} Main</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Stats */}
|
||||
{/* PB */}
|
||||
<div className="text-right">
|
||||
<p className="text-4xl font-bold font-mono text-primary text-glow">
|
||||
{user.pb}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">Personal Best</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<StatCard
|
||||
label="Total Runs"
|
||||
value={user.totalRuns.toLocaleString()}
|
||||
@@ -183,80 +93,71 @@ const Profile = () => {
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
{/* Recent Runs */}
|
||||
<div className="lg:col-span-2">
|
||||
<div className="bg-card border border-border rounded-xl p-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-xl font-bold text-foreground">
|
||||
Recent Runs
|
||||
</h2>
|
||||
<button className="text-sm text-primary hover:underline">
|
||||
View All
|
||||
</button>
|
||||
</div>
|
||||
<Card className="lg:col-span-2">
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
<CardTitle>Recent Runs</CardTitle>
|
||||
<Button variant="link" size="sm">
|
||||
View all
|
||||
</Button>
|
||||
</CardHeader>
|
||||
|
||||
<div className="space-y-3">
|
||||
{recentRuns.map((run, i) => (
|
||||
<div
|
||||
key={run.id}
|
||||
className="flex items-center justify-between py-3 px-4 rounded-lg bg-secondary/30 hover:bg-secondary/50 transition-colors animate-fade-in opacity-0"
|
||||
style={{
|
||||
animationDelay: `${i * 0.1}s`,
|
||||
animationFillMode: "forwards",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
run.status === "clean"
|
||||
? "bg-emerald-400"
|
||||
: "bg-red-400"
|
||||
}`}
|
||||
/>
|
||||
<div>
|
||||
<p className="font-medium text-foreground">
|
||||
{run.category}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{run.date}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p
|
||||
className={`font-mono font-semibold ${
|
||||
run.status === "reset"
|
||||
? "text-red-400"
|
||||
: "text-foreground"
|
||||
}`}
|
||||
>
|
||||
{run.time}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground capitalize">
|
||||
{run.status}
|
||||
<CardContent className="space-y-3">
|
||||
{recentRuns.map((run, i) => (
|
||||
<div
|
||||
key={run.id}
|
||||
className="flex items-center justify-between rounded-lg px-4 py-3 bg-secondary/30 hover:bg-secondary/50 transition animate-fade-in opacity-0"
|
||||
style={{
|
||||
animationDelay: `${i * 0.1}s`,
|
||||
animationFillMode: "forwards",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
run.status === "clean" ? "bg-emerald-400" : "bg-red-400"
|
||||
}`}
|
||||
/>
|
||||
<div>
|
||||
<p className="font-medium">{run.category}</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{run.date}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Achievements */}
|
||||
<div className="lg:col-span-1">
|
||||
<div className="bg-card border border-border rounded-xl p-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-xl font-bold text-foreground">
|
||||
Achievements
|
||||
</h2>
|
||||
<span className="text-sm text-muted-foreground">5/6</span>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p
|
||||
className={`font-mono font-semibold ${
|
||||
run.status === "reset"
|
||||
? "text-red-400"
|
||||
: "text-foreground"
|
||||
}`}
|
||||
>
|
||||
{run.time}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground capitalize">
|
||||
{run.status}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="space-y-3">
|
||||
{achievements.map((achievement, i) => (
|
||||
{/* Achievements + PB */}
|
||||
<div className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
<CardTitle>Achievements</CardTitle>
|
||||
<span className="text-sm text-muted-foreground">5 / 6</span>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-3">
|
||||
{achievements.map((a, i) => (
|
||||
<div
|
||||
key={achievement.name}
|
||||
className={`flex items-center gap-3 p-3 rounded-lg transition-all animate-fade-in opacity-0 ${
|
||||
achievement.unlocked
|
||||
key={a.name}
|
||||
className={`flex items-center gap-3 rounded-lg p-3 animate-fade-in opacity-0 ${
|
||||
a.unlocked
|
||||
? "bg-primary/10 border border-primary/20"
|
||||
: "bg-secondary/30 opacity-50"
|
||||
}`}
|
||||
@@ -267,39 +168,33 @@ const Profile = () => {
|
||||
>
|
||||
<div
|
||||
className={`p-2 rounded-lg ${
|
||||
achievement.unlocked
|
||||
a.unlocked
|
||||
? "bg-primary/20 text-primary"
|
||||
: "bg-secondary text-muted-foreground"
|
||||
}`}
|
||||
>
|
||||
<achievement.icon className="h-4 w-4" />
|
||||
<a.icon className="h-4 w-4" />
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<p
|
||||
className={`text-sm font-medium ${
|
||||
achievement.unlocked
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground"
|
||||
}`}
|
||||
>
|
||||
{achievement.name}
|
||||
</p>
|
||||
<p className="text-sm font-medium">{a.name}</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{achievement.description}
|
||||
{a.description}
|
||||
</p>
|
||||
</div>
|
||||
{achievement.unlocked && (
|
||||
|
||||
{a.unlocked && (
|
||||
<div className="w-5 h-5 rounded-full bg-primary flex items-center justify-center">
|
||||
<svg
|
||||
className="w-3 h-3 text-primary-foreground"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={3}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={3}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
@@ -307,44 +202,124 @@ const Profile = () => {
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* PB History */}
|
||||
<div className="bg-card border border-border rounded-xl p-6 mt-4">
|
||||
<h2 className="text-xl font-bold text-foreground mb-4">
|
||||
PB History
|
||||
</h2>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-center py-2 border-b border-border">
|
||||
<span className="text-muted-foreground text-sm">2:34.21</span>
|
||||
<span className="text-xs text-muted-foreground">Today</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center py-2 border-b border-border">
|
||||
<span className="text-muted-foreground text-sm">2:38.54</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
3 days ago
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center py-2 border-b border-border">
|
||||
<span className="text-muted-foreground text-sm">2:45.12</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
1 week ago
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span className="text-muted-foreground text-sm">2:52.33</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
2 weeks ago
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>PB History</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
{pbHistory.map((pb, i) => (
|
||||
<div key={i}>
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-muted-foreground">{pb.time}</span>
|
||||
<span className="text-muted-foreground">{pb.date}</span>
|
||||
</div>
|
||||
{i !== pbHistory.length - 1 && (
|
||||
<Separator className="my-2" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default Profile;
|
||||
/* ---------------- data ---------------- */
|
||||
|
||||
const recentRuns = [
|
||||
{
|
||||
id: 1,
|
||||
category: "Any%",
|
||||
time: "2:38.54",
|
||||
date: "2 hours ago",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
category: "Any%",
|
||||
time: "2:45.12",
|
||||
date: "3 hours ago",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
category: "Easy Only",
|
||||
time: "1:23.45",
|
||||
date: "5 hours ago",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
category: "Any%",
|
||||
time: "--:--",
|
||||
date: "5 hours ago",
|
||||
status: "reset",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
category: "Any%",
|
||||
time: "2:51.33",
|
||||
date: "Yesterday",
|
||||
status: "clean",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
category: "No DP",
|
||||
time: "3:45.67",
|
||||
date: "Yesterday",
|
||||
status: "clean",
|
||||
},
|
||||
];
|
||||
|
||||
const achievements = [
|
||||
{
|
||||
name: "First Blood",
|
||||
description: "Complete your first run",
|
||||
icon: Zap,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "Sub-3 Club",
|
||||
description: "Finish a run under 3 minutes",
|
||||
icon: Timer,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "World Record",
|
||||
description: "Hold a world record",
|
||||
icon: Trophy,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "Century",
|
||||
description: "Complete 100 runs",
|
||||
icon: Target,
|
||||
unlocked: true,
|
||||
},
|
||||
{
|
||||
name: "Perfectionist",
|
||||
description: "100 clean runs",
|
||||
icon: Award,
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
name: "Marathon",
|
||||
description: "10 hours of running",
|
||||
icon: Calendar,
|
||||
unlocked: true,
|
||||
},
|
||||
];
|
||||
|
||||
const pbHistory = [
|
||||
{ time: "2:34.21", date: "Today" },
|
||||
{ time: "2:38.54", date: "3 days ago" },
|
||||
{ time: "2:45.12", date: "1 week ago" },
|
||||
{ time: "2:52.33", date: "2 weeks ago" },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user