website refactor

This commit is contained in:
2026-01-18 23:24:30 +01:00
parent aeaa43f4d3
commit 182056a57b
487 changed files with 1783 additions and 2170 deletions

View File

@@ -3,8 +3,8 @@ import { Card } from '@/ui/Card';
import { GoalCard } from '@/ui/GoalCard';
import { Heading } from '@/ui/Heading';
import { MilestoneItem } from '@/components/achievements/MilestoneItem';
import { Stack } from '@/ui/primitives/Stack';
import { Grid } from '@/ui/primitives/Grid';
import { Stack } from '@/ui/Stack';
import { Grid } from '@/ui/Grid';
interface Achievement {
id: string;

View File

@@ -1,10 +1,10 @@
import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Grid } from '@/ui/primitives/Grid';
import { Grid } from '@/ui/Grid';
import { StatGridItem } from '@/ui/StatGridItem';
import { TrendingUp } from 'lucide-react';

View File

@@ -3,7 +3,7 @@
import { Button } from '@/ui/Button';
import { InfoBox } from '@/ui/InfoBox';
import { Input } from '@/ui/Input';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { TextArea } from '@/ui/TextArea';
import { AlertCircle } from 'lucide-react';

View File

@@ -1,10 +1,10 @@
import { DriverIdentity } from '@/components/drivers/DriverIdentity';
import { DriverIdentity } from '@/ui/DriverIdentity';
import { DriverStats } from '@/components/drivers/DriverStats';
import { RankBadge } from '@/components/leaderboards/RankBadge';
import { routes } from '@/lib/routing/RouteConfig';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Card } from '@/ui/Card';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
export interface DriverCardProps {
id: string;

View File

@@ -4,7 +4,7 @@ import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Badge } from '@/ui/Badge';
import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Zap } from 'lucide-react';

View File

@@ -1,6 +1,6 @@
import { RatingBadge } from '@/components/drivers/RatingBadge';
import { Image } from '@/ui/Image';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import React from 'react';

View File

