website refactor

This commit is contained in:
2026-01-19 14:07:49 +01:00
parent 54f42bab9f
commit 6154d54435
88 changed files with 755 additions and 566 deletions

View File

@@ -9,7 +9,8 @@ interface DriverHeaderPanelProps {
avatarUrl?: string;
nationality: string;
rating: number;
globalRank?: number | null;
ratingLabel: string;
globalRankLabel?: string | null;
bio?: string | null;
actions?: React.ReactNode;
}
@@ -19,7 +20,8 @@ export function DriverHeaderPanel({
avatarUrl,
nationality,
rating,
globalRank,
ratingLabel,
globalRankLabel,
bio,
actions
}: DriverHeaderPanelProps) {
@@ -54,8 +56,8 @@ export function DriverHeaderPanel({
rounded="2xl"
overflow="hidden"
border
borderColor="border-charcoal-outline"
bg="bg-graphite-black"
borderColor="border-charcoal-outline"
bg="bg-graphite-black"
flexShrink={0}
>
<Image
@@ -73,16 +75,16 @@ export function DriverHeaderPanel({
<Text as="h1" size="3xl" weight="bold" color="text-white">
{name}
</Text>
<RatingBadge rating={rating} size="lg" />
<RatingBadge rating={rating} ratingLabel={ratingLabel} size="lg" />
</Stack>
<Stack direction="row" align="center" gap={4} wrap>
<Text size="sm" color="text-gray-400">
{nationality}
</Text>
{globalRank !== undefined && globalRank !== null && (
{globalRankLabel && (
<Text size="sm" color="text-gray-400">
Global Rank: <Text color="text-warning-amber" weight="semibold">#{globalRank}</Text>
Global Rank: <Text color="text-warning-amber" weight="semibold">{globalRankLabel}</Text>
</Text>
)}
</Stack>

View File

@@ -14,8 +14,10 @@ interface DriverProfileHeaderProps {
avatarUrl?: string | null;
nationality: string;
rating: number;
ratingLabel: string;
safetyRating?: number;
globalRank?: number;
safetyRatingLabel: string;
globalRankLabel?: string;
bio?: string | null;
friendRequestSent: boolean;
onAddFriend: () => void;
@@ -26,8 +28,10 @@ export function DriverProfileHeader({
avatarUrl,
nationality,
rating,
ratingLabel,
safetyRating = 92,
globalRank,
safetyRatingLabel,
globalRankLabel,
bio,
friendRequestSent,
onAddFriend,
@@ -56,11 +60,11 @@ export function DriverProfileHeader({
<Stack>
<Stack direction="row" align="center" gap={3} mb={1}>
<Heading level={1}>{name}</Heading>
{globalRank && (
{globalRankLabel && (
<Stack display="flex" alignItems="center" gap={1} rounded="md" bg="bg-warning-amber/10" px={2} py={0.5} border borderColor="border-warning-amber/20">
<Trophy size={12} color="#FFBE4D" />
<Text size="xs" weight="bold" font="mono" color="text-warning-amber">
#{globalRank}
{globalRankLabel}
</Text>
</Stack>
)}
@@ -72,8 +76,8 @@ export function DriverProfileHeader({
</Stack>
<Stack w="1" h="1" rounded="full" bg="bg-gray-700" />
<Stack direction="row" align="center" gap={2}>
<RatingBadge rating={rating} size="sm" />
<SafetyRatingBadge rating={safetyRating} size="sm" />
<RatingBadge rating={rating} ratingLabel={ratingLabel} size="sm" />
<SafetyRatingBadge rating={safetyRating} ratingLabel={safetyRatingLabel} size="sm" />
</Stack>
</Stack>
</Stack>

View File

@@ -13,7 +13,8 @@ interface DriverTableRowProps {
avatarUrl?: string | null;
nationality: string;
rating: number;
wins: number;
ratingLabel: string;
winsLabel: string;
onClick: () => void;
}
@@ -23,7 +24,8 @@ export function DriverTableRow({
avatarUrl,
nationality,
rating,
wins,
ratingLabel,
winsLabel,
onClick,
}: DriverTableRowProps) {
return (
@@ -58,11 +60,11 @@ export function DriverTableRow({
<Text size="xs" variant="low">{nationality}</Text>
</TableCell>
<TableCell textAlign="right">
<RatingBadge rating={rating} size="sm" />
<RatingBadge rating={rating} ratingLabel={ratingLabel} size="sm" />
</TableCell>
<TableCell textAlign="right">
<Text size="sm" weight="semibold" font="mono" variant="success">
{wins}
{winsLabel}
</Text>
</TableCell>
</TableRow>

View File

@@ -17,25 +17,25 @@ interface DriverStat {
}
interface DriversDirectoryHeaderProps {
totalDrivers: number;
activeDrivers: number;
totalWins: number;
totalRaces: number;
totalDriversLabel: string;
activeDriversLabel: string;
totalWinsLabel: string;
totalRacesLabel: string;
onViewLeaderboard: () => void;
}
export function DriversDirectoryHeader({
totalDrivers,
activeDrivers,
totalWins,
totalRaces,
totalDriversLabel,
activeDriversLabel,
totalWinsLabel,
totalRacesLabel,
onViewLeaderboard,
}: DriversDirectoryHeaderProps) {
const stats: DriverStat[] = [
{ 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' },
{ label: 'drivers', value: totalDriversLabel, intent: 'primary' },
{ label: 'active', value: activeDriversLabel, intent: 'success' },
{ label: 'total wins', value: totalWinsLabel, intent: 'warning' },
{ label: 'races', value: totalRacesLabel, intent: 'telemetry' },
];
return (

View File

@@ -33,9 +33,9 @@ interface FeaturedDriverCardProps {
name: string;
nationality: string;
avatarUrl?: string;
rating: number;
wins: number;
podiums: number;
ratingLabel: string;
winsLabel: string;
podiumsLabel: string;
skillLevel?: string;
category?: string;
};
@@ -142,17 +142,17 @@ export function FeaturedDriverCard({ driver, position, onClick }: FeaturedDriver
<Box display="grid" gridCols={3} gap={3}>
<MiniStat
label="Rating"
value={driver.rating.toLocaleString()}
value={driver.ratingLabel}
color="text-primary-blue"
/>
<MiniStat
label="Wins"
value={driver.wins}
value={driver.winsLabel}
color="text-performance-green"
/>
<MiniStat
label="Podiums"
value={driver.podiums}
value={driver.podiumsLabel}
color="text-warning-amber"
/>
</Box>

View File

@@ -17,12 +17,12 @@ interface ProfileHeroProps {
avatarUrl?: string;
country: string;
iracingId: number;
joinedAt: string | Date;
joinedAtLabel: string;
};
stats: {
rating: number;
ratingLabel: string;
} | null;
globalRank: number;
globalRankLabel: string;
timezone: string;
socialHandles: {
platform: string;
@@ -47,7 +47,7 @@ function getSocialIcon(platform: string) {
export function ProfileHero({
driver,
stats,
globalRank,
globalRankLabel,
timezone,
socialHandles,
onAddFriend,
@@ -87,14 +87,14 @@ export function ProfileHero({
<Surface variant="muted" rounded="lg" padding={1} style={{ backgroundColor: 'rgba(59, 130, 246, 0.1)', border: '1px solid rgba(59, 130, 246, 0.3)', paddingLeft: '0.75rem', paddingRight: '0.75rem' }}>
<Stack direction="row" align="center" gap={2}>
<Star style={{ width: '1rem', height: '1rem', color: '#3b82f6' }} />
<Text font="mono" weight="bold" color="text-primary-blue">{stats.rating}</Text>
<Text font="mono" weight="bold" color="text-primary-blue">{stats.ratingLabel}</Text>
<Text size="xs" color="text-gray-400">Rating</Text>
</Stack>
</Surface>
<Surface variant="muted" rounded="lg" padding={1} style={{ backgroundColor: 'rgba(250, 204, 21, 0.1)', border: '1px solid rgba(250, 204, 21, 0.3)', paddingLeft: '0.75rem', paddingRight: '0.75rem' }}>
<Stack direction="row" align="center" gap={2}>
<Trophy style={{ width: '1rem', height: '1rem', color: '#facc15' }} />
<Text font="mono" weight="bold" style={{ color: '#facc15' }}>#{globalRank}</Text>
<Text font="mono" weight="bold" style={{ color: '#facc15' }}>{globalRankLabel}</Text>
<Text size="xs" color="text-gray-400">Global</Text>
</Stack>
</Surface>
@@ -111,11 +111,7 @@ export function ProfileHero({
<Stack direction="row" align="center" gap={1.5}>
<Calendar style={{ width: '1rem', height: '1rem' }} />
<Text size="sm">
Joined{' '}
{new Date(driver.joinedAt).toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
})}
Joined {driver.joinedAtLabel}
</Text>
</Stack>
<Stack direction="row" align="center" gap={1.5}>

View File

@@ -3,10 +3,11 @@ import { Badge } from '@/ui/Badge';
interface RatingBadgeProps {
rating: number;
ratingLabel: string;
size?: 'sm' | 'md' | 'lg';
}
export function RatingBadge({ rating, size = 'md' }: RatingBadgeProps) {
export function RatingBadge({ rating, ratingLabel, size = 'md' }: RatingBadgeProps) {
const badgeSize = size === 'lg' ? 'md' : size;
const getVariant = (val: number): 'warning' | 'primary' | 'success' | 'default' => {
@@ -22,7 +23,7 @@ export function RatingBadge({ rating, size = 'md' }: RatingBadgeProps) {
variant={getVariant(rating)}
size={badgeSize}
>
{rating.toLocaleString()}
{ratingLabel}
</Badge>
);
}

View File

@@ -6,10 +6,11 @@ import { Shield } from 'lucide-react';
interface SafetyRatingBadgeProps {
rating: number;
ratingLabel: string;
size?: 'sm' | 'md' | 'lg';
}
export function SafetyRatingBadge({ rating, size = 'md' }: SafetyRatingBadgeProps) {
export function SafetyRatingBadge({ rating, ratingLabel, size = 'md' }: SafetyRatingBadgeProps) {
const getColor = (r: number) => {
if (r >= 90) return 'text-performance-green';
if (r >= 70) return 'text-warning-amber';
@@ -65,7 +66,7 @@ export function SafetyRatingBadge({ rating, size = 'md' }: SafetyRatingBadgeProp
font="mono"
color={colorClass}
>
SR {rating.toFixed(0)}
{ratingLabel}
</Text>
</Box>
);