184 lines
7.1 KiB
TypeScript
184 lines
7.1 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { Award, ChevronRight, Crown, Trophy, Users } from 'lucide-react';
|
|
import { Button } from '@/ui/Button';
|
|
import { Box } from '@/ui/Box';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Text } from '@/ui/Text';
|
|
import { Heading } from '@/ui/Heading';
|
|
import { Image } from '@/ui/Image';
|
|
import { getMediaUrl } from '@/lib/utilities/media';
|
|
|
|
interface TeamLeaderboardPreviewProps {
|
|
topTeams: Array<{
|
|
id: string;
|
|
name: string;
|
|
logoUrl?: string;
|
|
category?: string;
|
|
memberCount: number;
|
|
totalWins: number;
|
|
isRecruiting: boolean;
|
|
rating?: number;
|
|
performanceLevel: string;
|
|
}>;
|
|
onTeamClick: (id: string) => void;
|
|
onViewFullLeaderboard: () => void;
|
|
}
|
|
|
|
export function TeamLeaderboardPreview({
|
|
topTeams,
|
|
onTeamClick,
|
|
onViewFullLeaderboard
|
|
}: TeamLeaderboardPreviewProps) {
|
|
const getMedalColor = (position: number) => {
|
|
switch (position) {
|
|
case 0: return '#facc15';
|
|
case 1: return '#d1d5db';
|
|
case 2: return '#d97706';
|
|
default: return '#6b7280';
|
|
}
|
|
};
|
|
|
|
const getMedalBg = (position: number) => {
|
|
switch (position) {
|
|
case 0: return 'rgba(250, 204, 21, 0.1)';
|
|
case 1: return 'rgba(209, 213, 219, 0.1)';
|
|
case 2: return 'rgba(217, 119, 6, 0.1)';
|
|
default: return 'rgba(38, 38, 38, 0.5)';
|
|
}
|
|
};
|
|
|
|
const getMedalBorder = (position: number) => {
|
|
switch (position) {
|
|
case 0: return 'rgba(250, 204, 21, 0.3)';
|
|
case 1: return 'rgba(209, 213, 219, 0.3)';
|
|
case 2: return 'rgba(217, 119, 6, 0.3)';
|
|
default: return 'rgba(38, 38, 38, 1)';
|
|
}
|
|
};
|
|
|
|
if (topTeams.length === 0) return null;
|
|
|
|
return (
|
|
<Box style={{ marginBottom: '3rem' }}>
|
|
{/* Header */}
|
|
<Stack direction="row" align="center" justify="between" style={{ marginBottom: '1rem' }}>
|
|
<Stack direction="row" align="center" gap={3}>
|
|
<Box style={{ display: 'flex', height: '2.75rem', width: '2.75rem', alignItems: 'center', justifyContent: 'center', borderRadius: '0.75rem', background: 'linear-gradient(to bottom right, rgba(250, 204, 21, 0.2), rgba(217, 119, 6, 0.1))', border: '1px solid rgba(250, 204, 21, 0.3)' }}>
|
|
<Award style={{ width: '1.25rem', height: '1.25rem', color: '#facc15' }} />
|
|
</Box>
|
|
<Box>
|
|
<Heading level={2}>Top Teams</Heading>
|
|
<Text size="sm" color="text-gray-500">Highest rated racing teams</Text>
|
|
</Box>
|
|
</Stack>
|
|
|
|
<Button
|
|
variant="secondary"
|
|
onClick={onViewFullLeaderboard}
|
|
style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', fontSize: '0.875rem' }}
|
|
>
|
|
View Full Leaderboard
|
|
<ChevronRight style={{ width: '1rem', height: '1rem' }} />
|
|
</Button>
|
|
</Stack>
|
|
|
|
{/* Compact Leaderboard */}
|
|
<Box style={{ borderRadius: '0.75rem', backgroundColor: 'rgba(38, 38, 38, 0.3)', border: '1px solid #262626', overflow: 'hidden' }}>
|
|
<Stack gap={0}>
|
|
{topTeams.map((team, index) => (
|
|
<Box
|
|
key={team.id}
|
|
as="button"
|
|
type="button"
|
|
onClick={() => onTeamClick(team.id)}
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '1rem',
|
|
padding: '0.75rem 1rem',
|
|
width: '100%',
|
|
textAlign: 'left',
|
|
backgroundColor: 'transparent',
|
|
border: 'none',
|
|
cursor: 'pointer',
|
|
borderBottom: index < topTeams.length - 1 ? '1px solid rgba(38, 38, 38, 0.5)' : 'none'
|
|
}}
|
|
>
|
|
{/* Position */}
|
|
<Box
|
|
style={{
|
|
display: 'flex',
|
|
height: '2rem',
|
|
width: '2rem',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
borderRadius: '9999px',
|
|
fontSize: '0.75rem',
|
|
fontWeight: 'bold',
|
|
border: `1px solid ${getMedalBorder(index)}`,
|
|
backgroundColor: getMedalBg(index),
|
|
color: getMedalColor(index)
|
|
}}
|
|
>
|
|
{index < 3 ? (
|
|
<Crown style={{ width: '0.875rem', height: '0.875rem' }} />
|
|
) : (
|
|
index + 1
|
|
)}
|
|
</Box>
|
|
|
|
{/* Team Info */}
|
|
<Box style={{ display: 'flex', height: '2.25rem', width: '2.25rem', alignItems: 'center', justifyContent: 'center', borderRadius: '0.5rem', backgroundColor: '#262626', border: '1px solid #262626', overflow: 'hidden' }}>
|
|
<Image
|
|
src={team.logoUrl || getMediaUrl('team-logo', team.id)}
|
|
alt={team.name}
|
|
width={36}
|
|
height={36}
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
</Box>
|
|
<Box style={{ flex: 1, minWidth: 0 }}>
|
|
<Text weight="medium" color="text-white" style={{ display: 'block', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
{team.name}
|
|
</Text>
|
|
<Stack direction="row" align="center" gap={2} wrap style={{ marginTop: '0.125rem' }}>
|
|
{team.category && (
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Box style={{ width: '0.375rem', height: '0.375rem', borderRadius: '9999px', backgroundColor: '#a855f7' }} />
|
|
<Text size="xs" color="text-purple-400">{team.category}</Text>
|
|
</Stack>
|
|
)}
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Users style={{ width: '0.75rem', height: '0.75rem', color: '#737373' }} />
|
|
<Text size="xs" color="text-gray-500">{team.memberCount}</Text>
|
|
</Stack>
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Trophy style={{ width: '0.75rem', height: '0.75rem', color: '#737373' }} />
|
|
<Text size="xs" color="text-gray-500">{team.totalWins} wins</Text>
|
|
</Stack>
|
|
{team.isRecruiting && (
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Box style={{ width: '0.375rem', height: '0.375rem', borderRadius: '9999px', backgroundColor: '#10b981' }} />
|
|
<Text size="xs" color="text-performance-green">Recruiting</Text>
|
|
</Stack>
|
|
)}
|
|
</Stack>
|
|
</Box>
|
|
|
|
{/* Rating */}
|
|
<Box style={{ textAlign: 'right' }}>
|
|
<Text font="mono" weight="semibold" color="text-purple-400" style={{ display: 'block' }}>
|
|
{typeof team.rating === 'number' ? Math.round(team.rating).toLocaleString() : '—'}
|
|
</Text>
|
|
<Text size="xs" color="text-gray-500">Rating</Text>
|
|
</Box>
|
|
</Box>
|
|
))}
|
|
</Stack>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
}
|