website refactor
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: '#' }}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user