website refactor

This commit is contained in:
2026-01-15 19:55:46 +01:00
parent 5ef149b782
commit ce7be39155
154 changed files with 436 additions and 356 deletions

View File

@@ -6,7 +6,7 @@ import React from 'react';
import './globals.css';
import { AppWrapper } from '@/components/AppWrapper';
import { Header } from '@/ui/Header';
import { HeaderContent } from '@/ui/HeaderContent';
import { HeaderContent } from '@/components/layout/HeaderContent';
import { MainContent } from '@/ui/MainContent';
export const dynamic = 'force-dynamic';

View File

@@ -18,7 +18,7 @@ import {
Target,
Timer,
} from 'lucide-react';
import { LeagueCard } from '@/ui/LeagueCardWrapper';
import { LeagueCard } from '@/components/leagues/LeagueCardWrapper';
import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { Input } from '@/ui/Input';

View File

@@ -19,7 +19,7 @@ import {
} from 'lucide-react';
import Link from 'next/link';
import { useMemo, useState } from 'react';
import { PendingProtestsList } from '@/ui/PendingProtestsList';
import { PendingProtestsList } from '@/components/leagues/PendingProtestsList';
import { PenaltyHistoryList } from '@/components/leagues/PenaltyHistoryList';
interface StewardingData {

View File

@@ -37,7 +37,7 @@ import { useMemo, useState } from 'react';
// Shared state components
import { StateContainer } from '@/components/shared/state/StateContainer';
import { LoadingWrapper } from '@/ui/LoadingWrapper';
import { LoadingWrapper } from '@/components/shared/state/LoadingWrapper';
import { useLeagueAdminStatus } from "@/lib/hooks/league/useLeagueAdminStatus";
import { useProtestDetail } from "@/lib/hooks/league/useProtestDetail";

View File

@@ -5,7 +5,7 @@ import { motion, useReducedMotion } from 'framer-motion';
import { Card } from '@/ui/Card';
import { Button } from '@/ui/Button';
import { Input } from '@/ui/Input';
import { SponsorHero } from '@/ui/SponsorHero';
import { SponsorHero } from '@/components/sponsors/SponsorHero';
import { SponsorWorkflowMockup } from '@/components/sponsors/SponsorWorkflowMockup';
import { SponsorBenefitCard } from '@/components/sponsors/SponsorBenefitCard';
import { siteConfig } from '@/lib/siteConfig';

View File

@@ -8,7 +8,7 @@ import {
Trophy,
Car,
} from 'lucide-react';
import { WorkflowMockup, WorkflowStep } from '@/ui/WorkflowMockup';
import { WorkflowMockup, WorkflowStep } from '@/components/mockups/WorkflowMockup';
const WORKFLOW_STEPS: WorkflowStep[] = [
{

View File

@@ -2,9 +2,9 @@
import { routes } from '@/lib/routing/RouteConfig';
import { Trophy, Users } from 'lucide-react';
import { Box } from './Box';
import { Heading } from './Heading';
import { QuickActionItem } from './QuickActionItem';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { QuickActionItem } from '@/ui/QuickActionItem';
export function QuickActions() {
return (

View File

@@ -6,11 +6,11 @@ import type { GlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
import { Bug, Shield, X } from 'lucide-react';
import { useCallback, useEffect, useState } from 'react';
import { Box } from './Box';
import { Button } from './Button';
import { Icon } from './Icon';
import { Stack } from './Stack';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
// Extend Window interface for debug globals
declare global {

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Card } from '@/ui/Card';
import { RankBadge } from '@/ui/RankBadge';
import { DriverIdentity } from '@/ui/DriverIdentity';
import { DriverIdentity } from '@/components/drivers/DriverIdentity';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Stack } from '@/ui/Stack';
import { DriverStats } from '@/ui/DriverStats';

View File

@@ -2,12 +2,12 @@
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Zap } from 'lucide-react';
import { Badge } from './Badge';
import { Box } from './Box';
import { Icon } from './Icon';
import { Image } from './Image';
import { Stack } from './Stack';
import { Text } from './Text';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface DriverEntryRowProps {
index: number;

View File

@@ -1,9 +1,9 @@
import Link from 'next/link';
import Image from 'next/image';
import { PlaceholderImage } from './PlaceholderImage';
import { Box } from './Box';
import { Text } from './Text';
import { Badge } from './Badge';
import { PlaceholderImage } from '@/ui/PlaceholderImage';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Badge } from '@/ui/Badge';
import { Image } from '@/ui/Image';
export interface DriverIdentityProps {
driver: {
@@ -43,7 +43,9 @@ export function DriverIdentity(props: DriverIdentityProps) {
alt={driver.name}
width={avatarSize}
height={avatarSize}
className="w-full h-full object-cover"
fullWidth
fullHeight
objectFit="cover"
/>
) : (
<PlaceholderImage size={avatarSize} />

View File

@@ -7,10 +7,10 @@ import { Text } from '@/ui/Text';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/Stack';
import { StatCard } from '@/ui/StatCard';
import { ProfileHeader } from '@/ui/ProfileHeader';
import { ProfileHeader } from '@/components/drivers/ProfileHeader';
import { ProfileStats } from './ProfileStats';
import { CareerHighlights } from '@/ui/CareerHighlights';
import { DriverRankings } from '@/ui/DriverRankings';
import { DriverRankings } from '@/components/drivers/DriverRankings';
import { PerformanceMetrics } from '@/ui/PerformanceMetrics';
import { useDriverProfile } from "@/hooks/driver/useDriverProfile";

View File

@@ -1,9 +1,9 @@
import React from 'react';
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { RankingListItem } from '@/ui/RankingListItem';
import { RankingList } from '@/ui/RankingList';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { RankingListItem } from '@/components/leaderboards/RankingListItem';
import { RankingList } from '@/components/leaderboards/RankingList';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
export interface DriverRanking {
type: 'overall' | 'league';

View File

@@ -1,6 +1,7 @@
import { mediaConfig } from '@/lib/config/mediaConfig';
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';

View File

@@ -6,8 +6,8 @@ import { Button } from '@/ui/Button';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { LoadingWrapper } from '@/ui/LoadingWrapper';
import { EmptyState } from '@/ui/EmptyState';
import { LoadingWrapper } from '@/components/shared/state/LoadingWrapper';
import { EmptyState } from '@/components/shared/state/EmptyState';
import { Pagination } from '@/ui/Pagination';
import { Trophy } from 'lucide-react';

View File

@@ -3,7 +3,7 @@
import React, { Component, ReactNode, useState } from 'react';
import { ApiError } from '@/lib/api/base/ApiError';
import { connectionMonitor } from '@/lib/api/base/ApiConnectionMonitor';
import { ErrorDisplay } from './ErrorDisplay';
import { ErrorDisplay } from '@/components/shared/state/ErrorDisplay';
import { DevErrorPanel } from './DevErrorPanel';
interface Props {

View File

@@ -4,7 +4,7 @@ import React, { Component, ReactNode, ErrorInfo, useState, version } from 'react
import { ApiError } from '@/lib/api/base/ApiError';
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
import { DevErrorPanel } from './DevErrorPanel';
import { ErrorDisplay } from './ErrorDisplay';
import { ErrorDisplay } from '@/components/shared/state/ErrorDisplay';
interface Props {
children: ReactNode;

View File

@@ -2,7 +2,7 @@
import React from 'react';
import { ApiError } from '@/lib/api/base/ApiError';
import { ErrorDisplay as UiErrorDisplay } from '@/ui/ErrorDisplay';
import { ErrorDisplay as UiErrorDisplay } from '@/components/shared/state/ErrorDisplay';
interface ErrorDisplayProps {
error: ApiError;

View File

@@ -4,8 +4,8 @@ import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { ActivityItem } from '@/ui/ActivityItem';
import { Icon } from '@/ui/Icon';
import { ActivityFeedList } from '@/ui/ActivityFeedList';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { ActivityFeedList } from '@/components/feed/ActivityFeedList';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
interface FeedItem {
id: string;

View File

@@ -1,8 +1,9 @@
import { ReactNode } from 'react';
import { Box } from './Box';
import { Surface } from './Surface';
import { Box } from '@/ui/Box';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
interface ActivityFeedItemProps {
icon: ReactNode;

View File

@@ -1,5 +1,5 @@
import React, { ReactNode } from 'react';
import { Stack } from './Stack';
import { Stack } from '@/ui/Stack';
interface ActivityFeedListProps {
children: ReactNode;

View File

@@ -1,7 +1,7 @@
import { Card } from '@/ui/Card';
import { FeedList } from '@/ui/FeedList';
import { UpcomingRacesSidebar } from '@/ui/UpcomingRacesSidebar';
import { LatestResultsSidebar } from '@/ui/LatestResultsSidebar';
import { FeedList } from '@/components/feed/FeedList';
import { UpcomingRacesSidebar } from '@/components/races/UpcomingRacesSidebar';
import { LatestResultsSidebar } from '@/components/races/LatestResultsSidebar';
interface FeedItemData {
id: string;

View File

@@ -3,11 +3,11 @@
import { motion, useReducedMotion } from 'framer-motion';
import { LucideIcon } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Box } from './Box';
import { Heading } from './Heading';
import { Icon } from './Icon';
import { Surface } from './Surface';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
interface BenefitCardProps {
icon: LucideIcon;

View File

@@ -1,12 +1,12 @@
'use client';
import { useRef, useState, useEffect } from 'react';
import { Section } from '@/ui/Section';
import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading';
import { MockupStack } from '@/ui/MockupStack';
import { MockupStack } from '@/components/mockups/MockupStack';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { LeagueHomeMockup } from '@/components/mockups/LeagueHomeMockup';
import { StandingsTableMockup } from '@/components/mockups/StandingsTableMockup';
import { TeamCompetitionMockup } from '@/components/mockups/TeamCompetitionMockup';

View File

@@ -1,5 +1,5 @@
import { useRef } from 'react';
import { useParallax } from '@/hooks/useScrollProgress';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
@@ -126,7 +126,7 @@ export function LandingHero() {
<Box display="flex" alignItems="center" justifyContent="center">
<Button
as="a"
href="#community"
href={discordUrl}
variant="primary"
px={8}
py={4}
@@ -168,4 +168,4 @@ export function LandingHero() {
</Container>
</Box>
);
}
}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { Text } from './Text';
import { Text } from '@/ui/Text';
export function HeaderContent() {
return (

View File

@@ -1,9 +1,9 @@
import React from 'react';
import Image from 'next/image';
import { Crown, Flag } from 'lucide-react';
import { Box } from './Box';
import { Text } from './Text';
import { Stack } from './Stack';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { Image } from '@/ui/Image';
import { mediaConfig } from '@/lib/config/mediaConfig';
interface LeaderboardItemProps {
@@ -80,7 +80,7 @@ export function LeaderboardItem({
{/* Avatar */}
<Box position="relative" width="9" height="9" rounded="full" overflow="hidden" border={true} borderColor="border-charcoal-outline">
<Image src={avatarUrl || mediaConfig.avatars.defaultFallback} alt={name} fill className="object-cover" />
<Image src={avatarUrl || mediaConfig.avatars.defaultFallback} alt={name} fill objectFit="cover" />
</Box>
{/* Info */}

View File

@@ -5,7 +5,7 @@ import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { LeaderboardItem } from '@/ui/LeaderboardItem';
import { LeaderboardItem } from '@/components/leaderboards/LeaderboardItem';
import { LeaderboardList } from '@/ui/LeaderboardList';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';

View File

@@ -1,5 +1,5 @@
import React, { ReactNode } from 'react';
import { Stack } from './Stack';
import { Stack } from '@/ui/Stack';
interface RankingListProps {
children: ReactNode;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Box } from './Box';
import { Text } from './Text';
import { Stack } from './Stack';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
interface RankingListItemProps {
name: string;

View File

@@ -2,7 +2,7 @@
import { routes } from '@/lib/routing/RouteConfig';
import { Card } from '@/ui/Card';
import { ChampionshipStandingsList } from '@/ui/ChampionshipStandingsList';
import { ChampionshipStandingsList } from '@/components/leagues/ChampionshipStandingsList';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Link } from '@/ui/Link';

View File

@@ -1,5 +1,5 @@
import React, { ReactNode } from 'react';
import { Stack } from './Stack';
import { Stack } from '@/ui/Stack';
interface ChampionshipStandingsListProps {
children: ReactNode;

View File

@@ -1,6 +1,6 @@
import { Trophy, Sparkles, LucideIcon } from 'lucide-react';
import { Card } from '@/ui/Card';
import { EmptyState as UiEmptyState } from '@/ui/EmptyState';
import { EmptyState as UiEmptyState } from '@/components/shared/state/EmptyState';
interface EmptyStateProps {
title: string;

View File

@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { Calendar, UserPlus, UserMinus, Shield, Flag, AlertTriangle } from 'lucide-react';
import { useLeagueRaces } from "@/hooks/league/useLeagueRaces";
import { ActivityFeedItem } from '@/ui/ActivityFeedItem';
import { ActivityFeedItem } from '@/components/feed/ActivityFeedItem';
import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';

View File

@@ -1,9 +1,9 @@
import React, { ReactNode } from 'react';
import { TableRow, TableCell } from './Table';
import { Box } from './Box';
import { Text } from './Text';
import { Badge } from './Badge';
import { DriverIdentity } from './DriverIdentity';
import { TableRow, TableCell } from '@/ui/Table';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Badge } from '@/ui/Badge';
import { DriverIdentity } from '@/components/drivers/DriverIdentity';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
interface LeagueMemberRowProps {
@@ -92,7 +92,7 @@ export function LeagueMemberRow({
</Text>
</TableCell>
{actions && (
<TableCell align="right">
<TableCell textAlign="right">
{actions}
</TableCell>
)}

View File

@@ -13,8 +13,8 @@ import { Text } from '@/ui/Text';
import { Select } from '@/ui/Select';
import { Button } from '@/ui/Button';
import { LeagueMemberTable } from '@/ui/LeagueMemberTable';
import { LeagueMemberRow } from '@/ui/LeagueMemberRow';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { LeagueMemberRow } from '@/components/leagues/LeagueMemberRow';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
interface LeagueMembersProps {
leagueId: string;

View File

@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { DriverSummaryPill } from '@/ui/DriverSummaryPillWrapper';
import { DriverSummaryPill } from '@/components/drivers/DriverSummaryPillWrapper';
import { Button } from '@/ui/Button';
import { UserCog } from 'lucide-react';
import { LeagueSettingsViewModel } from '@/lib/view-models/LeagueSettingsViewModel';

View File

@@ -7,7 +7,7 @@ import { useState } from 'react';
import type { LeagueScheduleRaceViewModel } from '@/lib/view-models/LeagueScheduleViewModel';
// Shared state components
import { StateContainer } from '@/ui/StateContainer';
import { StateContainer } from '@/components/shared/state/StateContainer';
import { useLeagueSchedule } from "@/hooks/league/useLeagueSchedule";
import { Calendar } from 'lucide-react';
import { Box } from '@/ui/Box';

View File

@@ -21,7 +21,7 @@ import {
import type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';
import type { Weekday } from '@/lib/types/Weekday';
import { Input } from '@/ui/Input';
import RangeField from '@/ui/RangeField';
import { RangeField } from '@/components/shared/RangeField';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';

View File

@@ -5,7 +5,7 @@ import { ProtestViewModel } from "@/lib/view-models/ProtestViewModel";
import { RaceViewModel } from "@/lib/view-models/RaceViewModel";
import { Box } from "@/ui/Box";
import { Card } from "@/ui/Card";
import { ProtestListItem } from "@/ui/ProtestListItem";
import { ProtestListItem } from "./ProtestListItem";
import { Stack } from "@/ui/Stack";
import { Text } from "@/ui/Text";
import { Flag } from "lucide-react";
@@ -21,7 +21,9 @@ interface PendingProtestsListProps {
export function PendingProtestsList({
protests,
drivers,
leagueId,
onReviewProtest,
}: PendingProtestsListProps) {
if (protests.length === 0) {
@@ -49,17 +51,25 @@ export function PendingProtestsList({
const daysSinceFiled = Math.floor((Date.now() - new Date(filedAt).getTime()) / (1000 * 60 * 60 * 24));
const isUrgent = daysSinceFiled > 2;
const protester = drivers[protest.protestingDriverId];
const accused = drivers[protest.accusedDriverId];
return (
<ProtestListItem
key={protest.id}
id={protest.id}
filedAt={filedAt}
description={protest.incident?.description || protest.description}
lap={protest.incident?.lap}
hasVideo={!!protest.proofVideoUrl}
protesterName={protester?.name || 'Unknown'}
protesterHref={`/drivers/${protest.protestingDriverId}`}
accusedName={accused?.name || 'Unknown'}
accusedHref={`/drivers/${protest.accusedDriverId}`}
status={protest.status}
isUrgent={isUrgent}
daysOld={daysSinceFiled}
href={`/leagues/${leagueId}/stewarding/protests/${protest.id}`}
lap={protest.incident?.lap ?? 0}
filedAtLabel={new Date(filedAt).toLocaleDateString()}
description={protest.incident?.description || protest.description}
proofVideoUrl={protest.proofVideoUrl || undefined}
isAdmin={true}
onReview={() => onReviewProtest(protest)}
/>
);
})}

View File

@@ -1,7 +1,7 @@
import { routes } from '@/lib/routing/RouteConfig';
import { ProtestListItem } from '@/ui/ProtestListItem';
import { ProtestListItem } from './ProtestListItem';
interface Protest {
id: string;

View File

@@ -1,14 +1,14 @@
import { AlertCircle, AlertTriangle, Video } from 'lucide-react';
import { Badge } from './Badge';
import { Box } from './Box';
import { Button } from './Button';
import { Card } from './Card';
import { Icon } from './Icon';
import { Link } from './Link';
import { Stack } from './Stack';
import { Text } from './Text';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import { Link } from '@/ui/Link';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface ProtestListItemProps {
protesterName: string;

View File

@@ -8,7 +8,7 @@ interface MockupStackProps {
index?: number;
}
export default function MockupStack({ children, index = 0 }: MockupStackProps) {
export function MockupStack({ children, index = 0 }: MockupStackProps) {
const shouldReduceMotion = useReducedMotion();
const [isMounted, setIsMounted] = useState(false);
const [isMobile, setIsMobile] = useState(true); // Default to mobile (no animations)

View File

@@ -3,11 +3,11 @@
import { AnimatePresence, motion, useReducedMotion } from 'framer-motion';
import { CheckCircle2, LucideIcon } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Box } from './Box';
import { Icon } from './Icon';
import { Stack } from './Stack';
import { Surface } from './Surface';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
export interface WorkflowStep {
id: number;

View File

@@ -1,7 +1,7 @@
import { User, Clock, ChevronRight } from 'lucide-react';
import { Input } from '@/ui/Input';
import { Heading } from '@/ui/Heading';
import { CountrySelect } from '@/ui/CountrySelect';
import { CountrySelect } from '@/components/shared/CountrySelect';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';

View File

@@ -1,7 +1,7 @@
import { Card } from '@/ui/Card';
import { DriverEntryRow } from '@/ui/DriverEntryRow';
import { DriverEntryRow } from '@/components/drivers/DriverEntryRow';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';

View File

@@ -6,7 +6,7 @@ import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card';
import { DateHeader } from '@/ui/DateHeader';
import { Icon } from '@/ui/Icon';
import { RaceListItem } from '@/ui/RaceListItem';
import { RaceListItem } from '@/components/races/RaceListItem';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Calendar, CheckCircle2, Clock, PlayCircle, XCircle } from 'lucide-react';

View File

@@ -1,13 +1,13 @@
import { ArrowRight, Car, ChevronRight, LucideIcon, Trophy, Zap } from 'lucide-react';
import { Badge } from './Badge';
import { Box } from './Box';
import { Heading } from './Heading';
import { Icon } from './Icon';
import { Link } from './Link';
import { Stack } from './Stack';
import { Text } from './Text';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Link } from '@/ui/Link';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface RaceListItemProps {
track: string;

View File

@@ -1,7 +1,7 @@
import { routes } from '@/lib/routing/RouteConfig';
import { RaceListItem as UiRaceListItem } from '@/ui/RaceListItem';
import { RaceListItem as UiRaceListItem } from '@/components/races/RaceListItem';
import { CheckCircle2, Clock, PlayCircle, XCircle } from 'lucide-react';
interface Race {

View File

@@ -1,11 +1,11 @@
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Box } from './Box';
import { Image } from './Image';
import { Stack } from './Stack';
import { Surface } from './Surface';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Image } from '@/ui/Image';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
interface ResultEntry {
position: number;
@@ -64,7 +64,7 @@ export function RaceResultRow({ result, points }: RaceResultRowProps) {
{/* Avatar */}
<Box position="relative" flexShrink={0}>
<Box width="10" height="10" rounded="full" overflow="hidden" border={isCurrentUser} borderColor="border-primary-blue/50" className={isCurrentUser ? 'border-2' : ''}>
<Image src={driverAvatar} alt={driverName} width={40} height={40} objectFit="cover" />
<Image src={driverAvatar} alt={driverName} width={40} height={40} fullWidth fullHeight objectFit="cover" />
</Box>
<Box position="absolute" bottom="-0.5" right="-0.5" width="5" height="5" rounded="full" bg="bg-deep-graphite" display="flex" center style={{ fontSize: '0.625rem' }}>
{CountryFlagDisplay.fromCountryCode(country).toString()}

View File

@@ -2,14 +2,14 @@
import { routes } from '@/lib/routing/RouteConfig';
import { Card } from '@/ui/Card';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Link } from '@/ui/Link';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { UpcomingRaceItem } from '@/ui/UpcomingRaceItem';
import { UpcomingRacesList } from '@/ui/UpcomingRacesList';
import { UpcomingRacesList } from '@/components/races/UpcomingRacesList';
import { Calendar } from 'lucide-react';
interface UpcomingRace {

View File

@@ -1,5 +1,5 @@
import React, { ReactNode } from 'react';
import { Stack } from './Stack';
import { Stack } from '@/ui/Stack';
interface UpcomingRacesListProps {
children: ReactNode;

View File

@@ -2,7 +2,7 @@
import { Check, ChevronDown, Globe, Search } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
import { CountryFlag } from './CountryFlag';
import { CountryFlag } from '@/ui/CountryFlag';
export interface Country {
code: string;

View File

@@ -20,7 +20,7 @@ interface RangeFieldProps {
compact?: boolean;
}
export default function RangeField({
export function RangeField({
label,
value,
min,

View File

@@ -1,7 +1,7 @@
import { Button } from './Button';
import { EmptyStateProps } from './state-types';
import { Button } from '@/ui/Button';
import { EmptyStateProps } from '@/ui/state-types';
// Illustration components (simple SVG representations)
const Illustrations = {

View File

@@ -2,14 +2,14 @@
import { ApiError } from '@/lib/api/base/ApiError';
import { AlertCircle, ArrowLeft, Home, RefreshCw } from 'lucide-react';
import { Box } from './Box';
import { Button } from './Button';
import { Heading } from './Heading';
import { Icon } from './Icon';
import { Stack } from './Stack';
import { ErrorDisplayAction, ErrorDisplayProps } from './state-types';
import { Surface } from './Surface';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { ErrorDisplayAction, ErrorDisplayProps } from '@/ui/state-types';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
export function ErrorDisplay({
error,

View File

@@ -1,9 +1,9 @@
import { Box } from './Box';
import { Stack } from './Stack';
import { LoadingWrapperProps } from './state-types';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { LoadingWrapperProps } from '@/ui/state-types';
import { Text } from '@/ui/Text';
/**
* LoadingWrapper Component

View File

@@ -1,8 +1,8 @@
import React, { ReactNode } from 'react';
import { ApiError } from '@/lib/api/base/ApiError';
import { LoadingWrapper } from '@/ui/LoadingWrapper';
import { ErrorDisplay } from '@/ui/ErrorDisplay';
import { EmptyState } from '@/ui/EmptyState';
import { LoadingWrapper } from '@/components/shared/state/LoadingWrapper';
import { ErrorDisplay } from '@/components/shared/state/ErrorDisplay';
import { EmptyState } from '@/components/shared/state/EmptyState';
import { Box } from '@/ui/Box';
import { Inbox, List, LucideIcon } from 'lucide-react';

View File

@@ -2,9 +2,9 @@
import React from 'react';
import { StateContainerProps, StateContainerConfig } from '@/ui/state-types';
import { LoadingWrapper } from '@/ui/LoadingWrapper';
import { ErrorDisplay } from '@/ui/ErrorDisplay';
import { EmptyState } from '@/ui/EmptyState';
import { LoadingWrapper } from '@/components/shared/state/LoadingWrapper';
import { ErrorDisplay } from '@/components/shared/state/ErrorDisplay';
import { EmptyState } from '@/components/shared/state/EmptyState';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text';
@@ -159,6 +159,11 @@ export function StateContainer<T>({
);
}
// Custom success render
if (config?.customRender?.success) {
return <>{config.customRender.success(data as T)}</>;
}
// At this point, data is guaranteed to be non-null and non-undefined
return <>{children(data as T)}</>;
}
@@ -383,4 +388,4 @@ export function GridStateContainer<T>({
{children}
</StateContainer>
);
}
}

View File

@@ -1,7 +1,7 @@
'use client';
import React from 'react';
import { PageWrapper, PageWrapperProps } from './PageWrapper';
import { PageWrapper, PageWrapperProps } from '@/components/shared/state/PageWrapper';
/**
* Stateful Page Wrapper - CLIENT SIDE ONLY
@@ -56,4 +56,4 @@ export function StatefulPageWrapper<TData>({
}
// Re-export types for convenience
export type { PageWrapperProps, PageWrapperLoadingConfig, PageWrapperErrorConfig, PageWrapperEmptyConfig } from './PageWrapper';
export type { PageWrapperProps, PageWrapperLoadingConfig, PageWrapperErrorConfig, PageWrapperEmptyConfig } from '@/components/shared/state/PageWrapper';

View File

@@ -3,7 +3,7 @@
import { routes } from '@/lib/routing/RouteConfig';
import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
import { FriendItem } from '@/ui/FriendItem';
import { FriendsList } from '@/ui/FriendsList';
import { Heading } from '@/ui/Heading';

View File

@@ -2,7 +2,7 @@
import React from 'react';
import { LucideIcon } from 'lucide-react';
import { BenefitCard } from '@/ui/BenefitCard';
import { BenefitCard } from '@/components/landing/BenefitCard';
interface SponsorBenefitCardProps {
icon: LucideIcon;

View File

@@ -3,11 +3,16 @@
import { motion, useReducedMotion } from 'framer-motion';
import { Building2 } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Box } from './Box';
import { Heading } from './Heading';
import { Icon } from './Icon';
import { Text } from './Text';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text';
interface SponsorHeroProps {
title: string;
subtitle: string;
children?: React.ReactNode;
}
export function SponsorHero({ title, subtitle, children }: SponsorHeroProps) {
const shouldReduceMotion = useReducedMotion();

View File

@@ -8,7 +8,7 @@ import {
Car,
TrendingUp,
} from 'lucide-react';
import { WorkflowMockup, WorkflowStep } from '@/ui/WorkflowMockup';
import { WorkflowMockup, WorkflowStep } from '@/components/mockups/WorkflowMockup';
const WORKFLOW_STEPS: WorkflowStep[] = [
{

View File

@@ -12,7 +12,7 @@ import { Heading } from '@/ui/Heading';
import { JoinRequestList } from '@/ui/JoinRequestList';
import { JoinRequestItem } from '@/ui/JoinRequestItem';
import { DangerZone } from '@/ui/DangerZone';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
import { useTeamJoinRequests, useUpdateTeam, useApproveJoinRequest, useRejectJoinRequest } from "@/hooks/team";
import type { TeamJoinRequestViewModel } from '@/lib/view-models/TeamJoinRequestViewModel';

View File

@@ -2,11 +2,11 @@
import { Users } from 'lucide-react';
import { ReactNode } from 'react';
import { Badge } from './Badge';
import { Box } from './Box';
import { Heading } from './Heading';
import { Stack } from './Stack';
import { Text } from './Text';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface TeamHeroSectionProps {
title: ReactNode;

View File

@@ -5,8 +5,8 @@ import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon';
import { SkillLevelButton } from '@/ui/SkillLevelButton';
import { Stack } from '@/ui/Stack';
import { TeamHeroSection as UiTeamHeroSection } from '@/ui/TeamHeroSection';
import { TeamHeroStats } from '@/ui/TeamHeroStats';
import { TeamHeroSection as UiTeamHeroSection } from '@/components/teams/TeamHeroSection';
import { TeamHeroStats } from '@/components/teams/TeamHeroStats';
import { Text } from '@/ui/Text';
import {
Crown,

View File

@@ -1,9 +1,9 @@
import React from 'react';
import { Users, UserPlus } from 'lucide-react';
import { Box } from './Box';
import { Text } from './Text';
import { Icon } from './Icon';
import { Stack } from './Stack';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
interface TeamHeroStatsProps {
teamCount: number;

View File

@@ -1,8 +1,8 @@
import React from 'react';
import { Box } from './Box';
import { Stack } from './Stack';
import { Text } from './Text';
import { Image } from './Image';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Image } from '@/ui/Image';
interface TeamIdentityProps {
name: string;
@@ -20,6 +20,9 @@ export function TeamIdentity({ name, logoUrl, performanceLevel, category }: Team
alt={name}
width={40}
height={40}
fullWidth
fullHeight
objectFit="cover"
/>
</Box>
<Box flex={1}>

View File

@@ -2,13 +2,13 @@ import React from 'react';
import { Trophy, Crown, Users } from 'lucide-react';
import type { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';
import { getMediaUrl } from '@/lib/utilities/media';
import { Box } from './Box';
import { Stack } from './Stack';
import { Text } from './Text';
import { Icon } from './Icon';
import { Button } from './Button';
import { Image } from './Image';
import { Podium, PodiumItem } from './Podium';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Icon } from '@/ui/Icon';
import { Button } from '@/ui/Button';
import { Image } from '@/ui/Image';
import { Podium, PodiumItem } from '@/ui/Podium';
interface TeamPodiumProps {
teams: TeamSummaryViewModel[];

View File

@@ -1,13 +1,13 @@
import React from 'react';
import { Users } from 'lucide-react';
import { Box } from './Box';
import { Stack } from './Stack';
import { Text } from './Text';
import { Icon } from './Icon';
import { Card } from './Card';
import { Table, TableHead, TableBody, TableRow, TableHeader, TableCell } from './Table';
import { RankBadge } from './RankBadge';
import { TeamIdentity } from './TeamIdentity';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Icon } from '@/ui/Icon';
import { Card } from '@/ui/Card';
import { Table, TableHead, TableBody, TableRow, TableHeader, TableCell } from '@/ui/Table';
import { RankBadge } from '@/ui/RankBadge';
import { TeamIdentity } from '@/components/teams/TeamIdentity';
import { getMediaUrl } from '@/lib/utilities/media';
interface Team {

View File

@@ -12,8 +12,8 @@ import { Select } from '@/ui/Select';
import { Button } from '@/ui/Button';
import { routes } from '@/lib/routing/RouteConfig';
import { TeamRosterList } from '@/ui/TeamRosterList';
import { TeamRosterItem } from '@/ui/TeamRosterItem';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { TeamRosterItem } from '@/components/teams/TeamRosterItem';
import { MinimalEmptyState } from '@/components/shared/state/EmptyState';
import { sortMembers } from '@/lib/utilities/roster-utils';
export type TeamRole = 'owner' | 'admin' | 'member';

View File

@@ -1,8 +1,8 @@
import React, { ReactNode } from 'react';
import { Box } from './Box';
import { Stack } from './Stack';
import { Text } from './Text';
import { DriverIdentity } from './DriverIdentity';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { DriverIdentity } from '@/components/drivers/DriverIdentity';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
interface TeamRosterItemProps {

View File

@@ -5,8 +5,8 @@ import { useTeamStandings } from "@/hooks/team/useTeamStandings";
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { StandingsList } from '@/ui/StandingsList';
import { LoadingWrapper } from '@/ui/LoadingWrapper';
import { EmptyState } from '@/ui/EmptyState';
import { LoadingWrapper } from '@/components/shared/state/LoadingWrapper';
import { EmptyState } from '@/components/shared/state/EmptyState';
import { Trophy } from 'lucide-react';
interface TeamStandingsProps {

View File

@@ -10,7 +10,7 @@ import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Heading } from '@/ui/Heading';
import { Grid } from '@/ui/Grid';
import { BenefitCard } from '@/ui/BenefitCard';
import { BenefitCard } from '@/components/landing/BenefitCard';
interface Benefit {
icon: LucideIcon;

View File

@@ -6,12 +6,12 @@ import { Box } from '@/ui/Box';
import { Container } from '@/ui/Container';
import { Grid } from '@/ui/Grid';
import { GridItem } from '@/ui/GridItem';
import { DashboardHero } from '@/ui/DashboardHeroWrapper';
import { NextRaceCard } from '@/ui/NextRaceCardWrapper';
import { ChampionshipStandings } from '@/ui/ChampionshipStandings';
import { ActivityFeed } from '@/ui/ActivityFeed';
import { UpcomingRaces } from '@/ui/UpcomingRaces';
import { FriendsSidebar } from '@/ui/FriendsSidebar';
import { DashboardHero } from '@/components/dashboard/DashboardHeroWrapper';
import { NextRaceCard } from '@/components/races/NextRaceCardWrapper';
import { ChampionshipStandings } from '@/components/leagues/ChampionshipStandings';
import { ActivityFeed } from '@/components/feed/ActivityFeed';
import { UpcomingRaces } from '@/components/races/UpcomingRaces';
import { FriendsSidebar } from '@/components/social/FriendsSidebar';
import { Stack } from '@/ui/Stack';
interface DashboardTemplateProps {

View File

@@ -2,12 +2,12 @@
import { RatingBreakdown } from '@/ui/RatingBreakdown';
import { Breadcrumbs } from '@/ui/Breadcrumbs';
import { AchievementGrid } from '@/ui/AchievementGrid';
import { AchievementGrid } from '@/components/achievements/AchievementGrid';
import { CareerStats } from '@/ui/CareerStats';
import { FriendsPreview } from '@/ui/FriendsPreview';
import { FriendsPreview } from '@/components/social/FriendsPreview';
import { PerformanceOverview } from '@/ui/PerformanceOverview';
import { ProfileBio } from '@/ui/ProfileBio';
import { ProfileHero } from '@/ui/ProfileHero';
import { ProfileHero } from '@/components/drivers/ProfileHero';
import { ProfileTabs, type ProfileTab } from '@/ui/ProfileTabs';
import { RacingProfile } from '@/ui/RacingProfile';
import { TeamMembershipGrid } from '@/ui/TeamMembershipGrid';

Some files were not shown because too many files have changed in this diff Show More