website refactor

This commit is contained in:
2026-01-20 22:31:14 +01:00
parent 51288234f4
commit 7cbec00474
52 changed files with 577 additions and 146 deletions

View File

@@ -41,7 +41,7 @@ export function AppErrorBoundaryView({ title, description, children }: AppErrorB
<Heading level={1} weight="bold">
{title}
</Heading>
<Text variant="low" align="center" style={{ maxWidth: '32rem' }} leading="relaxed">
<Text variant="low" align="center" maxWidth="32rem" leading="relaxed">
{description}
</Text>
</Stack>

View File

@@ -46,7 +46,7 @@ export function ErrorDetailsBlock({ error }: ErrorDetailsBlockProps) {
<Accordion title="Technical Logs">
<Stack gap={4}>
<Card variant="outline">
<Text font="mono" size="xs" variant="low" block leading="relaxed" style={{ maxHeight: '12rem', overflow: 'auto' }}>
<Text font="mono" size="xs" variant="low" block leading="relaxed" maxHeight="12rem" overflow="auto">
{error.stack || 'No stack trace available'}
{error.digest && `\n\nDigest: ${error.digest}`}
</Text>

View File

@@ -11,9 +11,9 @@ export function Hero() {
return (
<LandingHero
subtitle="Sim Racing Infrastructure"
title="Professional League Management. Engineered for Control."
description="GridPilot eliminates the administrative overhead of running iRacing leagues. No spreadsheets. No manual points. No protest chaos. Just pure competition, structured for growth."
primaryAction={{ label: 'Create Your League', href: '#' }}
title="League Management Infrastructure."
description="Automated results, standings, and stewarding for iRacing leagues. No manual data entry. Structured race management."
primaryAction={{ label: 'Create League', href: '#' }}
secondaryAction={{ label: 'View Demo', href: '#' }}
/>
);

View File

@@ -24,8 +24,8 @@ export function ValuePillars() {
icon: Gavel,
},
{
title: "Professional Presence",
description: "A clean, modern home for your league. Schedules, standings, and rosters that build prestige and attract drivers.",
title: "League Identity",
description: "Public schedules, standings, and rosters for league members.",
icon: Layout,
},
];

View File

@@ -30,7 +30,6 @@ export function RankingsTable({ drivers, onDriverClick }: RankingsTableProps) {
if (drivers.length === 0) {
return (
<Stack py={16} align="center" bg="bg-iron-gray/30" border borderColor="border-charcoal-outline" rounded="xl">
<Text size="4xl" block mb={4}>🔍</Text>
<Text color="text-gray-400" block mb={2}>No drivers found</Text>
<Text size="sm" color="text-gray-500">There are no drivers in the system yet</Text>
</Stack>

View File

@@ -0,0 +1,48 @@
import React from 'react';
import { TeamRankingRow } from './TeamRankingRow';
import { LeaderboardTableShell } from '@/ui/LeaderboardTableShell';
interface LeaderboardTeam {
id: string;
name: string;
logoUrl?: string;
position: number;
rating: number;
totalWins: number;
totalRaces: number;
memberCount: number;
}
interface TeamLeaderboardTableProps {
teams: LeaderboardTeam[];
onTeamClick?: (id: string) => void;
}
export function TeamLeaderboardTable({ teams, onTeamClick }: TeamLeaderboardTableProps) {
const columns = [
{ key: 'rank', label: 'Rank', width: '8rem' },
{ key: 'team', label: 'Team' },
{ key: 'rating', label: 'Rating', align: 'center' as const },
{ key: 'wins', label: 'Wins', align: 'center' as const },
{ key: 'races', label: 'Races', align: 'center' as const },
];
return (
<LeaderboardTableShell columns={columns}>
{teams.map((team) => (
<TeamRankingRow
key={team.id}
rank={team.position}
id={team.id}
name={team.name}
logoUrl={team.logoUrl}
rating={team.rating}
wins={team.totalWins}
races={team.totalRaces}
memberCount={team.memberCount}
onClick={() => onTeamClick?.(team.id)}
/>
))}
</LeaderboardTableShell>
);
}

View File

@@ -28,7 +28,7 @@ export function LeagueListItem({ league, isAdmin }: LeagueListItemProps) {
league.membershipRole && (
<Text size="xs" variant="low">
Your role:{' '}
<Text as="span" variant="med" style={{ textTransform: 'capitalize' }}>{league.membershipRole}</Text>
<Text as="span" variant="med" transform="capitalize">{league.membershipRole}</Text>
</Text>
)
}

View File

@@ -27,21 +27,22 @@ export function LeagueSummaryCard({
href,
}: LeagueSummaryCardProps) {
return (
<Card p={0} style={{ overflow: 'hidden' }}>
<Card p={0} overflow="hidden">
<Stack p={4}>
<Stack direction="row" align="center" gap={4} mb={4}>
<LeagueLogo leagueId={id} alt={name} size={56} />
<Stack style={{ flex: 1, minWidth: 0 }}>
<Stack flex={1} minWidth="0">
<Text
size="xs"
color="text-gray-500"
style={{ textTransform: 'uppercase', letterSpacing: '0.05em' }}
transform="uppercase"
letterSpacing="0.05em"
block
mb={0.5}
>
League
</Text>
<Heading level={3} style={{ fontSize: '1rem' }}>
<Heading level={3} fontSize="1rem">
{name}
</Heading>
</Stack>
@@ -54,7 +55,7 @@ export function LeagueSummaryCard({
block
mb={4}
lineClamp={2}
style={{ height: '2.5rem' }}
height="2.5rem"
>
{description}
</Text>
@@ -62,7 +63,7 @@ export function LeagueSummaryCard({
<Stack mb={4}>
<Grid cols={2} gap={3}>
<Card variant="outline" rounded="lg" p={3} className="bg-graphite-black">
<Card variant="outline" rounded="lg" p={3} bg="bg-graphite-black">
<Text size="xs" color="text-gray-500" block mb={1}>
Max Drivers
</Text>
@@ -70,14 +71,14 @@ export function LeagueSummaryCard({
{maxDrivers}
</Text>
</Card>
<Card variant="outline" rounded="lg" p={3} className="bg-graphite-black">
<Card variant="outline" rounded="lg" p={3} bg="bg-graphite-black">
<Text size="xs" color="text-gray-500" block mb={1}>
Format
</Text>
<Text
weight="medium"
color="text-white"
style={{ textTransform: 'capitalize' }}
transform="capitalize"
>
{qualifyingFormat}
</Text>

View File

@@ -35,7 +35,7 @@ export const Accordion = ({
};
return (
<Surface variant="muted" rounded="lg" style={{ border: '1px solid var(--ui-color-border-default)', overflow: 'hidden' }}>
<Surface variant="muted" rounded="lg" border={true} overflow="hidden">
<Box
as="button"
onClick={handleToggle}

View File

@@ -88,16 +88,14 @@ export const Modal = ({
variant="default"
rounded="lg"
shadow="xl"
style={{
width: '100%',
maxWidth: sizeMap[size],
maxHeight: '90vh',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
position: 'relative',
border: '1px solid var(--ui-color-border-default)'
}}
width="100%"
maxWidth={sizeMap[size]}
maxHeight="90vh"
overflow="hidden"
display="flex"
flexDirection="column"
position="relative"
border={true}
>
<Box
display="flex"

View File

@@ -1,5 +1,3 @@
import { Badge } from '@/ui/Badge';
import { Icon } from '@/ui/Icon';
import { Link } from '@/ui/Link';
@@ -28,8 +26,14 @@ export function TeamMembershipCard({
padding={4}
rounded="xl"
border
style={{ borderColor: 'rgba(38, 38, 38, 0.8)' }}
className="flex items-center gap-4 hover:border-purple-400/30 hover:bg-iron-gray/50 transition-all group"
borderColor="rgba(38, 38, 38, 0.8)"
display="flex"
alignItems="center"
gap={4}
hoverBorderColor="rgba(168, 85, 247, 0.3)"
hoverBg="iron-gray/50"
transition
group
>
<Surface
variant="muted"
@@ -38,17 +42,18 @@ export function TeamMembershipCard({
display="flex"
center
rounded="xl"
style={{ backgroundColor: 'rgba(147, 51, 234, 0.1)', borderColor: 'rgba(147, 51, 234, 0.2)' }}
bg="rgba(147, 51, 234, 0.1)"
borderColor="rgba(147, 51, 234, 0.2)"
border
>
<Icon icon={Users} size={6} color="var(--neon-purple)" />
</Surface>
<Stack style={{ flex: 1, minWidth: 0 }}>
<Text weight="semibold" color="text-white" className="truncate group-hover:text-purple-400 transition-colors" block>
<Stack flex="1" minWidth="0">
<Text weight="semibold" color="text-white" truncate groupHoverTextColor="purple-400" block>
{teamName}
</Text>
<Stack direction="row" align="center" gap={2} mt={1}>
<Badge variant="primary" style={{ backgroundColor: 'rgba(147, 51, 234, 0.1)', color: 'var(--neon-purple)', textTransform: 'capitalize' }}>
<Badge variant="primary" bg="rgba(147, 51, 234, 0.1)" color="var(--neon-purple)" transform="capitalize">
{role}
</Badge>
<Text size="xs" color="text-gray-400">
@@ -56,7 +61,7 @@ export function TeamMembershipCard({
</Text>
</Stack>
</Stack>
<Icon icon={ChevronRight} size={4} color="var(--text-gray-500)" className="group-hover:text-purple-400 transition-colors" />
<Icon icon={ChevronRight} size={4} color="var(--text-gray-500)" />
</Surface>
</Link>
);

View File

@@ -18,15 +18,16 @@ export function TeamsHeader({ title, subtitle, action }: TeamsHeaderProps) {
alignItems={{ md: 'end' }}
justifyContent="space-between"
gap={6}
className="border-b border-[var(--ui-color-border-muted)] pb-8"
borderBottom="1px solid var(--ui-color-border-muted)"
paddingBottom={8}
>
<Box className="space-y-2">
<Box display="flex" alignItems="center" gap={3}>
<Box width={1} height={8} className="bg-[var(--ui-color-intent-primary)]" />
<Box>
<Box display="flex" alignItems="center" gap={3} marginBottom={2}>
<Box width={1} height={8} backgroundColor="var(--ui-color-intent-primary)" />
<Heading level={1} weight="bold" uppercase>{title}</Heading>
</Box>
{subtitle && (
<Text variant="low" size="lg" uppercase mono className="tracking-[0.2em]">
<Text variant="low" size="lg" uppercase mono letterSpacing="0.2em">
{subtitle}
</Text>
)}