Files
gridpilot.gg/apps/website/ui/LeaderboardItem.tsx
2026-01-15 17:12:24 +01:00

117 lines
3.4 KiB
TypeScript

import React from 'react';
import Image from 'next/image';
import { Crown, Flag } from 'lucide-react';
import { Box } from './Box';
import { Text } from './Text';
import { Stack } from './Stack';
import { mediaConfig } from '@/lib/config/mediaConfig';
interface LeaderboardItemProps {
position: number;
name: string;
avatarUrl?: string;
nationality: string;
rating: number;
wins: number;
skillLevelLabel?: string;
skillLevelColor?: string;
categoryLabel?: string;
categoryColor?: string;
onClick: () => void;
}
export function LeaderboardItem({
position,
name,
avatarUrl,
nationality,
rating,
wins,
skillLevelLabel,
skillLevelColor,
categoryLabel,
categoryColor,
onClick,
}: LeaderboardItemProps) {
const getMedalColor = (pos: number) => {
switch (pos) {
case 1: return 'text-yellow-400';
case 2: return 'text-gray-300';
case 3: return 'text-amber-600';
default: return 'text-gray-500';
}
};
const getMedalBg = (pos: number) => {
switch (pos) {
case 1: return 'bg-yellow-400/10 border-yellow-400/30';
case 2: return 'bg-gray-300/10 border-gray-300/30';
case 3: return 'bg-amber-600/10 border-amber-600/30';
default: return 'bg-iron-gray/50 border-charcoal-outline';
}
};
return (
<Box
as="button"
type="button"
onClick={onClick}
display="flex"
alignItems="center"
gap={4}
px={4}
py={3}
fullWidth
textAlign="left"
className="hover:bg-iron-gray/30 transition-colors group"
>
{/* Position */}
<Box
width="8"
height="8"
display="flex"
center
rounded="full"
border
className={`${getMedalBg(position)} ${getMedalColor(position)} text-xs font-bold`}
>
{position <= 3 ? <Crown className="w-3.5 h-3.5" /> : position}
</Box>
{/* Avatar */}
<Box position="relative" width="9" height="9" rounded="full" overflow="hidden" border={true} borderColor="border-charcoal-outline">
<Image src={avatarUrl || mediaConfig.avatars.defaultFallback} alt={name} fill className="object-cover" />
</Box>
{/* Info */}
<Box flexGrow={1} minWidth="0">
<Text weight="medium" color="text-white" truncate block className="group-hover:text-primary-blue transition-colors">
{name}
</Text>
<Stack direction="row" align="center" gap={2}>
<Flag className="w-3 h-3 text-gray-500" />
<Text size="xs" color="text-gray-500">{nationality}</Text>
{categoryLabel && (
<Text size="xs" className={categoryColor}>{categoryLabel}</Text>
)}
{skillLevelLabel && (
<Text size="xs" className={skillLevelColor}>{skillLevelLabel}</Text>
)}
</Stack>
</Box>
{/* Stats */}
<Stack direction="row" align="center" gap={4}>
<Box textAlign="center">
<Text color="text-primary-blue" weight="semibold" font="mono" block>{rating.toLocaleString()}</Text>
<Text size="xs" color="text-gray-500" block style={{ fontSize: '10px' }}>Rating</Text>
</Box>
<Box textAlign="center">
<Text color="text-performance-green" weight="semibold" font="mono" block>{wins}</Text>
<Text size="xs" color="text-gray-500" block style={{ fontSize: '10px' }}>Wins</Text>
</Box>
</Stack>
</Box>
);
}