@@ -1,8 +1,8 @@
'use client';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
interface DriverPerformanceOverviewProps {
stats: {

View File

@@ -8,7 +8,7 @@ import { useDriverProfile } from "@/hooks/driver/useDriverProfile";
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { StatCard } from '@/ui/StatCard';
import { Text } from '@/ui/Text';
import { ProfileStats } from './ProfileStats';

View File

@@ -4,7 +4,7 @@ import { RatingBadge } from '@/components/drivers/RatingBadge';
import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Check, Globe, Trophy, UserPlus } from 'lucide-react';
import { SafetyRatingBadge } from './SafetyRatingBadge';

View File

@@ -1,7 +1,7 @@
'use client';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
import { BarChart3, LayoutDashboard, ShieldCheck } from 'lucide-react';
export type ProfileTab = 'overview' | 'stats' | 'ratings';

View File

@@ -2,7 +2,7 @@
import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Car, Clock, MailCheck, MapPin, Users2 } from 'lucide-react';
interface DriverRacingProfileProps {

View File

@@ -1,7 +1,7 @@
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text';
import { Star, Trophy } from 'lucide-react';

View File

@@ -1,7 +1,7 @@
'use client';
import { Box } from '@/ui/Box';
import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box';
import { Search } from 'lucide-react';
interface DriverSearchBarProps {

View File

@@ -1,4 +1,4 @@
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface DriverStatsProps {

View File

@@ -1,7 +1,7 @@
'use client';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
interface StatItem {
label: string;

View File

@@ -3,7 +3,7 @@
import { Image } from '@/ui/Image';
import { Link } from '@/ui/Link';
import { PlaceholderImage } from '@/ui/PlaceholderImage';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import React from 'react';

View File

@@ -2,8 +2,11 @@
import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Table, TableHead, TableBody, TableRow, TableHeaderCell } from '@/ui/Table';
import { TrendingUp } from 'lucide-react';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import React from 'react';
interface DriverTableProps {
@@ -14,31 +17,29 @@ export function DriverTable({ children }: DriverTableProps) {
return (
<Stack gap={4}>
<Stack direction="row" align="center" gap={3}>
<Stack display="flex" h="10" w="10" alignItems="center" justifyContent="center" rounded="xl" bg="bg-primary-blue/10" border borderColor="border-primary-blue/20">
<TrendingUp size={20} color="#198CFF" />
</Stack>
<Card variant="dark">
<Icon icon={TrendingUp} size={5} intent="primary" />
</Card>
<Stack>
<Heading level={2}>Driver Rankings</Heading>
<Text size="xs" color="text-gray-500">Top performers by skill rating</Text>
<Text size="xs" variant="low">Top performers by skill rating</Text>
</Stack>
</Stack>
<Stack overflow="hidden" rounded="xl" border borderColor="border-charcoal-outline" bg="bg-deep-charcoal/50">
<Stack as="table" w="full" textAlign="left">
<Stack as="thead">
<Stack as="tr" borderBottom borderColor="border-charcoal-outline" bg="bg-deep-charcoal/80">
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" textAlign="center" width="60px">#</Stack>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500">Driver</Stack>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" width="150px">Nationality</Stack>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" textAlign="right" width="100px">Rating</Stack>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" textAlign="right" width="80px">Wins</Stack>
</Stack>
</Stack>
<Stack as="tbody">
{children}
</Stack>
</Stack>
</Stack>
<Table>
<TableHead>
<TableRow>
<TableHeaderCell textAlign="center" w="60px">#</TableHeaderCell>
<TableHeaderCell>Driver</TableHeaderCell>
<TableHeaderCell w="150px">Nationality</TableHeaderCell>
<TableHeaderCell textAlign="right" w="100px">Rating</TableHeaderCell>
<TableHeaderCell textAlign="right" w="80px">Wins</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
{children}
</TableBody>
</Table>
</Stack>
);
}

View File

@@ -3,7 +3,9 @@
import { RatingBadge } from '@/components/drivers/RatingBadge';
import { Image } from '@/ui/Image';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { TableRow, TableCell } from '@/ui/Table';
import { Avatar } from '@/ui/Avatar';
interface DriverTableRowProps {
rank: number;
@@ -24,61 +26,45 @@ export function DriverTableRow({
wins,
onClick,
}: DriverTableRowProps) {
const defaultAvatar = 'https://cdn.gridpilot.com/avatars/default.png';
return (
<Stack
as="tr"
onClick={onClick}
cursor="pointer"
transition
hoverBg="bg-primary-blue/5"
group
borderBottom
borderColor="border-charcoal-outline/50"
>
<Stack as="td" px={6} py={4} textAlign="center">
<TableRow onClick={onClick} clickable>
<TableCell textAlign="center">
<Text
size="sm"
weight="bold"
font="mono"
color={rank <= 3 ? 'text-warning-amber' : 'text-gray-500'}
variant={rank <= 3 ? 'warning' : 'low'}
>
{rank}
</Text>
</Stack>
<Stack as="td" px={6} py={4}>
</TableCell>
<TableCell>
<Stack direction="row" align="center" gap={3}>
<Stack position="relative" h="8" w="8" overflow="hidden" rounded="full" border borderColor="border-charcoal-outline" bg="bg-deep-charcoal">
<Image
src={avatarUrl || defaultAvatar}
alt={name}
fill
objectFit="cover"
/>
</Stack>
<Avatar
src={avatarUrl || undefined}
alt={name}
size="sm"
/>
<Text
size="sm"
weight="semibold"
color="text-white"
groupHoverTextColor="text-primary-blue"
transition
variant="high"
>
{name}
</Text>
</Stack>
</Stack>
<Stack as="td" px={6} py={4}>
<Text size="xs" color="text-gray-400">{nationality}</Text>
</Stack>
<Stack as="td" px={6} py={4} textAlign="right">
</TableCell>
<TableCell>
<Text size="xs" variant="low">{nationality}</Text>
</TableCell>
<TableCell textAlign="right">
<RatingBadge rating={rating} size="sm" />
</Stack>
<Stack as="td" px={6} py={4} textAlign="right">
<Text size="sm" weight="semibold" font="mono" color="text-performance-green">
</TableCell>
<TableCell textAlign="right">
<Text size="sm" weight="semibold" font="mono" variant="success">
{wins}
</Text>
</Stack>
</Stack>
</TableCell>
</TableRow>
);
}

View File

@@ -2,15 +2,18 @@
import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Section } from '@/ui/Section';
import { Container } from '@/ui/Container';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import { Trophy, Users } from 'lucide-react';
interface DriverStat {
label: string;
value: string | number;
color?: string;
animate?: boolean;
intent?: 'primary' | 'success' | 'warning' | 'telemetry';
}
interface DriversDirectoryHeaderProps {
@@ -29,71 +32,53 @@ export function DriversDirectoryHeader({
onViewLeaderboard,
}: DriversDirectoryHeaderProps) {
const stats: DriverStat[] = [
{ label: 'drivers', value: totalDrivers, color: 'text-primary-blue' },
{ label: 'active', value: activeDrivers, color: 'text-performance-green', animate: true },
{ label: 'total wins', value: totalWins.toLocaleString(), color: 'text-warning-amber' },
{ label: 'races', value: totalRaces.toLocaleString(), color: 'text-neon-aqua' },
{ label: 'drivers', value: totalDrivers, intent: 'primary' },
{ label: 'active', value: activeDrivers, intent: 'success' },
{ label: 'total wins', value: totalWins.toLocaleString(), intent: 'warning' },
{ label: 'races', value: totalRaces.toLocaleString(), intent: 'telemetry' },
];
return (
<Stack
as="header"
position="relative"
overflow="hidden"
rounded="2xl"
border
borderColor="border-charcoal-outline/50"
bg="bg-gradient-to-br from-iron-gray/80 via-deep-graphite to-iron-gray/60"
p={{ base: 8, lg: 10 }}
>
{/* Background Accents */}
<Stack position="absolute" right="-24" top="-24" w="96" h="96" rounded="full" bg="bg-primary-blue/5" blur="3xl" />
<Stack position="absolute" bottom="-16" left="-16" w="64" h="64" rounded="full" bg="bg-neon-aqua/5" blur="3xl" />
<Stack position="relative" display="flex" flexDirection={{ base: 'col', lg: 'row' }} alignItems={{ lg: 'center' }} justifyContent="between" gap={8}>
<Stack maxWidth="2xl">
<Stack direction="row" align="center" gap={3} mb={4}>
<Stack display="flex" h="12" w="12" alignItems="center" justifyContent="center" rounded="xl" border borderColor="border-charcoal-outline" bg="bg-deep-charcoal" shadow="lg">
<Users size={24} color="#198CFF" />
<Section variant="dark" padding="md">
<Container>
<Stack direction="row" align="center" justify="between" gap={8}>
<Stack gap={6}>
<Stack direction="row" align="center" gap={3}>
<Card variant="dark">
<Icon icon={Users} size={6} intent="primary" />
</Card>
<Heading level={1}>Drivers</Heading>
</Stack>
<Heading level={1}>Drivers</Heading>
</Stack>
<Text size="lg" color="text-gray-400" block leading="relaxed">
Meet the racers who make every lap count. From rookies to champions, track their journey and see who&apos;s dominating the grid.
</Text>
<Text size="lg" variant="low">
Meet the racers who make every lap count. From rookies to champions, track their journey and see who&apos;s dominating the grid.
</Text>
<Stack display="flex" flexWrap="wrap" gap={6} mt={6}>
{stats.map((stat, index) => (
<Stack key={index} direction="row" align="center" gap={2}>
<Stack
w="2"
h="2"
rounded="full"
bg={stat.color?.replace('text-', 'bg-') || 'bg-primary-blue'}
animate={stat.animate ? 'pulse' : 'none'}
/>
<Text size="sm" color="text-gray-400">
<Text as="span" weight="semibold" color="text-white">{stat.value}</Text> {stat.label}
</Text>
</Stack>
))}
<Stack direction="row" gap={6} wrap>
{stats.map((stat, index) => (
<Stack key={index} direction="row" align="center" gap={2}>
<Text size="sm" variant="low">
<Text as="span" weight="semibold" variant="high">{stat.value}</Text> {stat.label}
</Text>
</Stack>
))}
</Stack>
</Stack>
<Stack gap={2} align="center">
<Button
variant="primary"
onClick={onViewLeaderboard}
icon={<Icon icon={Trophy} size={5} />}
>
View Leaderboard
</Button>
<Text size="xs" variant="low" align="center">
See full driver rankings
</Text>
</Stack>
</Stack>
<Stack gap={2}>
<Button
variant="primary"
onClick={onViewLeaderboard}
icon={<Trophy size={20} />}
>
View Leaderboard
</Button>
<Text size="xs" color="text-gray-500" align="center" block>
See full driver rankings
</Text>
</Stack>
</Stack>
</Stack>
</Container>
</Section>
);
}

View File

@@ -1,8 +1,8 @@
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon';
import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box';
import { Search } from 'lucide-react';
interface DriversSearchProps {

View File

@@ -3,11 +3,11 @@
import { MedalBadge } from '@/components/leaderboards/MedalBadge';
import { mediaConfig } from '@/lib/config/mediaConfig';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image';
import { MiniStat } from '@/ui/MiniStat';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text';
import { Flag, Shield, Star, TrendingUp } from 'lucide-react';

View File

@@ -3,7 +3,7 @@ import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Car, Download, Edit, Trash2 } from 'lucide-react';

View File

@@ -1,7 +1,7 @@
import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text';
interface PerformanceMetricsProps {

View File

@@ -5,9 +5,9 @@ import { CircularProgress } from '@/ui/CircularProgress';
import { Heading } from '@/ui/Heading';
import { HorizontalBarChart } from '@/ui/HorizontalBarChart';
import { Icon } from '@/ui/Icon';
import { Grid } from '@/ui/primitives/Grid';
import { GridItem } from '@/ui/primitives/GridItem';
import { Stack } from '@/ui/primitives/Stack';
import { Grid } from '@/ui/Grid';
import { GridItem } from '@/ui/GridItem';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Activity, BarChart3, Target, TrendingUp } from 'lucide-react';

View File

@@ -8,7 +8,7 @@ import { CountryFlag } from '@/ui/CountryFlag';
import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image';
import { PlaceholderImage } from '@/ui/PlaceholderImage';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface ProfileHeaderProps {

View File

@@ -6,8 +6,8 @@ import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image';
import { Link } from '@/ui/Link';
import { Stack } from '@/ui/primitives/Stack';
import { Surface } from '@/ui/primitives/Surface';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
import { Calendar, Clock, ExternalLink, Globe, Star, Trophy, UserPlus } from 'lucide-react';

View File

@@ -6,7 +6,7 @@ import { Card } from '@/ui/Card';
import { Checkbox } from '@/ui/Checkbox';
import { Heading } from '@/ui/Heading';
import { Input } from '@/ui/Input';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Select } from '@/ui/Select';
import { TextArea } from '@/ui/TextArea';
import { Toggle } from '@/ui/Toggle';

View File

@@ -4,7 +4,7 @@ import { RankBadge } from '@/components/leaderboards/RankBadge';
import { useDriverProfile } from "@/hooks/driver/useDriverProfile";
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { StatCard } from '@/ui/StatCard';
import { Text } from '@/ui/Text';
import { useMemo } from 'react';

View File

@@ -3,7 +3,7 @@
import { Card, Card as Surface } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Flag, UserPlus, Users } from 'lucide-react';

View File

@@ -3,33 +3,22 @@ import { Badge } from '@/ui/Badge';
interface RatingBadgeProps {
rating: number;
size?: 'sm' | 'md' | 'lg';
className?: string;
size?: 'sm' | 'md';
}
export function RatingBadge({ rating, size = 'md', className = '' }: RatingBadgeProps) {
const getColor = (val: number) => {
if (val >= 2500) return { variant: 'warning' as const };
if (val >= 2000) return { color: 'text-purple-400', bg: 'bg-purple-400/10', borderColor: 'border-purple-400/20' };
if (val >= 1500) return { variant: 'primary' as const };
if (val >= 1000) return { variant: 'success' as const };
return { variant: 'default' as const };
export function RatingBadge({ rating, size = 'md' }: RatingBadgeProps) {
const getVariant = (val: number): 'warning' | 'primary' | 'success' | 'default' => {
if (val >= 2500) return 'warning';
if (val >= 2000) return 'primary'; // Simplified
if (val >= 1500) return 'primary';
if (val >= 1000) return 'success';
return 'default';
};
const sizeMap: Record<string, 'xs' | 'sm' | 'md'> = {
sm: 'xs',
md: 'sm',
lg: 'md',
};
const config = getColor(rating);
return (
<Badge
{...config}
size={sizeMap[size]}
className={`font-mono ${className}`}
rounded="sm"
variant={getVariant(rating)}
size={size}
>
{rating.toLocaleString()}
</Badge>

View File

@@ -4,7 +4,7 @@ import { RatingComponent } from '@/components/drivers/RatingComponent';
import { RatingHistoryItem } from '@/components/drivers/RatingHistoryItem';
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface RatingBreakdownProps {

View File

@@ -1,6 +1,6 @@
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { ProgressBar } from '@/ui/ProgressBar';
import { Text } from '@/ui/Text';

View File

@@ -1,6 +1,6 @@
import { Box } from '@/ui/primitives/Box';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
interface RatingHistoryItemProps {

View File

@@ -1,7 +1,7 @@
'use client';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
import { Shield } from 'lucide-react';
interface SafetyRatingBadgeProps {

View File

@@ -1,8 +1,8 @@
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text';
import { BarChart3 } from 'lucide-react';

View File

@@ -1,6 +1,6 @@
import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { LucideIcon } from 'lucide-react';

View File

@@ -1,7 +1,7 @@
import { Badge } from '@/ui/Badge';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { ChevronRight, LucideIcon, UserPlus } from 'lucide-react';