website refactor

This commit is contained in:
2026-01-18 23:24:30 +01:00
parent aeaa43f4d3
commit 182056a57b
487 changed files with 1783 additions and 2170 deletions

View File

@@ -6,7 +6,7 @@ import { AdminUsersTemplate } from '@/templates/AdminUsersTemplate';
import { AdminUsersViewData } from '@/lib/view-data/AdminUsersViewData'; import { AdminUsersViewData } from '@/lib/view-data/AdminUsersViewData';
import { updateUserStatus, deleteUser } from '@/app/actions/adminActions'; import { updateUserStatus, deleteUser } from '@/app/actions/adminActions';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { ConfirmDialog } from '@/components/shared/ux/ConfirmDialog'; import { ConfirmDialog } from '@/ui/ConfirmDialog';
interface AdminUsersWrapperProps { interface AdminUsersWrapperProps {
initialViewData: AdminUsersViewData; initialViewData: AdminUsersViewData;

View File

@@ -3,7 +3,7 @@
import type { DriversViewData } from '@/lib/types/view-data/DriversViewData'; import type { DriversViewData } from '@/lib/types/view-data/DriversViewData';
import { DriversTemplate } from '@/templates/DriversTemplate'; import { DriversTemplate } from '@/templates/DriversTemplate';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';

View File

@@ -4,7 +4,7 @@ import type { ProfileTab } from '@/components/profile/ProfileTabs';
import type { DriverProfileViewData } from '@/lib/types/view-data/DriverProfileViewData'; import type { DriverProfileViewData } from '@/lib/types/view-data/DriverProfileViewData';
import { DriverProfileTemplate } from '@/templates/DriverProfileTemplate'; import { DriverProfileTemplate } from '@/templates/DriverProfileTemplate';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';

View File

@@ -4,26 +4,26 @@ import { LeagueCard } from '@/components/leagues/LeagueCardWrapper';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import type { LeaguesViewData } from '@/lib/view-data/LeaguesViewData'; import type { LeaguesViewData } from '@/lib/view-data/LeaguesViewData';
import { LeagueSummaryViewModel } from '@/lib/view-models/LeagueSummaryViewModel'; import { LeagueSummaryViewModel } from '@/lib/view-models/LeagueSummaryViewModel';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box'; import { Stack } from '@/ui/Stack';
import { Stack } from '@/ui/primitives/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { import {
Award, Award,
Clock, Clock,
Flag, Flag,
Flame, Flame,
Globe, Globe,
Plus, Plus,
Search, Search,
Sparkles, Sparkles,
Target, Target,
Timer, Timer,
Trophy, Trophy,
Users, Users,
type LucideIcon, type LucideIcon,
} from 'lucide-react'; } from 'lucide-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import React, { useState } from 'react'; import React, { useState } from 'react';

View File

@@ -1,26 +1,26 @@
'use client'; 'use client';
import { import {
createRaceAction, createRaceAction,
deleteRaceAction, deleteRaceAction,
publishScheduleAction, publishScheduleAction,
unpublishScheduleAction, unpublishScheduleAction,
updateRaceAction updateRaceAction
} from '@/app/actions/leagueScheduleActions'; } from '@/app/actions/leagueScheduleActions';
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { ConfirmDialog } from '@/components/shared/ux/ConfirmDialog'; import { ConfirmDialog } from '@/ui/ConfirmDialog';
import { import {
useLeagueAdminSchedule, useLeagueAdminSchedule,
useLeagueAdminStatus, useLeagueAdminStatus,
useLeagueSeasons useLeagueSeasons
} from "@/hooks/league/useLeagueScheduleAdminPageData"; } from "@/hooks/league/useLeagueScheduleAdminPageData";
import { useEffectiveDriverId } from "@/hooks/useEffectiveDriverId"; import { useEffectiveDriverId } from "@/hooks/useEffectiveDriverId";
import { RaceScheduleCommandModel } from '@/lib/command-models/leagues/RaceScheduleCommandModel'; import { RaceScheduleCommandModel } from '@/lib/command-models/leagues/RaceScheduleCommandModel';
import { LeagueAdminScheduleTemplate } from '@/templates/LeagueAdminScheduleTemplate'; import { LeagueAdminScheduleTemplate } from '@/templates/LeagueAdminScheduleTemplate';
import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Box } from '@/ui/primitives/Box'; import { Stack } from '@/ui/Stack';
import { Stack } from '@/ui/primitives/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { useParams, useRouter } from 'next/navigation'; import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';

View File

@@ -11,10 +11,10 @@ import type { StewardingViewData } from '@/lib/view-data/leagues/StewardingViewD
import { DriverViewModel } from '@/lib/view-models/DriverViewModel'; import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { ProtestViewModel } from '@/lib/view-models/ProtestViewModel'; import { ProtestViewModel } from '@/lib/view-models/ProtestViewModel';
import { RaceViewModel } from '@/lib/view-models/RaceViewModel'; import { RaceViewModel } from '@/lib/view-models/RaceViewModel';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Box } from '@/ui/primitives/Box'; import { Stack } from '@/ui/Stack';
import { Stack } from '@/ui/primitives/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';

View File

@@ -7,44 +7,44 @@ import { PROTEST_SERVICE_TOKEN } from '@/lib/di/tokens';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { import {
AlertCircle, AlertCircle,
AlertTriangle, AlertTriangle,
ArrowLeft, ArrowLeft,
Calendar, Calendar,
CheckCircle, CheckCircle,
ChevronDown, ChevronDown,
Clock, Clock,
ExternalLink, ExternalLink,
Flag, Flag,
Gavel, Gavel,
Grid3x3, Grid3x3,
MapPin, MapPin,
MessageCircle, MessageCircle,
Send, Send,
Shield, Shield,
ShieldAlert, ShieldAlert,
TrendingDown, TrendingDown,
User, User,
Video, Video,
XCircle, XCircle,
type LucideIcon type LucideIcon
} from 'lucide-react'; } from 'lucide-react';
import { useParams, useRouter } from 'next/navigation'; import { useParams, useRouter } from 'next/navigation';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
// Shared state components // Shared state components
import { LoadingWrapper } from '@/components/shared/state/LoadingWrapper'; import { LoadingWrapper } from '@/ui/LoadingWrapper';
import { StateContainer } from '@/components/shared/state/StateContainer'; import { StateContainer } from '@/ui/StateContainer';
import { useLeagueAdminStatus } from "@/hooks/league/useLeagueAdminStatus"; import { useLeagueAdminStatus } from "@/hooks/league/useLeagueAdminStatus";
import { useProtestDetail } from "@/hooks/league/useProtestDetail"; import { useProtestDetail } from "@/hooks/league/useProtestDetail";
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { GridItem } from '@/ui/primitives/GridItem'; import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon as UIIcon } from '@/ui/Icon'; import { Icon as UIIcon } from '@/ui/Icon';
import { Link as UILink } from '@/ui/Link'; import { Link as UILink } from '@/ui/Link';
import { Box } from '@/ui/primitives/Box'; import { Grid } from '@/ui/Grid';
import { Grid } from '@/ui/primitives/Grid'; import { GridItem } from '@/ui/GridItem';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
type PenaltyUiConfig = { type PenaltyUiConfig = {

View File

@@ -2,15 +2,15 @@
import { WalletSummaryPanel } from '@/components/leagues/WalletSummaryPanel'; import { WalletSummaryPanel } from '@/components/leagues/WalletSummaryPanel';
import type { LeagueWalletViewData } from '@/lib/view-data/leagues/LeagueWalletViewData'; import type { LeagueWalletViewData } from '@/lib/view-data/leagues/LeagueWalletViewData';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon as UIIcon } from '@/ui/Icon'; import { Icon as UIIcon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box'; import { Stack } from '@/ui/Stack';
import { Stack } from '@/ui/primitives/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { import {
Download Download
} from 'lucide-react'; } from 'lucide-react';
interface WalletTemplateProps { interface WalletTemplateProps {

View File

@@ -2,28 +2,28 @@
import { useAuth } from '@/components/auth/AuthContext'; import { useAuth } from '@/components/auth/AuthContext';
import { LeagueReviewSummary } from '@/components/leagues/LeagueReviewSummary'; import { LeagueReviewSummary } from '@/components/leagues/LeagueReviewSummary';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box'; import { Stack } from '@/ui/Stack';
import { Stack } from '@/ui/primitives/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { import {
AlertCircle, AlertCircle,
Award, Award,
Calendar, Calendar,
Check, Check,
CheckCircle2, CheckCircle2,
ChevronLeft, ChevronLeft,
ChevronRight, ChevronRight,
FileText, FileText,
Loader2, Loader2,
Scale, Scale,
Sparkles, Sparkles,
Trophy, Trophy,
Users, Users,
} from 'lucide-react'; } from 'lucide-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { FormEvent, useCallback, useEffect, useState } from 'react'; import { FormEvent, useCallback, useEffect, useState } from 'react';
@@ -33,8 +33,8 @@ import { LeagueWizardCommandModel } from '@/lib/command-models/leagues/LeagueWiz
import { LeagueBasicsSection } from '@/components/leagues/LeagueBasicsSection'; import { LeagueBasicsSection } from '@/components/leagues/LeagueBasicsSection';
import { LeagueDropSection } from '@/components/leagues/LeagueDropSection'; import { LeagueDropSection } from '@/components/leagues/LeagueDropSection';
import { import {
ChampionshipsSection, ChampionshipsSection,
ScoringPatternSection ScoringPatternSection
} from '@/components/leagues/LeagueScoringSection'; } from '@/components/leagues/LeagueScoringSection';
import { LeagueStewardingSection } from '@/components/leagues/LeagueStewardingSection'; import { LeagueStewardingSection } from '@/components/leagues/LeagueStewardingSection';
import { LeagueStructureSection } from '@/components/leagues/LeagueStructureSection'; import { LeagueStructureSection } from '@/components/leagues/LeagueStructureSection';

View File

@@ -1,4 +1,4 @@
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { HomeTemplate, type HomeViewData } from '@/templates/HomeTemplate'; import { HomeTemplate, type HomeViewData } from '@/templates/HomeTemplate';
import { PageDataFetcher } from '@/lib/page/PageDataFetcher'; import { PageDataFetcher } from '@/lib/page/PageDataFetcher';
import { HomePageQuery } from '@/lib/page-queries/HomePageQuery'; import { HomePageQuery } from '@/lib/page-queries/HomePageQuery';

View File

@@ -2,6 +2,7 @@
import { UploadDropzone } from '@/components/media/UploadDropzone'; import { UploadDropzone } from '@/components/media/UploadDropzone';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
@@ -9,7 +10,6 @@ import { Heading } from '@/ui/Heading';
import { MediaMetaPanel, mapMediaMetadata } from '@/ui/MediaMetaPanel'; import { MediaMetaPanel, mapMediaMetadata } from '@/ui/MediaMetaPanel';
import { MediaPreviewCard } from '@/ui/MediaPreviewCard'; import { MediaPreviewCard } from '@/ui/MediaPreviewCard';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
import Link from 'next/link'; import Link from 'next/link';
import { useState } from 'react'; import { useState } from 'react';

View File

@@ -1,11 +1,11 @@
'use client'; 'use client';
import { InlineNotice } from '@/components/shared/ux/InlineNotice'; import { InlineNotice } from '@/ui/InlineNotice';
import { ProgressLine } from '@/components/shared/ux/ProgressLine'; import { ProgressLine } from '@/ui/ProgressLine';
import type { Result } from '@/lib/contracts/Result'; import type { Result } from '@/lib/contracts/Result';
import type { ProfileViewData } from '@/lib/view-data/ProfileViewData'; import type { ProfileViewData } from '@/lib/view-data/ProfileViewData';
import { ProfileSettingsTemplate } from '@/templates/ProfileSettingsTemplate'; import { ProfileSettingsTemplate } from '@/templates/ProfileSettingsTemplate';
import { Box } from '@/ui/primitives/Box'; import { Box } from '@/ui/Box';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';

