This commit is contained in:
2026-02-02 23:13:09 +01:00
parent d0b4a53f80
commit 0951ad4799
3 changed files with 237 additions and 236 deletions
+2 -4
View File
@@ -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
View File
@@ -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" },
];
+28
View File
@@ -0,0 +1,28 @@
"use client"
import * as React from "react"
import { Separator as SeparatorPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
function Separator({
className,
orientation = "horizontal",
decorative = true,
...props
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
return (
<SeparatorPrimitive.Root
data-slot="separator"
decorative={decorative}
orientation={orientation}
className={cn(
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
className
)}
{...props}
/>
)
}
export { Separator }