144 lines
4.1 KiB
TypeScript
144 lines
4.1 KiB
TypeScript
|
|
|
|
import { ArrowRight, Car, ChevronRight, LucideIcon, Trophy, Zap } from 'lucide-react';
|
|
import { Badge } from './Badge';
|
|
import { Box } from './Box';
|
|
import { Heading } from './Heading';
|
|
import { Icon } from './Icon';
|
|
import { Link } from './Link';
|
|
import { Stack } from './Stack';
|
|
import { Text } from './Text';
|
|
|
|
interface RaceListItemProps {
|
|
track: string;
|
|
car: string;
|
|
timeLabel?: string;
|
|
relativeTimeLabel?: string;
|
|
dateLabel?: string;
|
|
dayLabel?: string;
|
|
status: string;
|
|
leagueName?: string | null;
|
|
leagueHref?: string;
|
|
strengthOfField?: number | null;
|
|
onClick: () => void;
|
|
statusConfig: {
|
|
icon: LucideIcon;
|
|
variant: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
|
|
label: string;
|
|
};
|
|
}
|
|
|
|
export function RaceListItem({
|
|
track,
|
|
car,
|
|
timeLabel,
|
|
relativeTimeLabel,
|
|
dateLabel,
|
|
dayLabel,
|
|
status,
|
|
leagueName,
|
|
leagueHref,
|
|
strengthOfField,
|
|
onClick,
|
|
statusConfig,
|
|
}: RaceListItemProps) {
|
|
const StatusIcon = statusConfig.icon;
|
|
|
|
return (
|
|
<Box
|
|
onClick={onClick}
|
|
position="relative"
|
|
overflow="hidden"
|
|
rounded="xl"
|
|
bg="bg-iron-gray"
|
|
border
|
|
borderColor="border-charcoal-outline"
|
|
p={4}
|
|
cursor="pointer"
|
|
transition
|
|
hoverScale
|
|
group
|
|
>
|
|
{/* Live indicator */}
|
|
{status === 'running' && (
|
|
<Box
|
|
position="absolute"
|
|
top="0"
|
|
left="0"
|
|
right="0"
|
|
h="1"
|
|
style={{ background: 'linear-gradient(to right, #10b981, rgba(16, 185, 129, 0.5), #10b981)' }}
|
|
/>
|
|
)}
|
|
|
|
<Stack direction="row" align="center" gap={4}>
|
|
{/* Time/Date Column */}
|
|
<Box flexShrink={0} textAlign="center" minWidth="60px">
|
|
{dateLabel && (
|
|
<Text size="xs" color="text-gray-500" block style={{ textTransform: 'uppercase' }}>
|
|
{dateLabel}
|
|
</Text>
|
|
)}
|
|
<Text size={dayLabel ? "2xl" : "lg"} weight="bold" color="text-white" block>
|
|
{dayLabel || timeLabel}
|
|
</Text>
|
|
<Text size="xs" color={status === 'running' ? 'text-performance-green' : 'text-gray-400'} block>
|
|
{status === 'running' ? 'LIVE' : relativeTimeLabel || timeLabel}
|
|
</Text>
|
|
</Box>
|
|
|
|
{/* Divider */}
|
|
<Box w="px" h="10" alignSelf="stretch" bg="bg-charcoal-outline" />
|
|
|
|
{/* Main Content */}
|
|
<Box flexGrow={1} minWidth="0">
|
|
<Stack direction="row" align="start" justify="between" gap={4}>
|
|
<Box minWidth="0">
|
|
<Heading level={3} truncate>
|
|
{track}
|
|
</Heading>
|
|
<Stack direction="row" align="center" gap={3} mt={1}>
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Icon icon={Car} size={3.5} color="rgb(156, 163, 175)" />
|
|
<Text size="sm" color="text-gray-400">{car}</Text>
|
|
</Stack>
|
|
{strengthOfField && (
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Icon icon={Zap} size={3.5} color="rgb(245, 158, 11)" />
|
|
<Text size="sm" color="text-gray-400">SOF {strengthOfField}</Text>
|
|
</Stack>
|
|
)}
|
|
</Stack>
|
|
</Box>
|
|
|
|
{/* Status Badge */}
|
|
<Badge variant={statusConfig.variant}>
|
|
<Icon icon={StatusIcon} size={3.5} />
|
|
{statusConfig.label}
|
|
</Badge>
|
|
</Stack>
|
|
|
|
{/* League Link */}
|
|
{leagueName && leagueHref && (
|
|
<Box mt={3} pt={3} borderTop borderColor="border-charcoal-outline" bgOpacity={0.5}>
|
|
<Link
|
|
href={leagueHref}
|
|
onClick={(e) => e.stopPropagation()}
|
|
variant="primary"
|
|
size="sm"
|
|
>
|
|
<Icon icon={Trophy} size={3.5} mr={2} />
|
|
{leagueName}
|
|
<Icon icon={ArrowRight} size={3} ml={2} />
|
|
</Link>
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
|
|
{/* Arrow */}
|
|
<Icon icon={ChevronRight} size={5} color="rgb(115, 115, 115)" flexShrink={0} />
|
|
</Stack>
|
|
</Box>
|
|
);
|
|
}
|