View File

@@ -1,11 +1,11 @@
'use client'; 'use client';
import { InlineNotice } from '@/components/shared/ux/InlineNotice'; import { InlineNotice } from '@/ui/InlineNotice';
import { ProgressLine } from '@/components/shared/ux/ProgressLine'; import { ProgressLine } from '@/ui/ProgressLine';
import type { Result } from '@/lib/contracts/Result'; import type { Result } from '@/lib/contracts/Result';
import type { SponsorshipRequestsViewData } from '@/lib/view-data/SponsorshipRequestsViewData'; import type { SponsorshipRequestsViewData } from '@/lib/view-data/SponsorshipRequestsViewData';
import { SponsorshipRequestsTemplate } from '@/templates/SponsorshipRequestsTemplate'; import { SponsorshipRequestsTemplate } from '@/templates/SponsorshipRequestsTemplate';
import { Box } from '@/ui/primitives/Box'; import { Box } from '@/ui/Box';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';

View File

@@ -1,5 +1,5 @@
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { RaceDetailPageQuery } from '@/lib/page-queries/races/RaceDetailPageQuery'; import { RaceDetailPageQuery } from '@/lib/page-queries/races/RaceDetailPageQuery';
import { RaceDetailPageClient } from './RaceDetailPageClient'; import { RaceDetailPageClient } from './RaceDetailPageClient';

View File

@@ -1,5 +1,5 @@
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { RaceResultsPageQuery } from '@/lib/page-queries/races/RaceResultsPageQuery'; import { RaceResultsPageQuery } from '@/lib/page-queries/races/RaceResultsPageQuery';
import { RaceResultsPageClient } from './RaceResultsPageClient'; import { RaceResultsPageClient } from './RaceResultsPageClient';

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { RaceStewardingTemplate, type StewardingTab } from '@/templates/RaceStewardingTemplate'; import { RaceStewardingTemplate, type StewardingTab } from '@/templates/RaceStewardingTemplate';
import { RaceStewardingPageQuery } from '@/lib/page-queries/races/RaceStewardingPageQuery'; import { RaceStewardingPageQuery } from '@/lib/page-queries/races/RaceStewardingPageQuery';
import { type RaceStewardingViewData } from '@/lib/view-data/races/RaceStewardingViewData'; import { type RaceStewardingViewData } from '@/lib/view-data/races/RaceStewardingViewData';

View File

@@ -2,7 +2,7 @@
import { useState } from 'react'; import { useState } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { StatefulPageWrapper } from '@/components/shared/state/StatefulPageWrapper'; import { StatefulPageWrapper } from '@/ui/StatefulPageWrapper';
import { RacesAllTemplate } from '@/templates/RacesAllTemplate'; import { RacesAllTemplate } from '@/templates/RacesAllTemplate';
import { useAllRacesPageData } from '@/hooks/race/useAllRacesPageData'; import { useAllRacesPageData } from '@/hooks/race/useAllRacesPageData';
import { type RacesViewData, type RaceViewData } from '@/lib/view-data/RacesViewData'; import { type RacesViewData, type RaceViewData } from '@/lib/view-data/RacesViewData';

View File

@@ -2,10 +2,10 @@
import { useSponsorBilling } from "@/hooks/sponsor/useSponsorBilling"; import { useSponsorBilling } from "@/hooks/sponsor/useSponsorBilling";
import { SponsorBillingTemplate } from "@/templates/SponsorBillingTemplate"; import { SponsorBillingTemplate } from "@/templates/SponsorBillingTemplate";
import { Box } from "@/ui/primitives/Box"; import { Box } from "@/ui/Box";
import { Text } from "@/ui/Text";
import { Button } from "@/ui/Button"; import { Button } from "@/ui/Button";
import { DollarSign, AlertTriangle, Calendar, TrendingUp } from "lucide-react"; import { Text } from "@/ui/Text";
import { AlertTriangle, Calendar, DollarSign, TrendingUp } from "lucide-react";
export default function SponsorBillingPage() { export default function SponsorBillingPage() {
const { data: billingData, isLoading, error, retry } = useSponsorBilling('demo-sponsor-1'); const { data: billingData, isLoading, error, retry } = useSponsorBilling('demo-sponsor-1');
@@ -40,11 +40,6 @@ export default function SponsorBillingPage() {
console.log('Setting default payment method:', methodId); console.log('Setting default payment method:', methodId);
}; };
const handleRemoveMethod = (methodId: string) => {
if (window.confirm('Remove this payment method?')) {
console.log('Removing payment method:', methodId);
}
};
const handleDownloadInvoice = (invoiceId: string) => { const handleDownloadInvoice = (invoiceId: string) => {
console.log('Downloading invoice:', invoiceId); console.log('Downloading invoice:', invoiceId);

View File

@@ -1,11 +1,11 @@
'use client'; 'use client';
import { useState } from 'react';
import { useSponsorSponsorships } from "@/hooks/sponsor/useSponsorSponsorships"; import { useSponsorSponsorships } from "@/hooks/sponsor/useSponsorSponsorships";
import { SponsorCampaignsTemplate, SponsorshipType } from "@/templates/SponsorCampaignsTemplate"; import { SponsorCampaignsTemplate, SponsorshipType } from "@/templates/SponsorCampaignsTemplate";
import { Box } from "@/ui/primitives/Box"; import { Box } from "@/ui/Box";
import { Text } from "@/ui/Text";
import { Button } from "@/ui/Button"; import { Button } from "@/ui/Button";
import { Text } from "@/ui/Text";
import { useState } from 'react';
export default function SponsorCampaignsPage() { export default function SponsorCampaignsPage() {
const [typeFilter, setTypeFilter] = useState<SponsorshipType>('all'); const [typeFilter, setTypeFilter] = useState<SponsorshipType>('all');

View File

@@ -1,5 +1,5 @@
import { createRouteGuard } from '@/lib/auth/createRouteGuard'; import { createRouteGuard } from '@/lib/auth/createRouteGuard';
import { Box } from '@/ui/primitives/Box'; import { Box } from '@/ui/Box';
import { headers } from 'next/headers'; import { headers } from 'next/headers';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';

View File

@@ -1,5 +1,5 @@
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { SponsorLeagueDetailPageClient } from './SponsorLeagueDetailPageClient'; import { SponsorLeagueDetailPageClient } from './SponsorLeagueDetailPageClient';
import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient'; import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter'; import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';

View File

@@ -1,4 +1,4 @@
import { PageWrapper } from '@/components/shared/state/PageWrapper'; import { PageWrapper } from '@/ui/PageWrapper';
import { SponsorLeaguesPageClient } from './SponsorLeaguesPageClient'; import { SponsorLeaguesPageClient } from './SponsorLeaguesPageClient';
import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient'; import { SponsorsApiClient } from '@/lib/api/sponsors/SponsorsApiClient';
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter'; import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';

View File

@@ -3,7 +3,7 @@
import { useState } from 'react'; import { useState } from 'react';
import { SponsorSettingsTemplate } from '@/templates/SponsorSettingsTemplate'; import { SponsorSettingsTemplate } from '@/templates/SponsorSettingsTemplate';
import { logoutAction } from '@/app/actions/logoutAction'; import { logoutAction } from '@/app/actions/logoutAction';
import { ConfirmDialog } from '@/components/shared/ux/ConfirmDialog'; import { ConfirmDialog } from '@/ui/ConfirmDialog';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { logger } from '@/lib/infrastructure/logging/logger'; import { logger } from '@/lib/infrastructure/logging/logger';

View File

@@ -5,31 +5,31 @@ import { SponsorHero } from '@/components/sponsors/SponsorHero';
import { SponsorWorkflowMockup } from '@/components/sponsors/SponsorWorkflowMockup'; import { SponsorWorkflowMockup } from '@/components/sponsors/SponsorWorkflowMockup';
import { SponsorSignupCommandModel } from '@/lib/command-models/sponsors/SponsorSignupCommandModel'; import { SponsorSignupCommandModel } from '@/lib/command-models/sponsors/SponsorSignupCommandModel';
import { siteConfig } from '@/lib/siteConfig'; import { siteConfig } from '@/lib/siteConfig';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box'; import { Stack } from '@/ui/Stack';
import { Stack } from '@/ui/primitives/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { motion, useReducedMotion } from 'framer-motion'; import { motion, useReducedMotion } from 'framer-motion';
import { import {
ArrowRight, ArrowRight,
BarChart3, BarChart3,
Building2, Building2,
Car, Car,
CheckCircle2, CheckCircle2,
Eye, Eye,
Flag, Flag,
Globe, Globe,
Mail, Mail,
Megaphone, Megaphone,
Shield, Shield,
Target, Target,
TrendingUp, TrendingUp,
Trophy, Trophy,
Upload, Upload,
Users Users
} from 'lucide-react'; } from 'lucide-react';
import { useState } from 'react'; import { useState } from 'react';

View File

@@ -4,7 +4,7 @@ import { CreateTeamForm } from '@/components/teams/CreateTeamForm';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Section } from '@/ui/Section'; import { Section } from '@/ui/Section';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';

View File

@@ -2,7 +2,7 @@ import { Badge } from '@/ui/Badge';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Hash, LucideIcon, Percent, Search, Star, Trophy } from 'lucide-react'; import { Hash, LucideIcon, Percent, Search, Star, Trophy } from 'lucide-react';

View File

@@ -4,7 +4,7 @@ import { Input } from '@/ui/Input';
import { ControlBar } from '@/ui/ControlBar'; import { ControlBar } from '@/ui/ControlBar';
import { Select } from '@/ui/Select'; import { Select } from '@/ui/Select';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Group } from '@/ui/Group'; import { ButtonGroup } from '@/ui/ButtonGroup';
import { useState } from 'react'; import { useState } from 'react';
export function ActionFiltersBar() { export function ActionFiltersBar() {
@@ -12,39 +12,41 @@ export function ActionFiltersBar() {
return ( return (
<ControlBar <ControlBar
actions={ leftContent={
<Input <Input
placeholder="SEARCH_ID..." placeholder="SEARCH_ID..."
/> />
} }
> >
<Group direction="row" align="center" gap={2}> <ButtonGroup gap={4}>
<Text size="xs" variant="low" weight="bold" uppercase>Filter:</Text> <ButtonGroup gap={2}>
<Select <Text size="xs" variant="low" weight="bold" uppercase>Filter:</Text>
options={[ <Select
{ label: 'All Types', value: 'all' }, options={[
{ label: 'User Update', value: 'user' }, { label: 'All Types', value: 'all' },
{ label: 'Onboarding', value: 'onboarding' } { label: 'User Update', value: 'user' },
]} { label: 'Onboarding', value: 'onboarding' }
value={filter} ]}
onChange={(e) => setFilter(e.target.value)} value={filter}
fullWidth={false} onChange={(e) => setFilter(e.target.value)}
/> fullWidth={false}
</Group> />
<Group direction="row" align="center" gap={2}> </ButtonGroup>
<Text size="xs" variant="low" weight="bold" uppercase>Status:</Text> <ButtonGroup gap={2}>
<Select <Text size="xs" variant="low" weight="bold" uppercase>Status:</Text>
options={[ <Select
{ label: 'All Status', value: 'all' }, options={[
{ label: 'Completed', value: 'completed' }, { label: 'All Status', value: 'all' },
{ label: 'Pending', value: 'pending' }, { label: 'Completed', value: 'completed' },
{ label: 'Failed', value: 'failed' } { label: 'Pending', value: 'pending' },
]} { label: 'Failed', value: 'failed' }
value="all" ]}
onChange={() => {}} value="all"
fullWidth={false} onChange={() => {}}
/> fullWidth={false}
</Group> />
</ButtonGroup>
</ButtonGroup>
</ControlBar> </ControlBar>
); );
} }

View File

@@ -3,6 +3,7 @@
import { Header } from '@/ui/Header'; import { Header } from '@/ui/Header';
import { StatusIndicator } from '@/ui/StatusIndicator'; import { StatusIndicator } from '@/ui/StatusIndicator';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { ButtonGroup } from '@/ui/ButtonGroup';
import { Activity } from 'lucide-react'; import { Activity } from 'lucide-react';
import React from 'react'; import React from 'react';
@@ -15,12 +16,11 @@ export function ActionsHeader({ title }: ActionsHeaderProps) {
<Header <Header
actions={<StatusIndicator icon={Activity} variant="info" label="SYSTEM_READY" />} actions={<StatusIndicator icon={Activity} variant="info" label="SYSTEM_READY" />}
> >
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}> <ButtonGroup gap={4}>
<div style={{ width: '0.5rem', height: '1.5rem', backgroundColor: 'var(--ui-color-intent-primary)', borderRadius: 'var(--ui-radius-sm)' }} />
<Text as="h1" size="xl" weight="medium" variant="high" uppercase> <Text as="h1" size="xl" weight="medium" variant="high" uppercase>
{title} {title}
</Text> </Text>
</div> </ButtonGroup>
</Header> </Header>
); );
} }

