website refactor
This commit is contained in:
179
apps/website/components/races/RaceList.tsx
Normal file
179
apps/website/components/races/RaceList.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import React from 'react';
|
||||
import { Calendar, Clock, PlayCircle, CheckCircle2, XCircle, Car, Zap, Trophy, ArrowRight, ChevronRight } from 'lucide-react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Link } from '@/ui/Link';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Badge } from '@/ui/Badge';
|
||||
import type { RaceViewData } from '@/lib/view-data/RacesViewData';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
|
||||
interface RaceListProps {
|
||||
racesByDate: Array<{
|
||||
dateKey: string;
|
||||
dateLabel: string;
|
||||
races: RaceViewData[];
|
||||
}>;
|
||||
totalCount: number;
|
||||
onRaceClick: (raceId: string) => void;
|
||||
}
|
||||
|
||||
export function RaceList({ racesByDate, totalCount, onRaceClick }: RaceListProps) {
|
||||
const statusConfig = {
|
||||
scheduled: {
|
||||
icon: Clock,
|
||||
variant: 'primary' as const,
|
||||
label: 'Scheduled',
|
||||
},
|
||||
running: {
|
||||
icon: PlayCircle,
|
||||
variant: 'success' as const,
|
||||
label: 'LIVE',
|
||||
},
|
||||
completed: {
|
||||
icon: CheckCircle2,
|
||||
variant: 'default' as const,
|
||||
label: 'Completed',
|
||||
},
|
||||
cancelled: {
|
||||
icon: XCircle,
|
||||
variant: 'warning' as const,
|
||||
label: 'Cancelled',
|
||||
},
|
||||
};
|
||||
|
||||
if (racesByDate.length === 0) {
|
||||
return (
|
||||
<Card style={{ textAlign: 'center', padding: '3rem 0' }}>
|
||||
<Stack align="center" gap={4}>
|
||||
<Box style={{ padding: '1rem', backgroundColor: '#262626', borderRadius: '9999px' }}>
|
||||
<Calendar style={{ width: '2rem', height: '2rem', color: '#737373' }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text weight="medium" color="text-white" style={{ marginBottom: '0.25rem' }}>No races found</Text>
|
||||
<Text size="sm" color="text-gray-500">
|
||||
{totalCount === 0
|
||||
? 'No races have been scheduled yet'
|
||||
: 'Try adjusting your filters'}
|
||||
</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap={4}>
|
||||
{racesByDate.map((group) => (
|
||||
<Stack key={group.dateKey} gap={3}>
|
||||
{/* Date Header */}
|
||||
<Stack direction="row" align="center" gap={3} style={{ padding: '0 0.5rem' }}>
|
||||
<Box style={{ padding: '0.5rem', backgroundColor: 'rgba(59, 130, 246, 0.1)', borderRadius: '0.5rem' }}>
|
||||
<Calendar style={{ width: '1rem', height: '1rem', color: '#3b82f6' }} />
|
||||
</Box>
|
||||
<Text weight="semibold" size="sm" color="text-white">
|
||||
{group.dateLabel}
|
||||
</Text>
|
||||
<Text size="xs" color="text-gray-500">
|
||||
{group.races.length} race{group.races.length !== 1 ? 's' : ''}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
{/* Races for this date */}
|
||||
<Stack gap={2}>
|
||||
{group.races.map((race) => {
|
||||
const config = statusConfig[race.status as keyof typeof statusConfig] || statusConfig.scheduled;
|
||||
const StatusIcon = config.icon;
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={race.id}
|
||||
onClick={() => onRaceClick(race.id)}
|
||||
style={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
borderRadius: '0.75rem',
|
||||
backgroundColor: '#262626',
|
||||
border: '1px solid rgba(38, 38, 38, 1)',
|
||||
padding: '1rem',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
{/* Live indicator */}
|
||||
{race.status === 'running' && (
|
||||
<Box style={{ position: 'absolute', top: 0, left: 0, right: 0, height: '0.25rem', background: 'linear-gradient(to right, #10b981, rgba(16, 185, 129, 0.5), #10b981)' }} />
|
||||
)}
|
||||
|
||||
<Stack direction="row" align="start" gap={4}>
|
||||
{/* Time Column */}
|
||||
<Box style={{ flexShrink: 0, textAlign: 'center', minWidth: '60px' }}>
|
||||
<Text size="lg" weight="bold" color="text-white">
|
||||
{race.timeLabel}
|
||||
</Text>
|
||||
<Text size="xs" style={{ color: race.status === 'running' ? '#10b981' : '#9ca3af' }}>
|
||||
{race.status === 'running'
|
||||
? 'LIVE'
|
||||
: race.relativeTimeLabel}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Divider */}
|
||||
<Box style={{ width: '1px', alignSelf: 'stretch', backgroundColor: 'rgba(38, 38, 38, 1)' }} />
|
||||
|
||||
{/* Main Content */}
|
||||
<Box style={{ flex: 1, minWidth: 0 }}>
|
||||
<Stack direction="row" align="start" justify="between" gap={4}>
|
||||
<Box style={{ minWidth: 0 }}>
|
||||
<Heading level={3} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{race.track}
|
||||
</Heading>
|
||||
<Stack direction="row" align="center" gap={3} style={{ marginTop: '0.25rem' }}>
|
||||
<Stack direction="row" align="center" gap={1}>
|
||||
<Car style={{ width: '0.875rem', height: '0.875rem', color: '#9ca3af' }} />
|
||||
<Text size="sm" color="text-gray-400">{race.car}</Text>
|
||||
</Stack>
|
||||
{race.strengthOfField && (
|
||||
<Stack direction="row" align="center" gap={1}>
|
||||
<Zap style={{ width: '0.875rem', height: '0.875rem', color: '#f59e0b' }} />
|
||||
<Text size="sm" color="text-gray-400">SOF {race.strengthOfField}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
{/* Status Badge */}
|
||||
<Badge variant={config.variant}>
|
||||
<StatusIcon style={{ width: '0.875rem', height: '0.875rem' }} />
|
||||
{config.label}
|
||||
</Badge>
|
||||
</Stack>
|
||||
|
||||
{/* League Link */}
|
||||
<Box style={{ marginTop: '0.75rem', paddingTop: '0.75rem', borderTop: '1px solid rgba(38, 38, 38, 0.5)' }}>
|
||||
<Link
|
||||
href={routes.league.detail(race.leagueId ?? '')}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
variant="primary"
|
||||
style={{ fontSize: '0.875rem' }}
|
||||
>
|
||||
<Trophy style={{ width: '0.875rem', height: '0.875rem', marginRight: '0.5rem' }} />
|
||||
{race.leagueName}
|
||||
<ArrowRight style={{ width: '0.75rem', height: '0.75rem', marginLeft: '0.5rem' }} />
|
||||
</Link>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Arrow */}
|
||||
<ChevronRight style={{ width: '1.25rem', height: '1.25rem', color: '#737373', flexShrink: 0 }} />
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user