website refactor
This commit is contained in:
@@ -1,61 +0,0 @@
|
||||
|
||||
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Image } from '@/ui/Image';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
interface LeagueHeaderProps {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
logoUrl: string;
|
||||
sponsorContent?: ReactNode;
|
||||
statusContent?: ReactNode;
|
||||
}
|
||||
|
||||
export function LeagueHeader({
|
||||
name,
|
||||
description,
|
||||
logoUrl,
|
||||
sponsorContent,
|
||||
statusContent,
|
||||
}: LeagueHeaderProps) {
|
||||
return (
|
||||
<Stack mb={8}>
|
||||
<Stack display="flex" alignItems="center" justifyContent="between" mb={6}>
|
||||
<Stack direction="row" align="center" gap={4}>
|
||||
<Stack h="16" w="16" rounded="xl" overflow="hidden" border style={{ borderColor: 'rgba(38, 38, 38, 0.8)', backgroundColor: '#1a1d23' }} shadow="lg">
|
||||
<Image
|
||||
src={logoUrl}
|
||||
alt={`${name} logo`}
|
||||
width={64}
|
||||
height={64}
|
||||
fullWidth
|
||||
fullHeight
|
||||
objectFit="cover"
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Stack display="flex" alignItems="center" gap={3} mb={1}>
|
||||
<Heading level={1}>
|
||||
{name}
|
||||
{sponsorContent && (
|
||||
<Text color="text-gray-400" weight="normal" size="lg" ml={2}>
|
||||
by {sponsorContent}
|
||||
</Text>
|
||||
)}
|
||||
</Heading>
|
||||
{statusContent}
|
||||
</Stack>
|
||||
{description && (
|
||||
<Text color="text-gray-400" size="sm" maxWidth="xl" block>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import type { LeagueDetailViewData } from '@/lib/view-data/LeagueDetailViewData';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Activity, Timer, Trophy, Users, type LucideIcon } from 'lucide-react';
|
||||
|
||||
interface LeagueHeaderPanelProps {
|
||||
viewData: LeagueDetailViewData;
|
||||
}
|
||||
|
||||
export function LeagueHeaderPanel({ viewData }: LeagueHeaderPanelProps) {
|
||||
return (
|
||||
<Card variant="outline" p={6} position="relative" overflow="hidden" className="bg-graphite-black">
|
||||
{/* Background Accent */}
|
||||
<Stack
|
||||
position="absolute"
|
||||
top={0}
|
||||
right={0}
|
||||
w="300px"
|
||||
h="full"
|
||||
bg="bg-gradient-to-l from-primary-blue/5 to-transparent"
|
||||
pointerEvents="none"
|
||||
>{null}</Stack>
|
||||
|
||||
<Stack direction={{ base: 'col', md: 'row' }} justify="between" align="center" gap={6}>
|
||||
<Stack gap={2}>
|
||||
<Stack direction="row" align="center" gap={3}>
|
||||
<Stack p={2} bg="bg-primary-blue/10" rounded="md" border borderColor="border-primary-blue/20">
|
||||
<Icon icon={Trophy} size={6} color="text-primary-blue" />
|
||||
</Stack>
|
||||
<Heading level={1} letterSpacing="tight">
|
||||
{viewData.name}
|
||||
</Heading>
|
||||
</Stack>
|
||||
<Text color="text-gray-400" size="sm" maxWidth="42rem">
|
||||
{viewData.description}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" gap={8} wrap>
|
||||
<StatItem
|
||||
icon={Users}
|
||||
label="Members"
|
||||
value={viewData.info.membersCount.toString()}
|
||||
color="text-primary-blue"
|
||||
/>
|
||||
<StatItem
|
||||
icon={Timer}
|
||||
label="Races"
|
||||
value={viewData.info.racesCount.toString()}
|
||||
color="text-neon-aqua"
|
||||
/>
|
||||
<StatItem
|
||||
icon={Activity}
|
||||
label="Avg SOF"
|
||||
value={(viewData.info.avgSOF ?? 0).toString()}
|
||||
color="text-performance-green"
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function StatItem({ icon, label, value, color }: { icon: LucideIcon, label: string, value: string, color: string }) {
|
||||
return (
|
||||
<Stack gap={1}>
|
||||
<Stack direction="row" align="center" gap={1.5}>
|
||||
<Icon icon={icon} size={3.5} color="text-gray-500" />
|
||||
<Text size="xs" color="text-gray-500" weight="medium" letterSpacing="wider" block>
|
||||
{label.toUpperCase()}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Text size="xl" weight="bold" color={color} lineHeight="none">
|
||||
{value}
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import { LeagueLogo as UiLeagueLogo } from '@/components/leagues/LeagueLogo';
|
||||
|
||||
export interface LeagueLogoProps {
|
||||
leagueId: string;
|
||||
alt: string;
|
||||
}
|
||||
|
||||
export function LeagueLogo({ leagueId, alt }: LeagueLogoProps) {
|
||||
return (
|
||||
<UiLeagueLogo
|
||||
leagueId={leagueId}
|
||||
alt={alt}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { Link } from '@/ui/Link';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
|
||||
interface Tab {
|
||||
label: string;
|
||||
href: string;
|
||||
exact?: boolean;
|
||||
}
|
||||
|
||||
interface LeagueNavTabsProps {
|
||||
tabs: Tab[];
|
||||
currentPathname: string;
|
||||
}
|
||||
|
||||
export function LeagueNavTabs({ tabs, currentPathname }: LeagueNavTabsProps) {
|
||||
return (
|
||||
<Stack as="nav" borderBottom borderColor="zinc-800" mb={6}>
|
||||
<Stack as="ul" direction="row" gap={8} overflow="auto" hideScrollbar>
|
||||
{tabs.map((tab) => {
|
||||
const isActive = tab.exact
|
||||
? currentPathname === tab.href
|
||||
: currentPathname.startsWith(tab.href);
|
||||
|
||||
return (
|
||||
<Stack as="li" key={tab.href} position="relative">
|
||||
<Link
|
||||
href={tab.href}
|
||||
variant="ghost"
|
||||
pb={4}
|
||||
display="block"
|
||||
size="sm"
|
||||
weight="medium"
|
||||
color={isActive ? 'text-blue-500' : 'text-zinc-400'}
|
||||
hoverTextColor={isActive ? 'text-blue-500' : 'text-zinc-200'}
|
||||
transition
|
||||
>
|
||||
{tab.label}
|
||||
</Link>
|
||||
{isActive && (
|
||||
<Stack
|
||||
position="absolute"
|
||||
bottom="0"
|
||||
left="0"
|
||||
right="0"
|
||||
h="0.5"
|
||||
bg="bg-blue-500"
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -12,6 +12,7 @@ interface RaceEvent {
|
||||
date: string;
|
||||
time: string;
|
||||
status: 'upcoming' | 'live' | 'completed';
|
||||
strengthOfField?: number;
|
||||
}
|
||||
|
||||
interface LeagueSchedulePanelProps {
|
||||
@@ -56,6 +57,12 @@ export function LeagueSchedulePanel({ events }: LeagueSchedulePanelProps) {
|
||||
<Stack color="text-zinc-600"><Clock size={14} /></Stack>
|
||||
<Text size="sm" color="text-zinc-400">{event.time}</Text>
|
||||
</Stack>
|
||||
{event.strengthOfField && (
|
||||
<Stack display="flex" alignItems="center" gap={1.5}>
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase>SOF</Text>
|
||||
<Text size="sm" color="text-zinc-300" font="mono">{event.strengthOfField}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ interface StandingEntry {
|
||||
points: number;
|
||||
wins: number;
|
||||
podiums: number;
|
||||
races: number;
|
||||
avgFinish: number | null;
|
||||
gap: string;
|
||||
}
|
||||
|
||||
@@ -34,10 +36,10 @@ export function LeagueStandingsTable({ standings }: LeagueStandingsTableProps) {
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase letterSpacing="widest">Team</Text>
|
||||
</TableHeader>
|
||||
<TableHeader className="text-center px-4 py-3">
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase letterSpacing="widest">Wins</Text>
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase letterSpacing="widest">Races</Text>
|
||||
</TableHeader>
|
||||
<TableHeader className="text-center px-4 py-3">
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase letterSpacing="widest">Podiums</Text>
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase letterSpacing="widest">Avg</Text>
|
||||
</TableHeader>
|
||||
<TableHeader className="text-right px-4 py-3">
|
||||
<Text size="xs" weight="bold" color="text-zinc-500" uppercase letterSpacing="widest">Points</Text>
|
||||
@@ -60,10 +62,10 @@ export function LeagueStandingsTable({ standings }: LeagueStandingsTableProps) {
|
||||
<Text size="sm" color="text-zinc-500">{entry.teamName || '—'}</Text>
|
||||
</TableCell>
|
||||
<TableCell className="text-center px-4 py-3">
|
||||
<Text size="sm" color="text-zinc-400">{entry.wins}</Text>
|
||||
<Text size="sm" color="text-zinc-400">{entry.races}</Text>
|
||||
</TableCell>
|
||||
<TableCell className="text-center px-4 py-3">
|
||||
<Text size="sm" color="text-zinc-400">{entry.podiums}</Text>
|
||||
<Text size="sm" color="text-zinc-400">{entry.avgFinish?.toFixed(1) || '—'}</Text>
|
||||
</TableCell>
|
||||
<TableCell className="text-right px-4 py-3">
|
||||
<Text size="sm" weight="bold" color="text-white">{entry.points}</Text>
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { Link } from '@/ui/Link';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface Tab {
|
||||
label: string;
|
||||
href: string;
|
||||
exact?: boolean;
|
||||
}
|
||||
|
||||
interface LeagueTabsProps {
|
||||
tabs: Tab[];
|
||||
}
|
||||
|
||||
export function LeagueTabs({ tabs }: LeagueTabsProps) {
|
||||
return (
|
||||
<Stack borderBottom borderColor="border-charcoal-outline">
|
||||
<Stack direction="row" gap={6} overflow="auto">
|
||||
{tabs.map((tab) => (
|
||||
<Link
|
||||
key={tab.href}
|
||||
href={tab.href}
|
||||
variant="ghost"
|
||||
>
|
||||
<Stack pb={3} px={1}>
|
||||
<Text weight="medium"
|
||||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||||
className="whitespace-nowrap"
|
||||
>
|
||||
{tab.label}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Link>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user