website refactor

This commit is contained in:
2026-01-19 00:46:46 +01:00
parent b0431637b7
commit e1ce3bffd1
21 changed files with 297 additions and 121 deletions

View File

@@ -14,31 +14,31 @@ interface RaceCardProps {
track: string;
car: string;
scheduledAt: string;
scheduledAtLabel: string;
timeLabel: string;
status: string;
statusLabel: string;
statusVariant: 'primary' | 'success' | 'warning' | 'critical' | 'default' | 'secondary' | 'info' | 'danger';
leagueName: string;
leagueId?: string;
strengthOfField?: number | null;
onClick?: () => void;
statusConfig: {
intent: 'primary' | 'success' | 'warning' | 'critical' | 'default' | 'secondary' | 'info' | 'danger';
icon: LucideIcon | null;
label: string;
};
}
export function RaceCard({
track,
car,
scheduledAt,
scheduledAtLabel,
timeLabel,
status,
statusLabel,
statusVariant,
leagueName,
leagueId,
strengthOfField,
onClick,
statusConfig,
}: RaceCardProps) {
const scheduledAtDate = new Date(scheduledAt);
return (
<Card
variant="dark"
@@ -48,10 +48,10 @@ export function RaceCard({
{/* Time Column */}
<Stack align="center" gap={1}>
<Text size="lg" weight="bold" variant="high">
{scheduledAtDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
{timeLabel}
</Text>
<Text size="xs" variant={statusConfig.intent === 'default' ? 'low' : (statusConfig.intent as any)}>
{status === 'running' ? 'LIVE' : scheduledAtDate.toLocaleDateString()}
<Text size="xs" variant={statusVariant === 'default' ? 'low' : (statusVariant as any)}>
{status === 'running' ? 'LIVE' : scheduledAtLabel}
</Text>
</Stack>
@@ -83,8 +83,8 @@ export function RaceCard({
</Stack>
{/* Status Badge */}
<Badge variant={statusConfig.intent}>
{statusConfig.label}
<Badge variant={statusVariant}>
{statusLabel}
</Badge>
</Stack>

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { LucideIcon } from 'lucide-react';
import { raceStatusConfig } from '@/lib/utilities/raceStatus';
import { RaceStatusDisplay } from '@/lib/display-objects/RaceStatusDisplay';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { RaceCard as UiRaceCard } from './RaceCard';
interface RaceCardProps {
@@ -18,28 +18,20 @@ interface RaceCardProps {
}
export function RaceCard({ race, onClick }: RaceCardProps) {
const config = raceStatusConfig[race.status as keyof typeof raceStatusConfig] || {
border: 'border-charcoal-outline',
bg: 'bg-charcoal-outline',
color: 'text-gray-400',
icon: null,
label: 'Scheduled',
};
return (
<UiRaceCard
track={race.track}
car={race.car}
scheduledAt={race.scheduledAt}
scheduledAtLabel={DateDisplay.formatShort(race.scheduledAt)}
timeLabel={DateDisplay.formatTime(race.scheduledAt)}
status={race.status}
statusLabel={RaceStatusDisplay.getLabel(race.status)}
statusVariant={RaceStatusDisplay.getVariant(race.status) as any}
leagueName={race.leagueName}
leagueId={race.leagueId}
strengthOfField={race.strengthOfField}
onClick={onClick}
statusConfig={{
...config,
icon: config.icon as LucideIcon | null,
}}
/>
);
}

View File

@@ -19,29 +19,6 @@ interface RaceListProps {
}
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 (
<EmptyState
@@ -62,8 +39,6 @@ export function RaceList({ racesByDate, totalCount, onRaceClick }: RaceListProps
<Stack gap={2}>
{group.races.map((race) => {
const config = statusConfig[race.status as keyof typeof statusConfig] || statusConfig.scheduled;
return (
<RaceListItem
key={race.id}
@@ -76,7 +51,9 @@ export function RaceList({ racesByDate, totalCount, onRaceClick }: RaceListProps
leagueHref={routes.league.detail(race.leagueId ?? '')}
strengthOfField={race.strengthOfField}
onClick={() => onRaceClick(race.id)}
statusConfig={config}
statusLabel={race.statusLabel}
statusVariant={race.statusVariant as any}
statusIconName={race.statusIconName}
/>
);
})}

View File

@@ -5,9 +5,16 @@ import { Icon } from '@/ui/Icon';
import { Link } from '@/ui/Link';
import { Text } from '@/ui/Text';
import { RaceCard, RaceTimeColumn, RaceInfo } from '@/ui/RaceCard';
import { Car, Trophy, Zap, ArrowRight } from 'lucide-react';
import { Car, Trophy, Zap, ArrowRight, Clock, PlayCircle, CheckCircle2, XCircle, HelpCircle } from 'lucide-react';
import React from 'react';
import { LucideIcon } from 'lucide-react';
const ICON_MAP = {
Clock,
PlayCircle,
CheckCircle2,
XCircle,
HelpCircle,
};
interface RaceListItemProps {
track: string;
@@ -17,15 +24,13 @@ interface RaceListItemProps {
dateLabel?: string;
dayLabel?: string;
status: string;
statusLabel: string;
statusVariant: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
statusIconName: 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({
@@ -36,13 +41,16 @@ export function RaceListItem({
dateLabel,
dayLabel,
status,
statusLabel,
statusVariant,
statusIconName,
leagueName,
leagueHref,
strengthOfField,
onClick,
statusConfig,
}: RaceListItemProps) {
const isLive = status === 'running';
const StatusIcon = ICON_MAP[statusIconName as keyof typeof ICON_MAP] || HelpCircle;
return (
<RaceCard onClick={onClick} isLive={isLive}>
@@ -59,9 +67,9 @@ export function RaceListItem({
title={track}
subtitle={car}
badge={
<Badge variant={statusConfig.variant}>
<Icon icon={statusConfig.icon} size={3.5} />
{statusConfig.label}
<Badge variant={statusVariant}>
<Icon icon={StatusIcon} size={3.5} />
{statusLabel}
</Badge>
}
meta={

View File

@@ -1,19 +1,18 @@
import { RaceSummary } from '@/ui/RaceSummary';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import React from 'react';
interface RaceSummaryItemProps {
track: string;
meta: string;
date: Date;
dateLabel: string;
}
export function RaceSummaryItem({ track, meta, date }: RaceSummaryItemProps) {
export function RaceSummaryItem({ track, meta, dateLabel }: RaceSummaryItemProps) {
return (
<RaceSummary
track={track}
meta={meta}
date={DateDisplay.formatShort(date)}
date={dateLabel}
/>
);
}

View File

@@ -14,7 +14,9 @@ interface TeamDetailsHeaderProps {
description?: string;
logoUrl?: string;
memberCount: number;
memberCountLabel?: string;
foundedDate?: string;
foundedDateLabel?: string;
isAdmin?: boolean;
onAdminClick?: () => void;
}
@@ -25,7 +27,9 @@ export function TeamDetailsHeader({
description,
logoUrl,
memberCount,
memberCountLabel,
foundedDate,
foundedDateLabel,
isAdmin,
onAdminClick,
}: TeamDetailsHeaderProps) {
@@ -38,6 +42,9 @@ export function TeamDetailsHeader({
</div>
}
description={description || 'No mission statement provided.'}
memberCount={memberCount}
memberCountLabel={memberCountLabel}
foundedDateLabel={foundedDateLabel}
sideContent={
<div className="w-32 h-32 bg-[var(--ui-color-bg-surface-muted)] border border-[var(--ui-color-border-default)] flex items-center justify-center overflow-hidden rounded-lg">
{logoUrl ? (
@@ -58,7 +65,7 @@ export function TeamDetailsHeader({
},
{
label: 'Established',
value: foundedDate ? new Date(foundedDate).toLocaleDateString() : 'Unknown',
value: foundedDateLabel || 'Unknown',
}
]}
/>

View File

@@ -17,13 +17,16 @@ interface TeamHeroProps {
description?: string;
category?: string | null;
createdAt?: string;
foundedDateLabel?: string;
leagues: { id: string }[];
};
memberCount: number;
memberCountLabel?: string;
leagueCountLabel?: string;
onUpdate: () => void;
}
export function TeamHero({ team, memberCount, onUpdate }: TeamHeroProps) {
export function TeamHero({ team, memberCount, memberCountLabel, leagueCountLabel, onUpdate }: TeamHeroProps) {
return (
<Card>
<Group align="start" justify="between" wrap gap={6}>
@@ -44,20 +47,20 @@ export function TeamHero({ team, memberCount, onUpdate }: TeamHeroProps) {
stats={[
{
label: 'Personnel',
value: `${memberCount} ${memberCount === 1 ? 'member' : 'members'}`,
value: memberCountLabel || 'Unknown',
},
...(team.category ? [{
label: 'Category',
value: team.category,
intent: 'primary' as const,
}] : []),
...(team.createdAt ? [{
...(team.foundedDateLabel ? [{
label: 'Founded',
value: new Date(team.createdAt).toLocaleDateString('en-US', { month: 'short', year: 'numeric' }),
value: team.foundedDateLabel,
}] : []),
...(team.leagues && team.leagues.length > 0 ? [{
label: 'Activity',
value: `${team.leagues.length} ${team.leagues.length === 1 ? 'league' : 'leagues'}`,
value: leagueCountLabel || 'Unknown',
}] : []),
]}
/>

View File

@@ -10,6 +10,7 @@ interface Member {
driverName: string;
role: string;
joinedAt: string;
joinedAtLabel: string;
}
interface TeamMembersTableProps {
@@ -49,7 +50,7 @@ export function TeamMembersTable({ members, isAdmin, onRemoveMember }: TeamMembe
</TableCell>
<TableCell>
<Text size="xs" color="text-gray-500" font="mono">
{new Date(member.joinedAt).toLocaleDateString()}
{member.joinedAtLabel}
</Text>
</TableCell>
<TableCell textAlign="right">