161 lines
5.7 KiB
TypeScript
161 lines
5.7 KiB
TypeScript
import Image from 'next/image';
|
|
import { Trophy, Crown, Users } from 'lucide-react';
|
|
import type { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';
|
|
import { getMediaUrl } from '@/lib/utilities/media';
|
|
import { Box } from '@/ui/Box';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Text } from '@/ui/Text';
|
|
import { Heading } from '@/ui/Heading';
|
|
import { Icon } from '@/ui/Icon';
|
|
import { Surface } from '@/ui/Surface';
|
|
import { Button } from '@/ui/Button';
|
|
|
|
interface TopThreePodiumProps {
|
|
teams: TeamSummaryViewModel[];
|
|
onClick: (id: string) => void;
|
|
}
|
|
|
|
export function TopThreePodium({ teams, onClick }: TopThreePodiumProps) {
|
|
const top3 = teams.slice(0, 3) as [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel];
|
|
if (teams.length < 3) return null;
|
|
|
|
// Display order: 2nd, 1st, 3rd
|
|
const podiumOrder: [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel] = [
|
|
top3[1],
|
|
top3[0],
|
|
top3[2],
|
|
];
|
|
const podiumHeights = ['h-28', 'h-36', 'h-20'];
|
|
const podiumPositions = [2, 1, 3];
|
|
|
|
const getPositionColor = (position: number) => {
|
|
switch (position) {
|
|
case 1:
|
|
return 'text-yellow-400';
|
|
case 2:
|
|
return 'text-gray-300';
|
|
case 3:
|
|
return 'text-amber-600';
|
|
default:
|
|
return 'text-gray-500';
|
|
}
|
|
};
|
|
|
|
const getVariant = (position: number): any => {
|
|
switch (position) {
|
|
case 1:
|
|
return 'gradient-gold';
|
|
case 2:
|
|
return 'default';
|
|
case 3:
|
|
return 'gradient-purple';
|
|
default:
|
|
return 'muted';
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Surface variant="muted" rounded="2xl" border padding={8} mb={10}>
|
|
<Box display="flex" center mb={8}>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={Trophy} size={6} color="text-yellow-400" />
|
|
<Heading level={2}>Top 3 Teams</Heading>
|
|
</Stack>
|
|
</Box>
|
|
|
|
<Stack direction="row" align="end" justify="center" gap={8}>
|
|
{podiumOrder.map((team, index) => {
|
|
const position = podiumPositions[index] ?? 0;
|
|
|
|
return (
|
|
<Stack key={team.id} align="center">
|
|
{/* Team card */}
|
|
<Button
|
|
variant="ghost"
|
|
onClick={() => onClick(team.id)}
|
|
className="p-0 h-auto hover:scale-105 transition-transform"
|
|
>
|
|
<Surface
|
|
variant={getVariant(position)}
|
|
rounded="xl"
|
|
border
|
|
padding={4}
|
|
position="relative"
|
|
mb={4}
|
|
>
|
|
{/* Crown for 1st place */}
|
|
{position === 1 && (
|
|
<Box position="absolute" top="-4" left="50%" style={{ transform: 'translateX(-50%)' }}>
|
|
<Box position="relative">
|
|
<Icon icon={Crown} size={8} color="text-yellow-400" className="animate-pulse" />
|
|
<Box position="absolute" inset="0" backgroundColor="yellow-400" opacity={0.3} className="blur-md rounded-full" />
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Team logo */}
|
|
<Box height={20} width={20} display="flex" center rounded="xl" backgroundColor="charcoal-outline" border borderColor="charcoal-outline" className="overflow-hidden" mb={3}>
|
|
<Image
|
|
src={team.logoUrl || getMediaUrl('team-logo', team.id)}
|
|
alt={team.name}
|
|
width={80}
|
|
height={80}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</Box>
|
|
|
|
{/* Team name */}
|
|
<Text weight="bold" size="sm" color="text-white" align="center" block className="max-w-[120px] truncate group-hover:text-primary-blue transition-colors">
|
|
{team.name}
|
|
</Text>
|
|
|
|
{/* Category */}
|
|
{team.category && (
|
|
<Text size="xs" color="text-primary-blue" align="center" block mt={1}>
|
|
{team.category}
|
|
</Text>
|
|
)}
|
|
|
|
{/* Rating placeholder */}
|
|
<Text size="xl" weight="bold" className={`${getPositionColor(position)}`} align="center" block mt={1}>
|
|
—
|
|
</Text>
|
|
|
|
{/* Stats row */}
|
|
<Stack direction="row" align="center" justify="center" gap={3} mt={2}>
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Icon icon={Trophy} size={3} color="text-performance-green" />
|
|
<Text size="xs" color="text-gray-400">{team.totalWins}</Text>
|
|
</Stack>
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Icon icon={Users} size={3} color="text-primary-blue" />
|
|
<Text size="xs" color="text-gray-400">{team.memberCount}</Text>
|
|
</Stack>
|
|
</Stack>
|
|
</Surface>
|
|
</Button>
|
|
|
|
{/* Podium stand */}
|
|
<Surface
|
|
variant={getVariant(position)}
|
|
rounded="none"
|
|
className={`rounded-t-lg ${podiumHeights[index]}`}
|
|
border
|
|
width="28"
|
|
display="flex"
|
|
padding={3}
|
|
>
|
|
<Box display="flex" center fullWidth>
|
|
<Text size="3xl" weight="bold" className={getPositionColor(position)}>
|
|
{position}
|
|
</Text>
|
|
</Box>
|
|
</Surface>
|
|
</Stack>
|
|
);
|
|
})}
|
|
</Stack>
|
|
</Surface>
|
|
);
|
|
}
|