website refactor

This commit is contained in:
2026-01-19 02:14:53 +01:00
parent 489c5f7858
commit a8731e6937
70 changed files with 2908 additions and 2423 deletions

View File

@@ -0,0 +1,22 @@
'use client';
import { ReactNode } from 'react';
import { Container } from '@/ui/Container';
import { Stack } from '@/ui/Stack';
import { Box } from '@/ui/Box';
interface AdminDashboardLayoutProps {
children: ReactNode;
}
export function AdminDashboardLayout({ children }: AdminDashboardLayoutProps) {
return (
<Container size="lg">
<Box paddingY={8}>
<Stack gap={8}>
{children}
</Stack>
</Box>
</Container>
);
}

View File

@@ -0,0 +1,24 @@
'use client';
import { ReactNode } from 'react';
import { SharedBox, SharedStack, SharedContainer } from '@/components/shared/UIComponents';
interface CreateLeagueWizardLayoutProps {
children: ReactNode;
header: ReactNode;
progress: ReactNode;
navigation: ReactNode;
footer: ReactNode;
}
export function CreateLeagueWizardLayout({ children, header, progress, navigation, footer }: CreateLeagueWizardLayoutProps) {
return (
<SharedBox as="main" maxWidth="4xl" mx="auto" pb={8}>
{header}
{progress}
{children}
{navigation}
{footer}
</SharedBox>
);
}

View File

@@ -0,0 +1,56 @@
'use client';
import { ReactNode } from 'react';
import { Box } from '@/ui/Box';
import { Container } from '@/ui/Container';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface RacesAllLayoutProps {
children: ReactNode;
header: ReactNode;
stats: ReactNode;
pagination: ReactNode;
}
export function RacesAllLayout({ children, header, stats, pagination }: RacesAllLayoutProps) {
return (
<Box as="main" minHeight="screen" bg="bg-base-black" py={8}>
<Container size="lg">
<Stack gap={8}>
{header}
{stats}
{children}
{pagination}
</Stack>
</Container>
</Box>
);
}
export function RacesAllStats({ count, onFilterClick }: { count: number, onFilterClick: () => void }) {
return (
<Box display="flex" justifyContent="between" alignItems="center">
<Text size="sm" color="text-gray-400">
Showing <Text as="span" color="text-white" weight="bold">{count}</Text> races
</Text>
<Box
as="button"
onClick={onFilterClick}
px={4}
py={2}
bg="bg-surface-charcoal"
border
borderColor="border-outline-steel"
fontSize="10px"
weight="bold"
letterSpacing="wider"
hoverBorderColor="border-primary-accent"
transition
className="uppercase"
>
Filters
</Box>
</Box>
);
}

View File

@@ -0,0 +1,48 @@
'use client';
import { ReactNode } from 'react';
import { Box } from '@/ui/Box';
import { Container } from '@/ui/Container';
import { Stack } from '@/ui/Stack';
import { Grid } from '@/ui/Grid';
import { GridItem } from '@/ui/GridItem';
import { Text } from '@/ui/Text';
interface RacesLayoutProps {
children: ReactNode;
header: ReactNode;
banner?: ReactNode;
sidebar: ReactNode;
}
export function RacesLayout({ children, header, banner, sidebar }: RacesLayoutProps) {
return (
<Box as="main" minHeight="screen" bg="bg-base-black" py={8}>
<Container size="lg">
<Stack gap={8}>
{header}
{banner}
<Grid cols={12} gap={6}>
<GridItem colSpan={12} lgSpan={8}>
{children}
</GridItem>
<GridItem colSpan={12} lgSpan={4}>
{sidebar}
</GridItem>
</Grid>
</Stack>
</Container>
</Box>
);
}
export function RaceScheduleSection({ children, title }: { children: ReactNode, title: string }) {
return (
<Box as="section" bg="bg-surface-charcoal" border borderColor="border-outline-steel" overflow="hidden">
<Box p={4} borderBottom borderColor="border-outline-steel" bg="bg-base-black" bgOpacity={0.2}>
<Text size="xs" weight="bold" color="text-gray-500" uppercase letterSpacing="widest">{title}</Text>
</Box>
{children}
</Box>
);
}

