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

146 lines
5.0 KiB
TypeScript

import React from 'react';
import { Trophy, Crown, Users } from 'lucide-react';
import type { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';
import { getMediaUrl } from '@/lib/utilities/media';
import { Box } from './Box';
import { Stack } from './Stack';
import { Text } from './Text';
import { Icon } from './Icon';
import { Button } from './Button';
import { Image } from './Image';
import { Podium, PodiumItem } from './Podium';
interface TeamPodiumProps {
teams: TeamSummaryViewModel[];
onClick: (id: string) => void;
}
export function TeamPodium({ teams, onClick }: TeamPodiumProps) {
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 = ['28', '36', '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 getBgColor = (position: number) => {
switch (position) {
case 1:
return 'bg-gradient-to-br from-primary-blue/20 via-iron-gray/80 to-deep-graphite';
case 2:
return 'bg-iron-gray';
case 3:
return 'bg-gradient-to-br from-purple-600/20 via-iron-gray/80 to-deep-graphite';
default:
return 'bg-iron-gray/50';
}
};
return (
<Podium title="Top 3 Teams">
{podiumOrder.map((team, index) => {
const position = podiumPositions[index] ?? 0;
return (
<PodiumItem
key={team.id}
position={position}
height={podiumHeights[index] || '20'}
bgColor={getBgColor(position)}
positionColor={getPositionColor(position)}
cardContent={
<Button
variant="ghost"
onClick={() => onClick(team.id)}
h="auto"
mb={4}
p={0}
className="transition-all"
>
<Box
bg={getBgColor(position)}
rounded="xl"
border={true}
borderColor="border-charcoal-outline"
p={4}
position="relative"
>
{/* Crown for 1st place */}
{position === 1 && (
<Box position="absolute" top="-4" left="1/2" translateX="-1/2">
<Box position="relative">
<Box animate="pulse">
<Icon icon={Crown} size={8} color="text-warning-amber" />
</Box>
<Box position="absolute" inset="0" bg="bg-yellow-400" bgOpacity={0.3} blur="md" rounded="full" />
</Box>
</Box>
)}
{/* Team logo */}
<Box h="20" w="20" display="flex" center rounded="xl" bg="bg-deep-graphite" border={true} borderColor="border-charcoal-outline" overflow="hidden" mb={3}>
<Image
src={team.logoUrl || getMediaUrl('team-logo', team.id)}
alt={team.name}
width={80}
height={80}
objectFit="cover"
/>
</Box>
{/* Team name */}
<Text weight="bold" size="sm" color="text-white" align="center" block truncate maxWidth="28">
{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" color={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>
</Box>
</Button>
}
/>
);
})}
</Podium>
);
}