33import { useRef } from 'react' ;
44import { motion , useMotionTemplate , useMotionValue } from 'framer-motion' ;
55import { useTranslations } from 'next-intl' ;
6+ import { cn } from '@/lib/utils' ;
67import { LeaderboardPodium } from './LeaderboardPodium' ;
78import { LeaderboardTable } from './LeaderboardTable' ;
8- import { User } from './types' ;
9+ import { User , CurrentUser } from './types' ;
910
10- // Імпортуємо тип з auth
11- type AuthUser = { id : string ; username : string ; email : string } ;
1211
1312interface LeaderboardClientProps {
1413 initialUsers : User [ ] ;
15- currentUser ?: AuthUser | null ;
14+ currentUser ?: CurrentUser | null ;
1615}
1716
1817export default function LeaderboardClient ( {
@@ -21,13 +20,10 @@ export default function LeaderboardClient({
2120} : LeaderboardClientProps ) {
2221 const t = useTranslations ( 'leaderboard' ) ;
2322
24- // Використовуємо всіх користувачів для таблиці
2523 const allUsers = initialUsers ;
26- // Подіум тільки для тих, хто має бали
2724 const topThree = allUsers . filter ( u => u . points > 0 ) . slice ( 0 , 3 ) ;
2825 const hasResults = topThree . length > 0 ;
2926
30- // --- Логіка ефекту ліхтарика ---
3127 const containerRef = useRef < HTMLDivElement > ( null ) ;
3228 const mouseX = useMotionValue ( 0 ) ;
3329 const mouseY = useMotionValue ( 0 ) ;
@@ -37,9 +33,8 @@ export default function LeaderboardClient({
3733 clientX,
3834 clientY,
3935 } : React . MouseEvent ) {
40- const { left, top } = currentTarget . getBoundingClientRect ( ) ;
41- mouseX . set ( clientX - left ) ;
42- mouseY . set ( clientY - top ) ;
36+ mouseX . set ( clientX ) ;
37+ mouseY . set ( clientY ) ;
4338 }
4439
4540 const maskImage = useMotionTemplate `radial-gradient(500px circle at ${ mouseX } px ${ mouseY } px, black, transparent)` ;
@@ -48,41 +43,37 @@ export default function LeaderboardClient({
4843 < div
4944 ref = { containerRef }
5045 onMouseMove = { handleMouseMove }
51- className = "relative min-h-screen overflow-hidden bg-slate-50 dark:bg-slate-950 group transition-colors duration-300"
46+ className = "relative min-h-screen bg-slate-50 dark:bg-slate-950 group transition-colors duration-300"
5247 >
53- { /* Background Layers - КОНТУРНІ СЕРДЕЧКА 💖 */ }
54-
55- { /* 1. Статичний шар (сірі контури, ледь помітні) */ }
5648 < div
57- className = "absolute inset-0 z-0 bg-repeat [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,#000_70%,transparent_100%)] "
49+ className = "fixed inset-0 z-0 bg-repeat opacity-60 pointer-events-none "
5850 style = { {
59- // stroke='%23808080' - це сірий колір обводки
60- // fill='none' - прозорий центр
61- backgroundImage : `url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z' stroke='%23808080' stroke-width='1.5' stroke-opacity='0.15' fill='none'/%3E%3C/svg%3E")` ,
51+ backgroundImage : `url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z' stroke='%23808080' stroke-width='0.2' stroke-opacity='0.2' fill='none'/%3E%3C/svg%3E")` ,
6252 backgroundSize : '40px 40px' ,
6353 } }
6454 />
6555
66- { /* 2. Динамічний шар (МАЖЕНТО контури, світяться під мишкою) */ }
6756 < motion . div
68- className = "absolute inset-0 z-0 bg-repeat"
57+ className = "fixed inset-0 z-0 bg-repeat pointer-events-none "
6958 style = { {
7059 maskImage,
71- WebkitMaskImage : maskImage ,
72- // stroke='%23ff2d55' - це твій маженто колір обводки
73- backgroundImage : `url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z' stroke='%23ff2d55' stroke-width='2' stroke-opacity='0.5' fill='none'/%3E%3C/svg%3E")` ,
60+ backgroundImage : `url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z' stroke='%23ff2d55' stroke-width='0.9' stroke-opacity='0.8' fill='none'/%3E%3C/svg%3E")` ,
7461 backgroundSize : '40px 40px' ,
7562 } }
7663 />
7764
78- { /* Велика розмита пляма по центру */ }
79- < div className = "absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[500px] bg-[#ff2d55]/15 blur-[120px] rounded-full pointer-events-none" />
65+ < div className = "fixed top-0 left-1/2 -translate-x-1/2 w-[800px] h-[500px] bg-[#ff2d55]/10 blur-[120px] rounded-full pointer-events-none z-0" />
8066
8167 < div className = "relative max-w-5xl mx-auto px-4 py-20 flex flex-col items-center z-10" >
8268 < header className = "text-center mb-16 animate-in fade-in slide-in-from-top-4 duration-700" >
83- < h1 className = "text-5xl md:text-7xl font-bold tracking-tight text-[#ff2d55] mb-6 drop-shadow-sm" >
69+ < h1 className = { cn (
70+ "text-6xl md:text-8xl mb-6 uppercase select-none font-black tracking-tight" ,
71+ "text-[#ff2d55]" ,
72+ "drop-shadow-[0_0_25px_rgba(255,45,85,0.4)]"
73+ ) } >
8474 { t ( 'title' ) }
8575 </ h1 >
76+
8677 < p className = "text-slate-600 dark:text-slate-400 text-lg md:text-xl max-w-2xl mx-auto leading-relaxed font-medium" >
8778 { t ( 'subtitle' ) }
8879 </ p >
@@ -112,4 +103,4 @@ export default function LeaderboardClient({
112103 </ div >
113104 </ div >
114105 ) ;
115- }
106+ }
0 commit comments