wip
This commit is contained in:
@@ -2,50 +2,20 @@ 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';
|
||||
|
||||
const SKILL_LEVELS: {
|
||||
id: string;
|
||||
icon: React.ElementType;
|
||||
color: string;
|
||||
bgColor: string;
|
||||
borderColor: string;
|
||||
}[] = [
|
||||
{
|
||||
id: 'pro',
|
||||
icon: () => null,
|
||||
color: 'text-yellow-400',
|
||||
bgColor: 'bg-yellow-400/10',
|
||||
borderColor: 'border-yellow-400/30',
|
||||
},
|
||||
{
|
||||
id: 'advanced',
|
||||
icon: () => null,
|
||||
color: 'text-purple-400',
|
||||
bgColor: 'bg-purple-400/10',
|
||||
borderColor: 'border-purple-400/30',
|
||||
},
|
||||
{
|
||||
id: 'intermediate',
|
||||
icon: () => null,
|
||||
color: 'text-primary-blue',
|
||||
bgColor: 'bg-primary-blue/10',
|
||||
borderColor: 'border-primary-blue/30',
|
||||
},
|
||||
{
|
||||
id: 'beginner',
|
||||
icon: () => null,
|
||||
color: 'text-green-400',
|
||||
bgColor: 'bg-green-400/10',
|
||||
borderColor: 'border-green-400/30',
|
||||
},
|
||||
];
|
||||
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 default function TopThreePodium({ teams, onClick }: TopThreePodiumProps) {
|
||||
export function TopThreePodium({ teams, onClick }: TopThreePodiumProps) {
|
||||
const top3 = teams.slice(0, 3) as [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel];
|
||||
if (teams.length < 3) return null;
|
||||
|
||||
@@ -71,118 +41,120 @@ export default function TopThreePodium({ teams, onClick }: TopThreePodiumProps)
|
||||
}
|
||||
};
|
||||
|
||||
const getGradient = (position: number) => {
|
||||
const getVariant = (position: number): any => {
|
||||
switch (position) {
|
||||
case 1:
|
||||
return 'from-yellow-400/30 via-yellow-500/20 to-yellow-600/10';
|
||||
return 'gradient-gold';
|
||||
case 2:
|
||||
return 'from-gray-300/30 via-gray-400/20 to-gray-500/10';
|
||||
return 'default';
|
||||
case 3:
|
||||
return 'from-amber-500/30 via-amber-600/20 to-amber-700/10';
|
||||
return 'gradient-purple';
|
||||
default:
|
||||
return 'from-gray-600/30 to-gray-700/10';
|
||||
}
|
||||
};
|
||||
|
||||
const getBorderColor = (position: number) => {
|
||||
switch (position) {
|
||||
case 1:
|
||||
return 'border-yellow-400/50';
|
||||
case 2:
|
||||
return 'border-gray-300/50';
|
||||
case 3:
|
||||
return 'border-amber-600/50';
|
||||
default:
|
||||
return 'border-charcoal-outline';
|
||||
return 'muted';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-10 p-8 rounded-2xl bg-gradient-to-br from-iron-gray/60 to-iron-gray/30 border border-charcoal-outline">
|
||||
<div className="flex items-center justify-center gap-2 mb-8">
|
||||
<Trophy className="w-6 h-6 text-yellow-400" />
|
||||
<h2 className="text-xl font-bold text-white">Top 3 Teams</h2>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<div className="flex items-end justify-center gap-4 md:gap-8">
|
||||
<Stack direction="row" align="end" justify="center" gap={8}>
|
||||
{podiumOrder.map((team, index) => {
|
||||
const position = podiumPositions[index] ?? 0;
|
||||
const levelConfig = SKILL_LEVELS.find((l) => l.id === team.performanceLevel);
|
||||
|
||||
return (
|
||||
<button
|
||||
key={team.id}
|
||||
type="button"
|
||||
onClick={() => onClick(team.id)}
|
||||
className="flex flex-col items-center group"
|
||||
>
|
||||
<Stack key={team.id} align="center">
|
||||
{/* Team card */}
|
||||
<div
|
||||
className={`relative mb-4 p-4 rounded-xl bg-gradient-to-br ${getGradient(position ?? 0)} border ${getBorderColor(position ?? 0)} transition-all group-hover:scale-105 group-hover:shadow-lg`}
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => onClick(team.id)}
|
||||
className="p-0 h-auto hover:scale-105 transition-transform"
|
||||
>
|
||||
{/* Crown for 1st place */}
|
||||
{position === 1 && (
|
||||
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
||||
<div className="relative">
|
||||
<Crown className="w-8 h-8 text-yellow-400 animate-pulse" />
|
||||
<div className="absolute inset-0 w-8 h-8 bg-yellow-400/30 blur-md rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<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 */}
|
||||
<div className="flex h-16 w-16 md:h-20 md:w-20 items-center justify-center rounded-xl bg-charcoal-outline border border-charcoal-outline 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"
|
||||
/>
|
||||
</div>
|
||||
{/* 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 */}
|
||||
<p className="text-white font-bold text-sm md:text-base text-center max-w-[120px] truncate group-hover:text-purple-400 transition-colors">
|
||||
{team.name}
|
||||
</p>
|
||||
{/* 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 && (
|
||||
<p className="text-xs text-purple-400 text-center mt-1">
|
||||
{team.category}
|
||||
</p>
|
||||
)}
|
||||
{/* Category */}
|
||||
{team.category && (
|
||||
<Text size="xs" color="text-primary-blue" align="center" block mt={1}>
|
||||
{team.category}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{/* Rating */}
|
||||
<p className={`text-lg md:text-xl font-mono font-bold ${getPositionColor(position)} text-center`}>
|
||||
{'—'}
|
||||
</p>
|
||||
{/* Rating placeholder */}
|
||||
<Text size="xl" weight="bold" className={`${getPositionColor(position)}`} align="center" block mt={1}>
|
||||
—
|
||||
</Text>
|
||||
|
||||
{/* Stats row */}
|
||||
<div className="flex items-center justify-center gap-3 mt-2 text-xs text-gray-400">
|
||||
<span className="flex items-center gap-1">
|
||||
<Trophy className="w-3 h-3 text-performance-green" />
|
||||
{team.totalWins}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Users className="w-3 h-3 text-purple-400" />
|
||||
{team.memberCount}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* 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 */}
|
||||
<div
|
||||
className={`${podiumHeights[index]} w-20 md:w-28 rounded-t-lg bg-gradient-to-t ${getGradient(position)} border-t border-x ${getBorderColor(position)} flex items-start justify-center pt-3`}
|
||||
<Surface
|
||||
variant={getVariant(position)}
|
||||
rounded="none"
|
||||
className={`rounded-t-lg ${podiumHeights[index]}`}
|
||||
border
|
||||
width="28"
|
||||
display="flex"
|
||||
padding={3}
|
||||
>
|
||||
<span className={`text-2xl md:text-3xl font-bold ${getPositionColor(position)}`}>
|
||||
{position}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<Box display="flex" center fullWidth>
|
||||
<Text size="3xl" weight="bold" className={getPositionColor(position)}>
|
||||
{position}
|
||||
</Text>
|
||||
</Box>
|
||||
</Surface>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Stack>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user