Skip to content

Commit 9e4e262

Browse files
authored
fix:leaderboard update leaderboard-style (#187)
1 parent ee4363c commit 9e4e262

4 files changed

Lines changed: 735 additions & 1515 deletions

File tree

frontend/components/leaderboard/LeaderboardClient.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,23 @@ export default function LeaderboardClient({
2424

2525
return (
2626
<div className="relative min-h-screen w-full">
27-
2827
<div className="fixed inset-0 z-0">
2928
<DynamicGridBackground className="w-full h-full bg-gray-50 transition-colors duration-300 dark:bg-transparent" />
3029
</div>
3130

32-
<div className="relative z-10 w-full max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col items-center pt-20 pb-10">
33-
31+
<div className="relative z-10 w-full max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col items-center pt-20 pb-10">
3432
<header className="text-center mb-16 max-w-3xl">
3533
<motion.div
3634
initial={{ y: 20, opacity: 0 }}
3735
animate={{ y: 0, opacity: 1 }}
3836
transition={{ duration: 0.6 }}
3937
>
40-
<h1 className="text-4xl md:text-6xl lg:text-7xl font-black tracking-tight text-[var(--accent-primary)] mb-6 uppercase drop-shadow-sm">
38+
<h1 className="text-4xl md:text-6xl lg:text-7xl font-black tracking-tight text-[var(--accent-primary)] mb-6 drop-shadow-sm">
4139
{t('title')}
4240
</h1>
4341
</motion.div>
44-
45-
<motion.p
42+
43+
<motion.p
4644
initial={{ y: 20, opacity: 0 }}
4745
animate={{ y: 0, opacity: 1 }}
4846
transition={{ duration: 0.6, delay: 0.1 }}
@@ -57,7 +55,7 @@ export default function LeaderboardClient({
5755
{hasResults ? (
5856
<LeaderboardPodium topThree={topThree} />
5957
) : (
60-
<motion.div
58+
<motion.div
6159
initial={{ opacity: 0, scale: 0.95 }}
6260
animate={{ opacity: 1, scale: 1 }}
6361
className="text-center py-20 rounded-2xl border border-gray-200 dark:border-white/10 bg-white/60 dark:bg-[#111]/60 backdrop-blur-xl shadow-xl"
@@ -80,4 +78,4 @@ export default function LeaderboardClient({
8078
</div>
8179
</div>
8280
);
83-
}
81+
}

frontend/components/leaderboard/LeaderboardPodium.tsx

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,67 @@ export function LeaderboardPodium({ topThree }: { topThree: User[] }) {
1515

1616
return (
1717
<div className="flex items-end justify-center gap-4 md:gap-8 h-[350px] w-full max-w-3xl mx-auto">
18-
{podiumOrder.map((user) => {
19-
const isFirst = user.rank === 1;
20-
const isSecond = user.rank === 2;
21-
22-
const height = isFirst ? '100%' : isSecond ? '45%' : '30%';
23-
const delay = isFirst ? 0.4 : isSecond ? 0.2 : 0.6;
18+
{podiumOrder.map(user => {
19+
const rank = user.rank;
20+
const isFirst = rank === 1;
21+
22+
const height = rank === 1 ? '100%' : rank === 2 ? '40%' : '35%';
23+
const delay = rank === 1 ? 0.4 : rank === 2 ? 0.2 : 0.6;
24+
25+
const rankStyles = {
26+
1: {
27+
border: 'border-yellow-400 dark:border-yellow-500',
28+
bg: 'bg-yellow-400/20 dark:bg-yellow-500/10',
29+
text: 'text-yellow-600 dark:text-yellow-400',
30+
badge: 'bg-yellow-400 dark:bg-yellow-500',
31+
ring: 'border-yellow-400 dark:border-yellow-500',
32+
barTop: 'bg-yellow-400 dark:bg-yellow-500',
33+
},
34+
2: {
35+
border: 'border-slate-300 dark:border-slate-500',
36+
bg: 'bg-slate-300/20 dark:bg-slate-500/10',
37+
text: 'text-slate-600 dark:text-slate-400',
38+
badge: 'bg-slate-400 dark:bg-slate-500',
39+
ring: 'border-slate-300 dark:border-slate-500',
40+
barTop: 'bg-slate-300 dark:bg-slate-500',
41+
},
42+
3: {
43+
border: 'border-orange-300 dark:border-orange-500',
44+
bg: 'bg-orange-300/20 dark:bg-orange-500/10',
45+
text: 'text-orange-600 dark:text-orange-400',
46+
badge: 'bg-orange-400 dark:bg-orange-500',
47+
ring: 'border-orange-300 dark:border-orange-500',
48+
barTop: 'bg-orange-300 dark:bg-orange-500',
49+
},
50+
};
51+
52+
const style = rankStyles[rank as 1 | 2 | 3] || rankStyles[2];
2453

2554
return (
26-
<div key={user.id} className="relative flex flex-col items-center justify-end w-1/3 h-full">
27-
28-
<motion.div
55+
<div
56+
key={user.id}
57+
className="relative flex flex-col items-center justify-end w-1/3 h-full"
58+
>
59+
<motion.div
2960
initial={{ opacity: 0, y: 20 }}
3061
animate={{ opacity: 1, y: 0 }}
3162
transition={{ delay: delay + 0.5, duration: 0.5 }}
32-
className="mb-4 flex flex-col items-center text-center z-10"
63+
className="mb-3 md:mb-4 flex flex-col items-center text-center z-10"
3364
>
3465
<div className="relative mb-2">
3566
{isFirst && (
36-
<Crown
37-
className="absolute -top-8 left-1/2 -translate-x-1/2 w-6 h-6 text-[var(--accent-primary)] animate-bounce"
67+
<Crown
68+
className="absolute -top-6 md:-top-8 left-1/2 -translate-x-1/2 w-5 h-5 md:w-6 md:h-6 text-yellow-500 animate-bounce"
3869
fill="currentColor"
3970
/>
4071
)}
41-
<div className={cn(
42-
"relative w-16 h-16 md:w-20 md:h-20 rounded-full p-1 transition-colors duration-300",
43-
"border-2",
44-
isFirst
45-
? "border-[var(--accent-primary)]"
46-
: "border-gray-200 dark:border-white/20"
47-
)}>
72+
73+
<div
74+
className={cn(
75+
'relative w-14 h-14 md:w-20 md:h-20 rounded-full p-1 transition-colors duration-300 border-2',
76+
style.ring
77+
)}
78+
>
4879
<div className="relative w-full h-full rounded-full overflow-hidden bg-gray-100 dark:bg-black">
4980
<Image
5081
src={user.avatar}
@@ -53,56 +84,58 @@ export function LeaderboardPodium({ topThree }: { topThree: User[] }) {
5384
className="object-cover"
5485
/>
5586
</div>
56-
<div className={cn(
57-
"absolute -bottom-2 left-1/2 -translate-x-1/2 w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold text-white shadow-md transition-colors duration-300",
58-
isFirst
59-
? "bg-[var(--accent-primary)]"
60-
: "bg-gray-500 dark:bg-gray-700"
61-
)}>
87+
88+
<div
89+
className={cn(
90+
'absolute -bottom-2 left-1/2 -translate-x-1/2 w-5 h-5 md:w-6 md:h-6 rounded-full flex items-center justify-center text-[10px] md:text-xs font-bold text-white shadow-sm transition-colors duration-300',
91+
style.badge
92+
)}
93+
>
6294
{user.rank}
6395
</div>
6496
</div>
6597
</div>
66-
67-
<div className="font-bold text-gray-900 dark:text-white text-sm md:text-base truncate max-w-[100px] md:max-w-[140px]">
98+
99+
<div className="font-bold text-gray-900 dark:text-white text-xs md:text-base truncate max-w-[90px] md:max-w-[140px]">
68100
{user.username}
69101
</div>
70-
<div className="font-mono text-xs font-bold text-[var(--accent-primary)]">
71-
{user.points}
102+
103+
<div
104+
className={cn(
105+
'font-mono text-[10px] md:text-xs font-bold mt-0.5',
106+
style.text
107+
)}
108+
>
109+
{user.points}
72110
</div>
73111
</motion.div>
74112

75113
<motion.div
76114
initial={{ height: 0 }}
77115
animate={{ height: height }}
78-
transition={{
79-
duration: 0.8,
80-
delay: delay,
81-
type: "spring",
116+
transition={{
117+
duration: 0.8,
118+
delay: delay,
119+
type: 'spring',
82120
stiffness: 60,
83-
damping: 15
121+
damping: 15,
84122
}}
85123
className={cn(
86-
"w-full rounded-t-2xl relative overflow-hidden backdrop-blur-xl border-x border-t transition-colors duration-300",
87-
"bg-white/60 border-gray-100 dark:bg-[#111]/60 dark:border-white/5",
88-
89-
isFirst
90-
? "shadow-[0_0_50px_-15px_var(--accent-primary)]"
91-
: "shadow-[0_-10px_40px_-15px_rgba(0,0,0,0.1)] dark:shadow-[0_-10px_40px_-15px_rgba(0,0,0,0.5)]"
124+
'w-full rounded-t-xl md:rounded-t-2xl relative overflow-hidden backdrop-blur-md border-x border-t transition-colors duration-300',
125+
style.bg,
126+
style.border
92127
)}
93128
>
94-
<div className={cn(
95-
"w-full h-1.5 absolute top-0 left-0 transition-colors duration-300",
96-
isFirst
97-
? "bg-gradient-to-r from-[var(--accent-primary)] to-[var(--accent-hover)]"
98-
: "bg-gray-200 dark:bg-white/10"
99-
)} />
100-
101-
129+
<div
130+
className={cn(
131+
'w-full h-1 md:h-1.5 absolute top-0 left-0 opacity-80',
132+
style.barTop
133+
)}
134+
/>
102135
</motion.div>
103136
</div>
104137
);
105138
})}
106139
</div>
107140
);
108-
}
141+
}

0 commit comments

Comments
 (0)