View File

@@ -1,6 +1,6 @@
'use client'; 'use client';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import React from 'react'; import React from 'react';
interface AuthFooterLinksProps { interface AuthFooterLinksProps {

View File

@@ -1,6 +1,6 @@
'use client'; 'use client';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import React from 'react'; import React from 'react';
interface AuthFormProps { interface AuthFormProps {

View File

@@ -1,7 +1,7 @@
import { LoadingSpinner } from '../../ui/LoadingSpinner'; import { LoadingSpinner } from '../../ui/LoadingSpinner';
import { Box } from '../../ui/primitives/Box'; import { Stack } from '../../ui/Stack';
import { Stack } from '../../ui/primitives/Stack';
import { Text } from '../../ui/Text'; import { Text } from '../../ui/Text';
import { Section } from '../../ui/Section';
interface AuthLoadingProps { interface AuthLoadingProps {
message?: string; message?: string;
@@ -9,19 +9,13 @@ interface AuthLoadingProps {
export function AuthLoading({ message = 'Authenticating...' }: AuthLoadingProps) { export function AuthLoading({ message = 'Authenticating...' }: AuthLoadingProps) {
return ( return (
<Box <Section variant="dark" padding="none">
fullWidth <Stack align="center" justify="center" gap={4} fullWidth>
minHeight="100vh"
display="flex"
center
bg="bg-[#0f1115]"
>
<Stack align="center" gap={4}>
<LoadingSpinner size={10} /> <LoadingSpinner size={10} />
<Text color="text-gray-400" weight="medium"> <Text variant="low" weight="medium">
{message} {message}
</Text> </Text>
</Stack> </Stack>
</Box> </Section>
); );
} }

View File

@@ -1,11 +1,12 @@
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Card } from '@/ui/Card';
interface KpiItem { interface KpiItem {
label: string; label: string;
value: string | number; value: string | number;
color?: string; intent?: 'primary' | 'success' | 'warning' | 'critical' | 'high' | 'med' | 'low';
} }
interface DashboardKpiRowProps { interface DashboardKpiRowProps {
@@ -16,32 +17,31 @@ interface DashboardKpiRowProps {
* DashboardKpiRow * DashboardKpiRow
* *
* A horizontal row of key performance indicators with telemetry styling. * A horizontal row of key performance indicators with telemetry styling.
* Uses UI primitives to comply with architectural constraints.
*/ */
export function DashboardKpiRow({ items }: DashboardKpiRowProps) { export function DashboardKpiRow({ items }: DashboardKpiRowProps) {
return ( return (
<Grid responsiveGridCols={{ base: 2, md: 3, lg: 6 }} gap={4}> <Grid cols={{ base: 2, md: 3, lg: 6 }} gap={4}>
{items.map((item, index) => ( {items.map((item, index) => (
<Stack key={index} borderLeft pl={4} borderColor="var(--color-outline)"> <Card key={index} variant="dark">
<Text <Stack gap={1}>
size="xs" <Text
weight="bold" size="xs"
uppercase weight="bold"
letterSpacing="tighter" uppercase
color="var(--color-text-low)" variant="low"
block >
> {item.label}
{item.label} </Text>
</Text> <Text
<Text size="xl"
size="xl" font="mono"
font="mono" weight="bold"
weight="bold" variant={item.intent || 'high'}
color={item.color || 'var(--color-text-high)'} >
> {item.value}
{item.value} </Text>
</Text> </Stack>
</Stack> </Card>
))} ))}
</Grid> </Grid>
); );

View File

@@ -1,4 +1,4 @@
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import React from 'react'; import React from 'react';
interface DashboardRailProps { interface DashboardRailProps {
@@ -13,7 +13,7 @@ interface DashboardRailProps {
*/ */
export function DashboardRail({ children }: DashboardRailProps) { export function DashboardRail({ children }: DashboardRailProps) {
return ( return (
<Stack as="nav" h="full" align="center" py={4} gap={4}> <Stack align="center" gap={4} fullWidth>
{children} {children}
</Stack> </Stack>
); );

View File

@@ -1,7 +1,7 @@
import { Sidebar } from '@/ui/Sidebar'; import { Box } from '@/ui/Box';
import { Header } from '@/ui/Header'; import { Header } from '@/ui/Header';
import { MainContent } from '@/ui/MainContent'; import { MainContent } from '@/ui/MainContent';
import { Box } from '@/ui/primitives/Box'; import { Sidebar } from '@/ui/Sidebar';
import React from 'react'; import React from 'react';
interface DashboardShellProps { interface DashboardShellProps {

View File

@@ -8,6 +8,8 @@ import { Text } from '@/ui/Text';
import { FloatingAction } from '@/ui/FloatingAction'; import { FloatingAction } from '@/ui/FloatingAction';
import { DebugPanel } from '@/ui/DebugPanel'; import { DebugPanel } from '@/ui/DebugPanel';
import { StatGrid } from '@/ui/StatGrid'; import { StatGrid } from '@/ui/StatGrid';
import { Stack } from '@/ui/Stack';
import { ButtonGroup } from '@/ui/ButtonGroup';
import { Bug, Shield } from 'lucide-react'; import { Bug, Shield } from 'lucide-react';
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
@@ -207,13 +209,13 @@ export function DebugModeToggle({ show }: DebugModeToggleProps) {
onClose={() => setIsOpen(false)} onClose={() => setIsOpen(false)}
icon={<Icon icon={Bug} size={4} intent="success" />} icon={<Icon icon={Bug} size={4} intent="success" />}
> >
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}> <Stack gap={4}>
{/* Debug Toggle */} {/* Debug Toggle */}
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0.5rem', backgroundColor: 'var(--ui-color-bg-surface-muted)', borderRadius: '0.5rem' }}> <Stack align="center" justify="between">
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}> <ButtonGroup gap={2}>
<Icon icon={Shield} size={4} intent={debugEnabled ? 'success' : 'low'} /> <Icon icon={Shield} size={4} intent={debugEnabled ? 'success' : 'low'} />
<Text size="sm" weight="medium">Debug Mode</Text> <Text size="sm" weight="medium">Debug Mode</Text>
</div> </ButtonGroup>
<Button <Button
onClick={toggleDebug} onClick={toggleDebug}
size="sm" size="sm"
@@ -221,7 +223,7 @@ export function DebugModeToggle({ show }: DebugModeToggleProps) {
> >
{debugEnabled ? 'ON' : 'OFF'} {debugEnabled ? 'ON' : 'OFF'}
</Button> </Button>
</div> </Stack>
{/* Metrics */} {/* Metrics */}
{debugEnabled && ( {debugEnabled && (
@@ -238,41 +240,41 @@ export function DebugModeToggle({ show }: DebugModeToggleProps) {
{/* Actions */} {/* Actions */}
{debugEnabled && ( {debugEnabled && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}> <Stack gap={2}>
<Text size="xs" weight="semibold" variant="low" uppercase>Test Actions</Text> <Text size="xs" weight="semibold" variant="low" uppercase>Test Actions</Text>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.5rem' }}> <ButtonGroup gap={2}>
<Button onClick={triggerTestError} variant="danger" size="sm">Test Error</Button> <Button onClick={triggerTestError} variant="danger" size="sm" fullWidth>Test Error</Button>
<Button onClick={triggerTestApiCall} size="sm">Test API</Button> <Button onClick={triggerTestApiCall} size="sm" fullWidth>Test API</Button>
</div> </ButtonGroup>
<Text size="xs" weight="semibold" variant="low" uppercase style={{ marginTop: '0.5rem' }}>Utilities</Text> <Text size="xs" weight="semibold" variant="low" uppercase>Utilities</Text>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.5rem' }}> <ButtonGroup gap={2}>
<Button onClick={copyDebugInfo} variant="secondary" size="sm">Copy Info</Button> <Button onClick={copyDebugInfo} variant="secondary" size="sm" fullWidth>Copy Info</Button>
<Button onClick={clearAllLogs} variant="secondary" size="sm">Clear Logs</Button> <Button onClick={clearAllLogs} variant="secondary" size="sm" fullWidth>Clear Logs</Button>
</div> </ButtonGroup>
</div> </Stack>
)} )}
{/* Quick Links */} {/* Quick Links */}
{debugEnabled && ( {debugEnabled && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem' }}> <Stack gap={1}>
<Text size="xs" weight="semibold" variant="low" uppercase>Quick Access</Text> <Text size="xs" weight="semibold" variant="low" uppercase>Quick Access</Text>
<div style={{ fontSize: '10px', color: 'var(--ui-color-text-low)', fontFamily: 'var(--ui-font-mono)' }}> <Stack gap={0.5}>
<div> window.__GRIDPILOT_GLOBAL_HANDLER__</div> <Text size="xs" variant="low" font="mono"> window.__GRIDPILOT_GLOBAL_HANDLER__</Text>
<div> window.__GRIDPILOT_API_LOGGER__</div> <Text size="xs" variant="low" font="mono"> window.__GRIDPILOT_API_LOGGER__</Text>
<div> window.__GRIDPILOT_REACT_ERRORS__</div> <Text size="xs" variant="low" font="mono"> window.__GRIDPILOT_REACT_ERRORS__</Text>
</div> </Stack>
</div> </Stack>
)} )}
{/* Status */} {/* Status */}
<div style={{ paddingTop: '0.5rem', borderTop: '1px solid var(--ui-color-border-muted)', textAlign: 'center' }}> <Stack align="center">
<Text size="xs" variant="low" style={{ fontSize: '10px' }}> <Text size="xs" variant="low">
{debugEnabled ? 'Debug features active' : 'Debug mode disabled'} {debugEnabled ? 'Debug features active' : 'Debug mode disabled'}
{isDev && ' • Development Environment'} {isDev && ' • Development Environment'}
</Text> </Text>
</div> </Stack>
</div> </Stack>
</DebugPanel> </DebugPanel>
)} )}
</React.Fragment> </React.Fragment>

View File

@@ -4,7 +4,7 @@ import { useNotifications } from '@/components/notifications/NotificationProvide
import type { NotificationVariant } from '@/components/notifications/notificationTypes'; import type { NotificationVariant } from '@/components/notifications/notificationTypes';
import { useEffectiveDriverId } from "@/hooks/useEffectiveDriverId"; import { useEffectiveDriverId } from "@/hooks/useEffectiveDriverId";
import { ApiConnectionMonitor } from '@/lib/api/base/ApiConnectionMonitor'; import { ApiConnectionMonitor } from '@/lib/api/base/ApiConnectionMonitor';
import { CircuitBreakerRegistry } from '@/lib/api/base/RetryHandler'; import { CircuitBreakerRegistry } from '@/lib/api/base/CircuitBreakerRegistry';
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler'; import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
import { Activity, AlertTriangle, ChevronDown, ChevronUp, MessageSquare, Wrench, X } from 'lucide-react'; import { Activity, AlertTriangle, ChevronDown, ChevronUp, MessageSquare, Wrench, X } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@@ -16,7 +16,7 @@ import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { IconButton } from '@/ui/IconButton'; import { IconButton } from '@/ui/IconButton';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { APIStatusSection } from './sections/APIStatusSection'; import { APIStatusSection } from './sections/APIStatusSection';
import { NotificationSendSection } from './sections/NotificationSendSection'; import { NotificationSendSection } from './sections/NotificationSendSection';
import { NotificationTypeSection } from './sections/NotificationTypeSection'; import { NotificationTypeSection } from './sections/NotificationTypeSection';
@@ -229,7 +229,7 @@ export function DevToolbar() {
if (isMinimized) { if (isMinimized) {
return ( return (
<Stack position="fixed" bottom="4" right="4" zIndex={50}> <Stack align="end" justify="end">
<IconButton <IconButton
icon={Wrench} icon={Wrench}
onClick={() => setIsMinimized(false)} onClick={() => setIsMinimized(false)}
@@ -242,25 +242,13 @@ export function DevToolbar() {
} }
return ( return (
<Stack <Stack gap={4}>
position="fixed"
bottom="4"
right="4"
zIndex={50}
w="80"
bg="bg-deep-graphite"
border
borderColor="border-charcoal-outline"
rounded="xl"
shadow="2xl"
overflow="hidden"
>
{/* Header */} {/* Header */}
<Stack direction="row" align="center" justify="between" px={4} py={3} bg="bg-iron-gray/50" borderBottom borderColor="border-charcoal-outline"> <Stack direction="row" align="center" justify="between" gap={4}>
<Stack direction="row" align="center" gap={2}> <Stack direction="row" align="center" gap={2}>
<Icon icon={Wrench} size={4} color="rgb(59, 130, 246)" /> <Icon icon={Wrench} size={4} intent="primary" />
<Text size="sm" weight="semibold" color="text-white">Dev Toolbar</Text> <Text size="sm" weight="semibold" variant="high">Dev Toolbar</Text>
<Badge variant="primary" size="xs"> <Badge variant="primary" size="sm">
DEMO DEMO
</Badge> </Badge>
</Stack> </Stack>
@@ -282,12 +270,11 @@ export function DevToolbar() {
{/* Content */} {/* Content */}
{isExpanded && ( {isExpanded && (
<Stack p={4}> <Stack gap={4}>
<Stack gap={3}> <Stack gap={3}>
{/* Notification Section - Accordion */} {/* Notification Section - Accordion */}
<Accordion <Accordion
title="Notifications" title="Notifications"
icon={<Icon icon={MessageSquare} size={4} color="rgb(156, 163, 175)" />}
isOpen={openAccordion === 'notifications'} isOpen={openAccordion === 'notifications'}
onToggle={() => setOpenAccordion(openAccordion === 'notifications' ? null : 'notifications')} onToggle={() => setOpenAccordion(openAccordion === 'notifications' ? null : 'notifications')}
> >
@@ -313,7 +300,6 @@ export function DevToolbar() {
{/* API Status Section - Accordion */} {/* API Status Section - Accordion */}
<Accordion <Accordion
title="API Status" title="API Status"
icon={<Icon icon={Activity} size={4} color="rgb(156, 163, 175)" />}
isOpen={openAccordion === 'apiStatus'} isOpen={openAccordion === 'apiStatus'}
onToggle={() => setOpenAccordion(openAccordion === 'apiStatus' ? null : 'apiStatus')} onToggle={() => setOpenAccordion(openAccordion === 'apiStatus' ? null : 'apiStatus')}
> >
@@ -331,27 +317,26 @@ export function DevToolbar() {
{/* Error Stats Section - Accordion */} {/* Error Stats Section - Accordion */}
<Accordion <Accordion
title="Error Stats" title="Error Stats"
icon={<Icon icon={AlertTriangle} size={4} color="rgb(156, 163, 175)" />}
isOpen={openAccordion === 'errors'} isOpen={openAccordion === 'errors'}
onToggle={() => setOpenAccordion(openAccordion === 'errors' ? null : 'errors')} onToggle={() => setOpenAccordion(openAccordion === 'errors' ? null : 'errors')}
> >
<Stack gap={2}> <Stack gap={2}>
<Stack direction="row" justify="between" align="center" p={2} bg="bg-iron-gray/30" rounded="md"> <Stack direction="row" justify="between" align="center" gap={2}>
<Text size="xs" color="text-gray-400">Total Errors</Text> <Text size="xs" variant="low">Total Errors</Text>
<Text size="xs" font="mono" weight="bold" color="text-red-400">{errorStats.total}</Text> <Text size="xs" font="mono" weight="bold" variant="critical">{errorStats.total}</Text>
</Stack> </Stack>
{Object.keys(errorStats.byType).length > 0 ? ( {Object.keys(errorStats.byType).length > 0 ? (
<Stack gap={1}> <Stack gap={1}>
{Object.entries(errorStats.byType).map(([type, count]) => ( {Object.entries(errorStats.byType).map(([type, count]) => (
<Stack key={type} direction="row" justify="between" align="center" p={1.5} bg="bg-deep-graphite" rounded="md"> <Stack key={type} direction="row" justify="between" align="center" gap={2}>
<Text size="xs" color="text-gray-300">{type}</Text> <Text size="xs" variant="low">{type}</Text>
<Text size="xs" font="mono" color="text-warning-amber">{count}</Text> <Text size="xs" font="mono" variant="warning">{count}</Text>
</Stack> </Stack>
))} ))}
</Stack> </Stack>
) : ( ) : (
<Stack align="center" py={2}> <Stack align="center">
<Text size="xs" color="text-gray-500">No errors yet</Text> <Text size="xs" variant="low">No errors yet</Text>
</Stack> </Stack>
)} )}
<Button <Button
@@ -374,8 +359,8 @@ export function DevToolbar() {
{/* Collapsed state hint */} {/* Collapsed state hint */}
{!isExpanded && ( {!isExpanded && (
<Stack px={4} py={2}> <Stack>
<Text size="xs" color="text-gray-500">Click to expand dev tools</Text> <Text size="xs" variant="low">Click to expand dev tools</Text>
</Stack> </Stack>
)} )}
</Stack> </Stack>

View File

@@ -4,8 +4,8 @@ import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Badge, StatRow, StatusIndicator } from '@/ui/StatusIndicator'; import { Badge, StatRow, StatusIndicator } from '@/ui/StatusIndicator';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Activity, RefreshCw, Terminal, Wifi } from 'lucide-react'; import { Activity, RefreshCw, Terminal, Wifi } from 'lucide-react';
interface APIStatusSectionProps { interface APIStatusSectionProps {

View File

@@ -2,7 +2,7 @@
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Bell, Loader2 } from 'lucide-react'; import { Bell, Loader2 } from 'lucide-react';
import type { DemoNotificationType, DemoUrgency } from '../types'; import type { DemoNotificationType, DemoUrgency } from '../types';

View File

@@ -2,8 +2,8 @@
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { AlertTriangle, Award, LucideIcon, MessageSquare, Shield, TrendingUp, Vote } from 'lucide-react'; import { AlertTriangle, Award, LucideIcon, MessageSquare, Shield, TrendingUp, Vote } from 'lucide-react';
import type { DemoNotificationType } from '../types'; import type { DemoNotificationType } from '../types';

View File

@@ -4,7 +4,7 @@ import { getGlobalReplaySystem } from '@/lib/infrastructure/ErrorReplay';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { IconButton } from '@/ui/IconButton'; import { IconButton } from '@/ui/IconButton';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Box, Clock, Copy, Download, Play, Trash2 } from 'lucide-react'; import { Box, Clock, Copy, Download, Play, Trash2 } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';

View File

@@ -2,8 +2,8 @@
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { AlertCircle, Bell, BellRing, LucideIcon } from 'lucide-react'; import { AlertCircle, Bell, BellRing, LucideIcon } from 'lucide-react';
import type { DemoUrgency } from '../types'; import type { DemoUrgency } from '../types';

View File

@@ -3,8 +3,8 @@ import { Card } from '@/ui/Card';
import { GoalCard } from '@/ui/GoalCard'; import { GoalCard } from '@/ui/GoalCard';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { MilestoneItem } from '@/components/achievements/MilestoneItem'; import { MilestoneItem } from '@/components/achievements/MilestoneItem';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
interface Achievement { interface Achievement {
id: string; id: string;

View File

@@ -1,10 +1,10 @@
import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box'; import { Grid } from '@/ui/Grid';
import { Grid } from '@/ui/primitives/Grid';
import { StatGridItem } from '@/ui/StatGridItem'; import { StatGridItem } from '@/ui/StatGridItem';
import { TrendingUp } from 'lucide-react'; import { TrendingUp } from 'lucide-react';

View File

@@ -3,7 +3,7 @@
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { InfoBox } from '@/ui/InfoBox'; import { InfoBox } from '@/ui/InfoBox';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { TextArea } from '@/ui/TextArea'; import { TextArea } from '@/ui/TextArea';
import { AlertCircle } from 'lucide-react'; import { AlertCircle } from 'lucide-react';

View File

@@ -1,10 +1,10 @@
import { DriverIdentity } from '@/components/drivers/DriverIdentity'; import { DriverIdentity } from '@/ui/DriverIdentity';
import { DriverStats } from '@/components/drivers/DriverStats'; import { DriverStats } from '@/components/drivers/DriverStats';
import { RankBadge } from '@/components/leaderboards/RankBadge'; import { RankBadge } from '@/components/leaderboards/RankBadge';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel'; import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
export interface DriverCardProps { export interface DriverCardProps {
id: string; id: string;

View File

@@ -4,7 +4,7 @@ import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Badge } from '@/ui/Badge'; import { Badge } from '@/ui/Badge';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Zap } from 'lucide-react'; import { Zap } from 'lucide-react';

View File

@@ -1,6 +1,6 @@
import { RatingBadge } from '@/components/drivers/RatingBadge'; import { RatingBadge } from '@/components/drivers/RatingBadge';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import React from 'react'; import React from 'react';

View File

@@ -1,8 +1,8 @@
'use client'; 'use client';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
interface DriverPerformanceOverviewProps { interface DriverPerformanceOverviewProps {
stats: { stats: {

View File

@@ -8,7 +8,7 @@ import { useDriverProfile } from "@/hooks/driver/useDriverProfile";
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel'; import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { StatCard } from '@/ui/StatCard'; import { StatCard } from '@/ui/StatCard';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { ProfileStats } from './ProfileStats'; import { ProfileStats } from './ProfileStats';

View File

@@ -4,7 +4,7 @@ import { RatingBadge } from '@/components/drivers/RatingBadge';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Check, Globe, Trophy, UserPlus } from 'lucide-react'; import { Check, Globe, Trophy, UserPlus } from 'lucide-react';
import { SafetyRatingBadge } from './SafetyRatingBadge'; import { SafetyRatingBadge } from './SafetyRatingBadge';

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
import { BarChart3, LayoutDashboard, ShieldCheck } from 'lucide-react'; import { BarChart3, LayoutDashboard, ShieldCheck } from 'lucide-react';
export type ProfileTab = 'overview' | 'stats' | 'ratings'; export type ProfileTab = 'overview' | 'stats' | 'ratings';

View File

@@ -2,7 +2,7 @@
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Car, Clock, MailCheck, MapPin, Users2 } from 'lucide-react'; import { Car, Clock, MailCheck, MapPin, Users2 } from 'lucide-react';
interface DriverRacingProfileProps { interface DriverRacingProfileProps {

View File

@@ -1,7 +1,7 @@
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Star, Trophy } from 'lucide-react'; import { Star, Trophy } from 'lucide-react';

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { Box } from '@/ui/Box';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box';
import { Search } from 'lucide-react'; import { Search } from 'lucide-react';
interface DriverSearchBarProps { interface DriverSearchBarProps {

View File

@@ -1,4 +1,4 @@
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
interface DriverStatsProps { interface DriverStatsProps {

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
interface StatItem { interface StatItem {
label: string; label: string;

View File

@@ -3,7 +3,7 @@
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { PlaceholderImage } from '@/ui/PlaceholderImage'; import { PlaceholderImage } from '@/ui/PlaceholderImage';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import React from 'react'; import React from 'react';

View File

@@ -2,8 +2,11 @@
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Table, TableHead, TableBody, TableRow, TableHeaderCell } from '@/ui/Table';
import { TrendingUp } from 'lucide-react'; import { TrendingUp } from 'lucide-react';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import React from 'react'; import React from 'react';
interface DriverTableProps { interface DriverTableProps {
@@ -14,31 +17,29 @@ export function DriverTable({ children }: DriverTableProps) {
return ( return (
<Stack gap={4}> <Stack gap={4}>
<Stack direction="row" align="center" gap={3}> <Stack direction="row" align="center" gap={3}>
<Stack display="flex" h="10" w="10" alignItems="center" justifyContent="center" rounded="xl" bg="bg-primary-blue/10" border borderColor="border-primary-blue/20"> <Card variant="dark">
<TrendingUp size={20} color="#198CFF" /> <Icon icon={TrendingUp} size={5} intent="primary" />
</Stack> </Card>
<Stack> <Stack>
<Heading level={2}>Driver Rankings</Heading> <Heading level={2}>Driver Rankings</Heading>
<Text size="xs" color="text-gray-500">Top performers by skill rating</Text> <Text size="xs" variant="low">Top performers by skill rating</Text>
</Stack> </Stack>
</Stack> </Stack>
<Stack overflow="hidden" rounded="xl" border borderColor="border-charcoal-outline" bg="bg-deep-charcoal/50"> <Table>
<Stack as="table" w="full" textAlign="left"> <TableHead>
<Stack as="thead"> <TableRow>
<Stack as="tr" borderBottom borderColor="border-charcoal-outline" bg="bg-deep-charcoal/80"> <TableHeaderCell textAlign="center" w="60px">#</TableHeaderCell>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" textAlign="center" width="60px">#</Stack> <TableHeaderCell>Driver</TableHeaderCell>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500">Driver</Stack> <TableHeaderCell w="150px">Nationality</TableHeaderCell>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" width="150px">Nationality</Stack> <TableHeaderCell textAlign="right" w="100px">Rating</TableHeaderCell>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" textAlign="right" width="100px">Rating</Stack> <TableHeaderCell textAlign="right" w="80px">Wins</TableHeaderCell>
<Stack as="th" px={6} py={4} fontSize="xs" color="text-gray-500" textAlign="right" width="80px">Wins</Stack> </TableRow>
</Stack> </TableHead>
</Stack> <TableBody>
<Stack as="tbody"> {children}
{children} </TableBody>
</Stack> </Table>
</Stack>
</Stack>
</Stack> </Stack>
); );
} }

View File

@@ -3,7 +3,9 @@
import { RatingBadge } from '@/components/drivers/RatingBadge'; import { RatingBadge } from '@/components/drivers/RatingBadge';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { TableRow, TableCell } from '@/ui/Table';
import { Avatar } from '@/ui/Avatar';
interface DriverTableRowProps { interface DriverTableRowProps {
rank: number; rank: number;
@@ -24,61 +26,45 @@ export function DriverTableRow({
wins, wins,
onClick, onClick,
}: DriverTableRowProps) { }: DriverTableRowProps) {
const defaultAvatar = 'https://cdn.gridpilot.com/avatars/default.png';
return ( return (
<Stack <TableRow onClick={onClick} clickable>
as="tr" <TableCell textAlign="center">
onClick={onClick}
cursor="pointer"
transition
hoverBg="bg-primary-blue/5"
group
borderBottom
borderColor="border-charcoal-outline/50"
>
<Stack as="td" px={6} py={4} textAlign="center">
<Text <Text
size="sm" size="sm"
weight="bold" weight="bold"
font="mono" font="mono"
color={rank <= 3 ? 'text-warning-amber' : 'text-gray-500'} variant={rank <= 3 ? 'warning' : 'low'}
> >
{rank} {rank}
</Text> </Text>
</Stack> </TableCell>
<Stack as="td" px={6} py={4}> <TableCell>
<Stack direction="row" align="center" gap={3}> <Stack direction="row" align="center" gap={3}>
<Stack position="relative" h="8" w="8" overflow="hidden" rounded="full" border borderColor="border-charcoal-outline" bg="bg-deep-charcoal"> <Avatar
<Image src={avatarUrl || undefined}
src={avatarUrl || defaultAvatar} alt={name}
alt={name} size="sm"
fill />
objectFit="cover"
/>
</Stack>
<Text <Text
size="sm" size="sm"
weight="semibold" weight="semibold"
color="text-white" variant="high"
groupHoverTextColor="text-primary-blue"
transition
> >
{name} {name}
</Text> </Text>
</Stack> </Stack>
</Stack> </TableCell>
<Stack as="td" px={6} py={4}> <TableCell>
<Text size="xs" color="text-gray-400">{nationality}</Text> <Text size="xs" variant="low">{nationality}</Text>
</Stack> </TableCell>
<Stack as="td" px={6} py={4} textAlign="right"> <TableCell textAlign="right">
<RatingBadge rating={rating} size="sm" /> <RatingBadge rating={rating} size="sm" />
</Stack> </TableCell>
<Stack as="td" px={6} py={4} textAlign="right"> <TableCell textAlign="right">
<Text size="sm" weight="semibold" font="mono" color="text-performance-green"> <Text size="sm" weight="semibold" font="mono" variant="success">
{wins} {wins}
</Text> </Text>
</Stack> </TableCell>
</Stack> </TableRow>
); );
} }

View File

@@ -2,15 +2,18 @@
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Section } from '@/ui/Section';
import { Container } from '@/ui/Container';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import { Trophy, Users } from 'lucide-react'; import { Trophy, Users } from 'lucide-react';
interface DriverStat { interface DriverStat {
label: string; label: string;
value: string | number; value: string | number;
color?: string; intent?: 'primary' | 'success' | 'warning' | 'telemetry';
animate?: boolean;
} }
interface DriversDirectoryHeaderProps { interface DriversDirectoryHeaderProps {
@@ -29,71 +32,53 @@ export function DriversDirectoryHeader({
onViewLeaderboard, onViewLeaderboard,
}: DriversDirectoryHeaderProps) { }: DriversDirectoryHeaderProps) {
const stats: DriverStat[] = [ const stats: DriverStat[] = [
{ label: 'drivers', value: totalDrivers, color: 'text-primary-blue' }, { label: 'drivers', value: totalDrivers, intent: 'primary' },
{ label: 'active', value: activeDrivers, color: 'text-performance-green', animate: true }, { label: 'active', value: activeDrivers, intent: 'success' },
{ label: 'total wins', value: totalWins.toLocaleString(), color: 'text-warning-amber' }, { label: 'total wins', value: totalWins.toLocaleString(), intent: 'warning' },
{ label: 'races', value: totalRaces.toLocaleString(), color: 'text-neon-aqua' }, { label: 'races', value: totalRaces.toLocaleString(), intent: 'telemetry' },
]; ];
return ( return (
<Stack <Section variant="dark" padding="md">
as="header" <Container>
position="relative" <Stack direction="row" align="center" justify="between" gap={8}>
overflow="hidden" <Stack gap={6}>
rounded="2xl" <Stack direction="row" align="center" gap={3}>
border <Card variant="dark">
borderColor="border-charcoal-outline/50" <Icon icon={Users} size={6} intent="primary" />
bg="bg-gradient-to-br from-iron-gray/80 via-deep-graphite to-iron-gray/60" </Card>
p={{ base: 8, lg: 10 }} <Heading level={1}>Drivers</Heading>
>
{/* Background Accents */}
<Stack position="absolute" right="-24" top="-24" w="96" h="96" rounded="full" bg="bg-primary-blue/5" blur="3xl" />
<Stack position="absolute" bottom="-16" left="-16" w="64" h="64" rounded="full" bg="bg-neon-aqua/5" blur="3xl" />
<Stack position="relative" display="flex" flexDirection={{ base: 'col', lg: 'row' }} alignItems={{ lg: 'center' }} justifyContent="between" gap={8}>
<Stack maxWidth="2xl">
<Stack direction="row" align="center" gap={3} mb={4}>
<Stack display="flex" h="12" w="12" alignItems="center" justifyContent="center" rounded="xl" border borderColor="border-charcoal-outline" bg="bg-deep-charcoal" shadow="lg">
<Users size={24} color="#198CFF" />
</Stack> </Stack>
<Heading level={1}>Drivers</Heading>
</Stack> <Text size="lg" variant="low">
Meet the racers who make every lap count. From rookies to champions, track their journey and see who&apos;s dominating the grid.
<Text size="lg" color="text-gray-400" block leading="relaxed"> </Text>
Meet the racers who make every lap count. From rookies to champions, track their journey and see who&apos;s dominating the grid.
</Text>
<Stack display="flex" flexWrap="wrap" gap={6} mt={6}> <Stack direction="row" gap={6} wrap>
{stats.map((stat, index) => ( {stats.map((stat, index) => (
<Stack key={index} direction="row" align="center" gap={2}> <Stack key={index} direction="row" align="center" gap={2}>
<Stack <Text size="sm" variant="low">
w="2" <Text as="span" weight="semibold" variant="high">{stat.value}</Text> {stat.label}
h="2" </Text>
rounded="full" </Stack>
bg={stat.color?.replace('text-', 'bg-') || 'bg-primary-blue'} ))}
animate={stat.animate ? 'pulse' : 'none'} </Stack>
/> </Stack>
<Text size="sm" color="text-gray-400">
<Text as="span" weight="semibold" color="text-white">{stat.value}</Text> {stat.label} <Stack gap={2} align="center">
</Text> <Button
</Stack> variant="primary"
))} onClick={onViewLeaderboard}
icon={<Icon icon={Trophy} size={5} />}
>
View Leaderboard
</Button>
<Text size="xs" variant="low" align="center">
See full driver rankings
</Text>
</Stack> </Stack>
</Stack> </Stack>
</Container>
<Stack gap={2}> </Section>
<Button
variant="primary"
onClick={onViewLeaderboard}
icon={<Trophy size={20} />}
>
View Leaderboard
</Button>
<Text size="xs" color="text-gray-500" align="center" block>
See full driver rankings
</Text>
</Stack>
</Stack>
</Stack>
); );
} }

View File

@@ -1,8 +1,8 @@
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Box } from '@/ui/primitives/Box';
import { Search } from 'lucide-react'; import { Search } from 'lucide-react';
interface DriversSearchProps { interface DriversSearchProps {

View File

@@ -3,11 +3,11 @@
import { MedalBadge } from '@/components/leaderboards/MedalBadge'; import { MedalBadge } from '@/components/leaderboards/MedalBadge';
import { mediaConfig } from '@/lib/config/mediaConfig'; import { mediaConfig } from '@/lib/config/mediaConfig';
import { Badge } from '@/ui/Badge'; import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { MiniStat } from '@/ui/MiniStat'; import { MiniStat } from '@/ui/MiniStat';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Flag, Shield, Star, TrendingUp } from 'lucide-react'; import { Flag, Shield, Star, TrendingUp } from 'lucide-react';

View File

@@ -3,7 +3,7 @@ import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Car, Download, Edit, Trash2 } from 'lucide-react'; import { Car, Download, Edit, Trash2 } from 'lucide-react';

View File

@@ -1,7 +1,7 @@
import { Box } from '@/ui/Box';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
interface PerformanceMetricsProps { interface PerformanceMetricsProps {

View File

@@ -5,9 +5,9 @@ import { CircularProgress } from '@/ui/CircularProgress';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { HorizontalBarChart } from '@/ui/HorizontalBarChart'; import { HorizontalBarChart } from '@/ui/HorizontalBarChart';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { GridItem } from '@/ui/primitives/GridItem'; import { GridItem } from '@/ui/GridItem';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Activity, BarChart3, Target, TrendingUp } from 'lucide-react'; import { Activity, BarChart3, Target, TrendingUp } from 'lucide-react';

View File

@@ -8,7 +8,7 @@ import { CountryFlag } from '@/ui/CountryFlag';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { PlaceholderImage } from '@/ui/PlaceholderImage'; import { PlaceholderImage } from '@/ui/PlaceholderImage';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
interface ProfileHeaderProps { interface ProfileHeaderProps {

View File

@@ -6,8 +6,8 @@ import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image'; import { Image } from '@/ui/Image';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/primitives/Surface'; import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Calendar, Clock, ExternalLink, Globe, Star, Trophy, UserPlus } from 'lucide-react'; import { Calendar, Clock, ExternalLink, Globe, Star, Trophy, UserPlus } from 'lucide-react';

View File

@@ -6,7 +6,7 @@ import { Card } from '@/ui/Card';
import { Checkbox } from '@/ui/Checkbox'; import { Checkbox } from '@/ui/Checkbox';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Select } from '@/ui/Select'; import { Select } from '@/ui/Select';
import { TextArea } from '@/ui/TextArea'; import { TextArea } from '@/ui/TextArea';
import { Toggle } from '@/ui/Toggle'; import { Toggle } from '@/ui/Toggle';

View File

@@ -4,7 +4,7 @@ import { RankBadge } from '@/components/leaderboards/RankBadge';
import { useDriverProfile } from "@/hooks/driver/useDriverProfile"; import { useDriverProfile } from "@/hooks/driver/useDriverProfile";
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { StatCard } from '@/ui/StatCard'; import { StatCard } from '@/ui/StatCard';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { useMemo } from 'react'; import { useMemo } from 'react';

View File

@@ -3,7 +3,7 @@
import { Card, Card as Surface } from '@/ui/Card'; import { Card, Card as Surface } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Flag, UserPlus, Users } from 'lucide-react'; import { Flag, UserPlus, Users } from 'lucide-react';

View File

@@ -3,33 +3,22 @@ import { Badge } from '@/ui/Badge';
interface RatingBadgeProps { interface RatingBadgeProps {
rating: number; rating: number;
size?: 'sm' | 'md' | 'lg'; size?: 'sm' | 'md';
className?: string;
} }
export function RatingBadge({ rating, size = 'md', className = '' }: RatingBadgeProps) { export function RatingBadge({ rating, size = 'md' }: RatingBadgeProps) {
const getColor = (val: number) => { const getVariant = (val: number): 'warning' | 'primary' | 'success' | 'default' => {
if (val >= 2500) return { variant: 'warning' as const }; if (val >= 2500) return 'warning';
if (val >= 2000) return { color: 'text-purple-400', bg: 'bg-purple-400/10', borderColor: 'border-purple-400/20' }; if (val >= 2000) return 'primary'; // Simplified
if (val >= 1500) return { variant: 'primary' as const }; if (val >= 1500) return 'primary';
if (val >= 1000) return { variant: 'success' as const }; if (val >= 1000) return 'success';
return { variant: 'default' as const }; return 'default';
}; };
const sizeMap: Record<string, 'xs' | 'sm' | 'md'> = {
sm: 'xs',
md: 'sm',
lg: 'md',
};
const config = getColor(rating);
return ( return (
<Badge <Badge
{...config} variant={getVariant(rating)}
size={sizeMap[size]} size={size}
className={`font-mono ${className}`}
rounded="sm"
> >
{rating.toLocaleString()} {rating.toLocaleString()}
</Badge> </Badge>

View File

@@ -4,7 +4,7 @@ import { RatingComponent } from '@/components/drivers/RatingComponent';
import { RatingHistoryItem } from '@/components/drivers/RatingHistoryItem'; import { RatingHistoryItem } from '@/components/drivers/RatingHistoryItem';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
interface RatingBreakdownProps { interface RatingBreakdownProps {

View File

@@ -1,6 +1,6 @@
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { ProgressBar } from '@/ui/ProgressBar'; import { ProgressBar } from '@/ui/ProgressBar';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';

View File

@@ -1,6 +1,6 @@
import { Box } from '@/ui/primitives/Box'; import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
interface RatingHistoryItemProps { interface RatingHistoryItemProps {

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Box } from '@/ui/primitives/Box';
import { Shield } from 'lucide-react'; import { Shield } from 'lucide-react';
interface SafetyRatingBadgeProps { interface SafetyRatingBadgeProps {

View File

@@ -1,8 +1,8 @@
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { BarChart3 } from 'lucide-react'; import { BarChart3 } from 'lucide-react';

View File

@@ -1,6 +1,6 @@
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { LucideIcon } from 'lucide-react'; import { LucideIcon } from 'lucide-react';

View File

@@ -1,7 +1,7 @@
import { Badge } from '@/ui/Badge'; import { Badge } from '@/ui/Badge';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { ChevronRight, LucideIcon, UserPlus } from 'lucide-react'; import { ChevronRight, LucideIcon, UserPlus } from 'lucide-react';

View File

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

View File

@@ -5,7 +5,7 @@ import { getErrorSeverity, isConnectivityError, isRetryable, parseApiError } fro
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { IconButton } from '@/ui/IconButton'; import { IconButton } from '@/ui/IconButton';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { import {

View File

@@ -8,7 +8,7 @@ import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { IconButton } from '@/ui/IconButton'; import { IconButton } from '@/ui/IconButton';
import { Input } from '@/ui/Input'; import { Input } from '@/ui/Input';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { import {
Activity, Activity,

View File

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

View File

@@ -3,6 +3,7 @@
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Glow } from '@/ui/Glow'; import { Glow } from '@/ui/Glow';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { ErrorPageContainer } from '@/ui/ErrorPageContainer'; import { ErrorPageContainer } from '@/ui/ErrorPageContainer';
import { AppErrorBoundaryView } from './AppErrorBoundaryView'; import { AppErrorBoundaryView } from './AppErrorBoundaryView';
import { ErrorDetailsBlock } from './ErrorDetailsBlock'; import { ErrorDetailsBlock } from './ErrorDetailsBlock';
@@ -32,13 +33,13 @@ export function ErrorScreen({ error, reset, onHome }: ErrorScreenProps) {
description="The application encountered an unexpected state. Our telemetry has logged the incident." description="The application encountered an unexpected state. Our telemetry has logged the incident."
> >
{/* Error Message Summary */} {/* Error Message Summary */}
<div style={{ width: '100%', marginBottom: '1.5rem' }}> <Stack fullWidth marginBottom={6}>
<Card variant="outline"> <Card variant="outline">
<Text font="mono" size="sm" variant="warning" block> <Text font="mono" size="sm" variant="warning" block>
{error.message || 'Unknown execution error'} {error.message || 'Unknown execution error'}
</Text> </Text>
</Card> </Card>
</div> </Stack>
<ErrorRecoveryActions onRetry={reset} onHome={onHome} /> <ErrorRecoveryActions onRetry={reset} onHome={onHome} />

View File

@@ -9,6 +9,8 @@ import { Icon } from '@/ui/Icon';
import { EmptyState } from '@/ui/EmptyState'; import { EmptyState } from '@/ui/EmptyState';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Stack } from '@/ui/Stack';
interface FeedItem { interface FeedItem {
id: string; id: string;
headline: string; headline: string;
@@ -32,7 +34,7 @@ export function ActivityFeed({ items, hasItems }: ActivityFeedProps) {
actions={<Icon icon={Activity} size={5} intent="primary" />} actions={<Icon icon={Activity} size={5} intent="primary" />}
/> />
{hasItems ? ( {hasItems ? (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}> <Stack gap={4}>
{items.slice(0, 5).map((item) => ( {items.slice(0, 5).map((item) => (
<ActivityItem <ActivityItem
key={item.id} key={item.id}
@@ -47,7 +49,7 @@ export function ActivityFeed({ items, hasItems }: ActivityFeedProps) {
)} )}
</ActivityItem> </ActivityItem>
))} ))}
</div> </Stack>
) : ( ) : (
<EmptyState <EmptyState
icon={Activity} icon={Activity}

View File

@@ -4,8 +4,8 @@ import { UpcomingRacesSidebar } from '@/components/races/UpcomingRacesSidebar';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Section } from '@/ui/Section'; import { Section } from '@/ui/Section';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
interface HomeFeatureDescriptionProps { interface HomeFeatureDescriptionProps {
lead: string; lead: string;

View File

@@ -3,8 +3,8 @@
import React from 'react'; import React from 'react';
import { Panel } from '@/ui/Panel'; import { Panel } from '@/ui/Panel';
import { Glow } from '@/ui/Glow'; import { Glow } from '@/ui/Glow';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Section } from '@/ui/Section'; import { Section } from '@/ui/Section';
@@ -19,7 +19,6 @@ interface HomeFeatureSectionProps {
/** /**
* HomeFeatureSection - A semantic section highlighting a feature. * HomeFeatureSection - A semantic section highlighting a feature.
* Refactored to use semantic HTML and Tailwind.
*/ */
export function HomeFeatureSection({ export function HomeFeatureSection({
heading, heading,
@@ -28,18 +27,6 @@ export function HomeFeatureSection({
layout, layout,
accentColor = 'primary', accentColor = 'primary',
}: HomeFeatureSectionProps) { }: HomeFeatureSectionProps) {
const accentBorderColor = {
primary: 'border-primary-accent/40',
aqua: 'border-telemetry-aqua/40',
amber: 'border-warning-amber/40',
}[accentColor];
const accentBgColor = {
primary: 'primary-accent',
aqua: 'telemetry-aqua',
amber: 'warning-amber',
}[accentColor];
const glowColor = ({ const glowColor = ({
primary: 'primary', primary: 'primary',
aqua: 'aqua', aqua: 'aqua',
@@ -47,7 +34,7 @@ export function HomeFeatureSection({
}[accentColor] || 'primary') as 'primary' | 'aqua' | 'amber' | 'purple'; }[accentColor] || 'primary') as 'primary' | 'aqua' | 'amber' | 'purple';
return ( return (
<Section variant="dark" py={24} borderBottom borderColor="border-gray" overflow="hidden" position="relative"> <Section variant="dark" padding="lg">
<Glow <Glow
color={glowColor} color={glowColor}
size="lg" size="lg"
@@ -56,31 +43,25 @@ export function HomeFeatureSection({
/> />
<Container> <Container>
<Grid cols={1} lgCols={2} gap={12} alignItems="center"> <Grid cols={{ base: 1, lg: 2 }} gap={12}>
{/* Text Content */} {/* Text Content */}
<Stack gap={8} order={{ lg: layout === 'text-right' ? 2 : 1 }}> <Stack gap={8}>
<Stack gap={4}> <Stack gap={4}>
<Stack w="12" h="1" bg={accentBgColor}>{null}</Stack> <Heading level={2} weight="bold">
<Heading level={2} fontSize={{ base: '3xl', md: '5xl' }} weight="bold" letterSpacing="tighter" lineHeight="none" color="text-white">
{heading} {heading}
</Heading> </Heading>
</Stack> </Stack>
<Stack color="text-gray-500" borderLeft borderStyle="solid" borderColor="border-gray/20" pl={6}> <Stack>
{description} {description}
</Stack> </Stack>
</Stack> </Stack>
{/* Mockup Panel */} {/* Mockup Panel */}
<Stack order={{ lg: layout === 'text-right' ? 1 : 2 }}> <Panel variant="dark">
<Panel padding={1} variant="dark" border={true} position="relative" group overflow="hidden"> <Stack align="center" justify="center">
<Stack bg="graphite-black" minHeight="300px" align="center" justify="center"> {mockup}
{mockup} </Stack>
</Stack> </Panel>
{/* Decorative corner accents */}
<Stack position="absolute" top="0" left="0" w="4" h="4" borderTop borderLeft borderColor={accentBorderColor} opacity={0.4}>{null}</Stack>
<Stack position="absolute" bottom="0" right="0" w="4" h="4" borderBottom borderRight borderColor={accentBorderColor} opacity={0.4}>{null}</Stack>
</Panel>
</Stack>
</Grid> </Grid>
</Container> </Container>
</Section> </Section>

View File

@@ -8,8 +8,8 @@ import { DiscordIcon } from '@/ui/icons/DiscordIcon';
import { Code, Lightbulb, LucideIcon, MessageSquare, Users } from 'lucide-react'; import { Code, Lightbulb, LucideIcon, MessageSquare, Users } from 'lucide-react';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Card } from '@/ui/Card'; import { Card } from '@/ui/Card';
import { Section } from '@/ui/Section'; import { Section } from '@/ui/Section';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
@@ -18,71 +18,59 @@ export function HomeFooterCTA() {
const discordUrl = process.env.NEXT_PUBLIC_DISCORD_URL || '#'; const discordUrl = process.env.NEXT_PUBLIC_DISCORD_URL || '#';
return ( return (
<Section variant="dark" py={32} borderBottom borderColor="border-gray/50" overflow="hidden" position="relative"> <Section variant="dark" padding="lg">
<Glow color="primary" size="xl" position="center" opacity={0.05} /> <Glow color="primary" size="xl" position="center" opacity={0.05} />
<Container> <Container>
<Card position="relative" overflow="hidden" variant="outline" p={{ base: 8, md: 12 }} className="bg-panel-gray/40"> <Card variant="outline">
{/* Discord brand accent */} <Stack align="center" gap={12}>
<Stack position="absolute" top={0} left={0} right={0} h="1" bg="primary-accent">{null}</Stack>
<Stack align="center" gap={12} center>
{/* Header */} {/* Header */}
<Stack align="center" gap={6}> <Stack align="center" gap={6}>
<Stack position="relative" align="center" justify="center" w={{ base: '16', md: '20' }} h={{ base: '16', md: '20' }} bg="primary-accent/10" border borderColor="primary-accent/30"> <DiscordIcon size={40} />
<DiscordIcon color="text-primary-accent" size={40} />
<Stack position="absolute" top="-1px" left="-1px" w="2" h="2" borderTop borderLeft borderColor="primary-accent">{null}</Stack>
<Stack position="absolute" bottom="-1px" right="-1px" w="2" h="2" borderBottom borderRight borderColor="primary-accent">{null}</Stack>
</Stack>
<Stack gap={4} align="center"> <Stack gap={4} align="center">
<Heading level={2} weight="bold" color="text-white" fontSize={{ base: '2xl', md: '4xl' }} letterSpacing="tight"> <Heading level={2} weight="bold" align="center">
Join the Grid on Discord Join the Grid on Discord
</Heading> </Heading>
<Stack w="16" h="1" bg="primary-accent">{null}</Stack>
</Stack> </Stack>
</Stack> </Stack>
{/* Personal message */} {/* Personal message */}
<Stack maxWidth="2xl" mx="auto" align="center"> <Stack align="center" gap={6}>
<Stack gap={6}> <Text size="lg" variant="high" weight="medium" align="center">
<Text size="lg" color="text-gray-300" weight="medium" leading="relaxed" textAlign="center"> GridPilot is a <Text as="span" variant="high" weight="bold">solo developer project</Text> built for the community.
GridPilot is a <Text as="span" color="text-white" weight="bold">solo developer project</Text> built for the community. </Text>
</Text> <Text size="base" variant="low" align="center">
<Text size="base" color="text-gray-400" weight="normal" leading="relaxed" textAlign="center"> We are in early alpha. Join us to help shape the future of motorsport infrastructure. Your feedback directly influences the roadmap.
We are in early alpha. Join us to help shape the future of motorsport infrastructure. Your feedback directly influences the roadmap. </Text>
</Text>
</Stack>
</Stack> </Stack>
{/* Benefits grid */} {/* Benefits grid */}
<Stack maxWidth="4xl" mx="auto" fullWidth> <Grid cols={{ base: 1, md: 2 }} gap={6}>
<Grid cols={1} mdCols={2} gap={6}> <BenefitItem
<BenefitItem icon={MessageSquare}
icon={MessageSquare} title="Share your pain points"
title="Share your pain points" description="Tell us what frustrates you about league racing today."
description="Tell us what frustrates you about league racing today." />
/> <BenefitItem
<BenefitItem icon={Lightbulb}
icon={Lightbulb} title="Shape the product"
title="Shape the product" description="Your ideas directly influence our roadmap."
description="Your ideas directly influence our roadmap." />
/> <BenefitItem
<BenefitItem icon={Users}
icon={Users} title="Connect with racers"
title="Connect with racers" description="Join a community of like-minded competitive drivers."
description="Join a community of like-minded competitive drivers." />
/> <BenefitItem
<BenefitItem icon={Code}
icon={Code} title="Early Access"
title="Early Access" description="Test new features before they go public."
description="Test new features before they go public." />
/> </Grid>
</Grid>
</Stack>
{/* CTA Button */} {/* CTA Button */}
<Stack gap={6} pt={4} align="center"> <Stack gap={6} align="center">
<Button <Button
as="a" as="a"
href={discordUrl} href={discordUrl}
@@ -90,19 +78,14 @@ export function HomeFooterCTA() {
rel="noopener noreferrer" rel="noopener noreferrer"
variant="primary" variant="primary"
size="lg" size="lg"
px={16}
py={4}
h="auto"
icon={<DiscordIcon size={24} />} icon={<DiscordIcon size={24} />}
> >
Join Discord Join Discord
</Button> </Button>
<Stack border borderStyle="dashed" borderColor="primary-accent/50" px={4} py={1}> <Text size="xs" variant="primary" weight="bold" font="mono" uppercase>
<Text size="xs" color="text-primary-accent" weight="bold" font="mono" uppercase letterSpacing="widest"> Early Alpha Access Available
Early Alpha Access Available </Text>
</Text>
</Stack>
</Stack> </Stack>
</Stack> </Stack>
</Card> </Card>
@@ -113,14 +96,14 @@ export function HomeFooterCTA() {
function BenefitItem({ icon, title, description }: { icon: LucideIcon, title: string, description: string }) { function BenefitItem({ icon, title, description }: { icon: LucideIcon, title: string, description: string }) {
return ( return (
<Stack direction="row" align="start" gap={5} p={6} bg="panel-gray/20" border borderColor="border-gray" className="transition-all hover:border-primary-accent/30 group"> <Card variant="dark">
<Stack align="center" justify="center" flexShrink={0} w="10" h="10" bg="primary-accent/5" border borderColor="border-gray/50" className="transition-all group-hover:border-primary-accent/30"> <Stack align="start" gap={5}>
<Icon icon={icon} size={5} color="text-primary-accent" /> <Icon icon={icon} size={5} intent="primary" />
<Stack gap={2}>
<Text size="base" weight="bold" variant="high">{title}</Text>
<Text size="sm" variant="low">{description}</Text>
</Stack>
</Stack> </Stack>
<Stack gap={2}> </Card>
<Text size="base" weight="bold" color="text-white" letterSpacing="wide">{title}</Text>
<Text size="sm" color="text-gray-400" leading="relaxed">{description}</Text>
</Stack>
</Stack>
); );
} }

View File

@@ -5,7 +5,9 @@ import { Container } from '@/ui/Container';
import { Glow } from '@/ui/Glow'; import { Glow } from '@/ui/Glow';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Section } from '@/ui/Section';
import { ButtonGroup } from '@/ui/ButtonGroup';
interface HomeHeaderProps { interface HomeHeaderProps {
title: string; title: string;
@@ -23,7 +25,6 @@ interface HomeHeaderProps {
/** /**
* HomeHeader - Semantic hero section for the landing page. * HomeHeader - Semantic hero section for the landing page.
* Follows "Precision Racing Minimal" theme.
*/ */
export function HomeHeader({ export function HomeHeader({
title, title,
@@ -33,43 +34,29 @@ export function HomeHeader({
secondaryAction, secondaryAction,
}: HomeHeaderProps) { }: HomeHeaderProps) {
return ( return (
<Stack as="header" position="relative" overflow="hidden" bg="graphite-black" py={{ base: 24, lg: 32 }} borderBottom borderColor="border-gray"> <Section variant="dark" padding="lg">
<Glow color="primary" size="xl" position="top-right" opacity={0.1} /> <Glow color="primary" size="xl" position="top-right" opacity={0.1} />
<Container> <Container>
<Stack maxWidth="4xl" fullWidth> <Stack gap={8}>
<Stack direction="row" align="center" gap={3} borderLeft borderStyle="solid" borderWidth="2px" borderColor="primary-accent" bg="primary-accent/5" px={4} py={1} mb={8}> <Text size="xs" weight="bold" uppercase variant="primary">
<Text size="xs" weight="bold" uppercase letterSpacing="0.3em" color="text-primary-accent"> {subtitle}
{subtitle} </Text>
</Text>
</Stack>
<Heading <Heading level={1} weight="bold">
level={1}
fontSize={{ base: '5xl', md: '7xl', lg: '8xl' }}
weight="bold"
color="text-white"
letterSpacing="tighter"
lineHeight="0.9"
mb={8}
>
{title} {title}
</Heading> </Heading>
<Stack borderLeft borderStyle="solid" borderColor="border-gray" pl={8} mb={12} maxWidth="2xl"> <Text size="lg" variant="low">
<Text size="lg" color="text-gray-400" leading="relaxed" opacity={0.8}> {description}
{description} </Text>
</Text>
</Stack>
<Stack direction={{ base: 'col', md: 'row' }} gap={4}> <ButtonGroup gap={4}>
<Button <Button
as="a" as="a"
href={primaryAction.href} href={primaryAction.href}
variant="primary" variant="primary"
h="14" size="lg"
px={12}
fontSize="xs"
> >
{primaryAction.label} {primaryAction.label}
</Button> </Button>
@@ -77,18 +64,13 @@ export function HomeHeader({
as="a" as="a"
href={secondaryAction.href} href={secondaryAction.href}
variant="secondary" variant="secondary"
h="14" size="lg"
px={12}
fontSize="xs"
bg="transparent"
borderColor="border-gray"
hoverBorderColor="primary-accent/50"
> >
{secondaryAction.label} {secondaryAction.label}
</Button> </Button>
</Stack> </ButtonGroup>
</Stack> </Stack>
</Container> </Container>
</Stack> </Section>
); );
} }

View File

@@ -4,58 +4,40 @@ import React from 'react';
import { MetricCard } from '@/ui/MetricCard'; import { MetricCard } from '@/ui/MetricCard';
import { Activity, Users, Trophy, Calendar } from 'lucide-react'; import { Activity, Users, Trophy, Calendar } from 'lucide-react';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/primitives/Stack';
/** /**
* HomeStatsStrip - A thin strip showing some status or quick info. * HomeStatsStrip - A thin strip showing some status or quick info.
* Part of the "Telemetry-workspace" feel. * Part of the "Telemetry-workspace" feel.
* Refactored to use semantic HTML and Tailwind.
*/ */
export function HomeStatsStrip() { export function HomeStatsStrip() {
return ( return (
<Stack bg="graphite-black" borderBottom borderTop borderColor="border-gray/30" py={0}> <Container>
<Container> <Grid cols={{ base: 2, md: 4 }} gap={4}>
<Grid cols={2} mdCols={4} gap={0} borderLeft borderRight borderColor="border-gray/30"> <MetricCard
<MetricCard label="Active Drivers"
label="Active Drivers" value="1,284"
value="1,284" icon={Users}
icon={Users} trend={{ value: 12, isPositive: true }}
trend={{ value: 12, isPositive: true }} />
border={false} <MetricCard
bg="transparent" label="Live Sessions"
/> value="42"
<Stack borderLeft borderColor="border-gray/30"> icon={Activity}
<MetricCard intent="telemetry"
label="Live Sessions" />
value="42" <MetricCard
icon={Activity} label="Total Races"
color="text-telemetry-aqua" value="15,402"
border={false} icon={Trophy}
bg="transparent" intent="warning"
/> />
</Stack> <MetricCard
<Stack borderLeft borderColor="border-gray/30"> label="Next Event"
<MetricCard value="14:00"
label="Total Races" icon={Calendar}
value="15,402" />
icon={Trophy} </Grid>
color="text-warning-amber" </Container>
border={false}
bg="transparent"
/>
</Stack>
<Stack borderLeft borderColor="border-gray/30">
<MetricCard
label="Next Event"
value="14:00"
icon={Calendar}
border={false}
bg="transparent"
/>
</Stack>
</Grid>
</Container>
</Stack>
); );
} }

View File

@@ -2,9 +2,9 @@
import { LeagueCard } from '@/components/leagues/LeagueCard'; import { LeagueCard } from '@/components/leagues/LeagueCard';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { Box } from '@/ui/primitives/Box';
interface League { interface League {
id: string; id: string;

View File

@@ -4,13 +4,11 @@ import { routes } from '@/lib/routing/RouteConfig';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text'; import { ButtonGroup } from '@/ui/ButtonGroup';
import { Stack } from '@/ui/primitives/Stack';
import { Plus, Search, Shield, Users } from 'lucide-react'; import { Plus, Search, Shield, Users } from 'lucide-react';
/** /**
* QuickLinksPanel - Semantic quick actions bar. * QuickLinksPanel - Semantic quick actions bar.
* Replaces HomeQuickActions with a more semantic implementation.
*/ */
export function QuickLinksPanel() { export function QuickLinksPanel() {
const links = [ const links = [
@@ -21,34 +19,20 @@ export function QuickLinksPanel() {
]; ];
return ( return (
<Stack as="nav" bg="panel-gray/50" py={8} borderBottom borderColor="border-gray/30"> <Container>
<Container> <ButtonGroup alignment="center" gap={4} marginTop={8}>
<Stack direction="row" wrap justify="center" gap={4}> {links.map((link) => (
{links.map((link) => ( <Button
<Button key={link.label}
key={link.label} as="a"
as="a" href={link.href}
href={link.href} variant="secondary"
variant="secondary" icon={<Icon icon={link.icon} size={4} intent="low" />}
px={6} >
bg="graphite-black" {link.label}
borderColor="border-gray/50" </Button>
className="flex items-center gap-3 transition-all hover:border-primary-accent/50 group" ))}
> </ButtonGroup>
<Icon </Container>
icon={link.icon}
size={4}
color="text-gray-500"
groupHoverTextColor="primary-accent"
transition
/>
<Text size="xs" weight="bold" uppercase letterSpacing="widest">
{link.label}
</Text>
</Button>
))}
</Stack>
</Container>
</Stack>
); );
} }

View File

@@ -5,7 +5,7 @@ import { routes } from '@/lib/routing/RouteConfig';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { Panel } from '@/ui/Panel'; import { Panel } from '@/ui/Panel';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
interface Race { interface Race {

View File

@@ -2,9 +2,9 @@
import { TeamCard } from '@/components/teams/TeamCard'; import { TeamCard } from '@/components/teams/TeamCard';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { Box } from '@/ui/primitives/Box';
interface Team { interface Team {
id: string; id: string;

View File

@@ -1,17 +1,16 @@
import { useParallax } from "@/hooks/useScrollProgress";
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Grid } from '@/ui/Grid';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { useRef } from 'react'; import { Section } from '@/ui/Section';
import { Panel } from '@/ui/Panel';
interface AlternatingSectionProps { interface AlternatingSectionProps {
heading: string; heading: string;
description: string | React.ReactNode; description: string | React.ReactNode;
mockup: React.ReactNode; mockup: React.ReactNode;
layout: 'text-left' | 'text-right'; layout: 'text-left' | 'text-right';
backgroundImage?: string;
backgroundVideo?: string;
} }
export function AlternatingSection({ export function AlternatingSection({
@@ -19,112 +18,49 @@ export function AlternatingSection({
description, description,
mockup, mockup,
layout, layout,
backgroundImage,
backgroundVideo
}: AlternatingSectionProps) { }: AlternatingSectionProps) {
const sectionRef = useRef<HTMLElement>(null); const textContent = (
const bgParallax = useParallax(sectionRef, 0.1); <Stack gap={8}>
<Stack gap={4}>
return ( <Heading level={2} weight="bold">
<Stack {heading}
as="section" </Heading>
ref={sectionRef} </Stack>
position="relative" <Stack>
overflow="hidden" {typeof description === 'string' ? (
bg="graphite-black" <Text size="lg" variant="low">{description}</Text>
py={{ base: 20, md: 32 }} ) : (
className="border-b border-border-gray" description
> )}
{backgroundVideo && ( </Stack>
<Stack
position="absolute"
inset="0"
fullWidth
fullHeight
overflow="hidden"
>
<Stack
as="video"
autoPlay
loop
muted
playsInline
fullWidth
fullHeight
objectFit="cover"
opacity={0.1}
>
<Stack as="source" src={backgroundVideo} type="video/mp4" />
</Stack>
{/* Dark overlay to ensure readability */}
<Stack position="absolute" inset="0" bg="linear-gradient(to bottom, #0C0D0F, transparent, #0C0D0F)" />
</Stack>
)}
{backgroundImage && !backgroundVideo && (
<Stack
position="absolute"
inset="0"
fullWidth
fullHeight
overflow="hidden"
>
<Stack
position="absolute"
inset="0"
bg={`url(${backgroundImage})`}
backgroundSize="cover"
backgroundPosition="center"
opacity={0.1}
style={{ transform: `translateY(${bgParallax * 0.3}px)` }}
/>
{/* Dark overlay to ensure readability */}
<Stack position="absolute" inset="0" bg="linear-gradient(to bottom, #0C0D0F, transparent, #0C0D0F)" />
</Stack>
)}
<Container size="lg" position="relative" zIndex={10}>
<Stack display="grid" gridCols={{ base: 1, lg: 2 }} gap={{ base: 12, lg: 24 }} alignItems="center">
{/* Text Content */}
<Stack
display="flex"
flexDirection="column"
gap={8}
order={{ lg: layout === 'text-right' ? 2 : 1 }}
>
<Stack gap={4}>
<Stack w="8" h="1" bg="primary-accent" />
<Heading level={2} fontSize={{ base: '3xl', md: '5xl' }} weight="bold" className="tracking-tighter uppercase leading-none">
{heading}
</Heading>
</Stack>
<Stack className="text-gray-500 border-l border-border-gray/20 pl-6">
{typeof description === 'string' ? (
<Text size="lg" leading="relaxed" weight="normal">{description}</Text>
) : (
description
)}
</Stack>
</Stack>
{/* Mockup */}
<Stack
position="relative"
order={{ lg: layout === 'text-right' ? 1 : 2 }}
className="bg-panel-gray/20 border border-border-gray/30 rounded-none p-1 shadow-2xl group"
>
<Stack
fullWidth
minHeight={{ base: '240px', md: '380px' }}
className="overflow-hidden rounded-none border border-border-gray/20 bg-graphite-black"
>
{mockup}
</Stack>
{/* Decorative corner accents */}
<Stack position="absolute" top="-1px" left="-1px" w="3" h="3" borderTop borderLeft borderColor="primary-accent/40" />
<Stack position="absolute" bottom="-1px" right="-1px" w="3" h="3" borderBottom borderRight borderColor="primary-accent/40" />
</Stack>
</Stack>
</Container>
</Stack> </Stack>
); );
const mockupContent = (
<Panel variant="dark">
<Stack align="center" justify="center">
{mockup}
</Stack>
</Panel>
);
return (
<Section variant="dark" padding="lg">
<Container size="lg">
<Grid cols={{ base: 1, lg: 2 }} gap={12}>
{layout === 'text-left' ? (
<>
{textContent}
{mockupContent}
</>
) : (
<>
{mockupContent}
{textContent}
</>
)}
</Grid>
</Container>
</Section>
);
} }

View File

@@ -1,9 +1,9 @@
import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box'; import { Surface } from '@/ui/Surface';
import { Surface } from '@/ui/primitives/Surface';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { motion, useReducedMotion } from 'framer-motion'; import { motion, useReducedMotion } from 'framer-motion';
import { LucideIcon } from 'lucide-react'; import { LucideIcon } from 'lucide-react';

View File

@@ -1,10 +1,10 @@
'use client'; 'use client';
import { routes } from '@/lib/routing/RouteConfig'; import { routes } from '@/lib/routing/RouteConfig';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Button } from '@/ui/Button'; import { Button } from '@/ui/Button';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Grid } from '@/ui/primitives/Grid'; import { Grid } from '@/ui/Grid';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';

View File

@@ -2,7 +2,7 @@
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { ChevronDown } from 'lucide-react'; import { ChevronDown } from 'lucide-react';

View File

@@ -9,7 +9,7 @@ import { StandingsTableMockup } from '@/components/mockups/StandingsTableMockup'
import { TeamCompetitionMockup } from '@/components/mockups/TeamCompetitionMockup'; import { TeamCompetitionMockup } from '@/components/mockups/TeamCompetitionMockup';
import { Container } from '@/ui/Container'; import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading'; import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/primitives/Stack'; import { Stack } from '@/ui/Stack';
import { Section } from '@/ui/Section'; import { Section } from '@/ui/Section';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';

View File

@@ -1,5 +1,5 @@
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon'; import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { LucideIcon } from 'lucide-react'; import { LucideIcon } from 'lucide-react';

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