View File

@@ -0,0 +1,26 @@
'use client';
import { LucideIcon } from 'lucide-react';
import { EmptyState } from '@/ui/EmptyState';
interface SharedEmptyStateProps {
icon: LucideIcon;
title: string;
description?: string;
action?: {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'race-final' | 'discord';
};
}
export function SharedEmptyState({ icon, title, description, action }: SharedEmptyStateProps) {
return (
<EmptyState
icon={icon}
title={title}
description={description}
action={action}
/>
);
}

View File

@@ -0,0 +1,42 @@
import { Pagination } from '@/ui/Pagination';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Container } from '@/ui/Container';
import { ConfirmDialog } from '@/ui/ConfirmDialog';
import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon';
import { Card } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
import { Grid } from '@/ui/Grid';
import { GridItem } from '@/ui/GridItem';
import { Surface } from '@/ui/Surface';
import { Input } from '@/ui/Input';
import { Link } from '@/ui/Link';
import { Skeleton } from '@/ui/Skeleton';
import { LoadingSpinner } from '@/ui/LoadingSpinner';
import { Badge } from '@/ui/Badge';
import { ProgressLine } from '@/ui/ProgressLine';
export {
Pagination as SharedPagination,
Text as SharedText,
Box as SharedBox,
Stack as SharedStack,
Container as SharedContainer,
ConfirmDialog as SharedConfirmDialog,
Button as SharedButton,
Icon as SharedIcon,
Card as SharedCard,
Heading as SharedHeading,
Grid as SharedGrid,
GridItem as SharedGridItem,
Surface as SharedSurface,
Input as SharedInput,
Link as SharedLink,
Skeleton as SharedSkeleton,
LoadingSpinner as SharedLoadingSpinner,
Badge as SharedBadge,
ProgressLine as SharedProgressLine
};

View File

@@ -40,7 +40,7 @@ export interface PageWrapperProps<TData> {
/** Retry function for errors */
retry?: () => void;
/** Template component that receives the data */
Template: React.ComponentType<{ data: TData }>;
Template: React.ComponentType<{ viewData: TData }>;
/** Loading configuration */
loading?: PageWrapperLoadingConfig;
/** Error configuration */
@@ -162,7 +162,7 @@ export function PageWrapper<TData>({
// 4. Success State - Render Template with data
return (
<React.Fragment>
<Template data={data} />
<Template viewData={data} />
{children}
</React.Fragment>
);

View File

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

View File

@@ -0,0 +1,45 @@
'use client';
import { ReactNode } from 'react';
import { Box } from '@/ui/Box';
import { Container } from '@/ui/Container';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
interface TeamsDirectoryProps {
children: ReactNode;
title?: string;
subtitle?: string;
}
export function TeamsDirectory({ children, title, subtitle }: TeamsDirectoryProps) {
return (
<Box as="main" bg="base-black" minHeight="screen">
<Container size="lg">
<Box paddingY={12}>
<Stack gap={10}>
{title && (
<Stack direction="row" align="center" gap={2} mb={6}>
<Box w="2" h="2" bg="primary-accent" />
<Text size="xs" weight="bold" color="text-gray-400" uppercase>{title}</Text>
</Stack>
)}
{children}
</Stack>
</Box>
</Container>
</Box>
);
}
export function TeamsDirectorySection({ children, title, accentColor = "primary-accent" }: { children: ReactNode, title: string, accentColor?: string }) {
return (
<Box>
<Stack direction="row" align="center" gap={2} mb={6}>
<Box w="2" h="2" bg={accentColor} />
<Text size="xs" weight="bold" color="text-gray-400" uppercase>{title}</Text>
</Stack>
{children}
</Box>
);
}