website refactor
This commit is contained in:
22
apps/website/components/admin/AdminDashboardLayout.tsx
Normal file
22
apps/website/components/admin/AdminDashboardLayout.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
24
apps/website/components/leagues/CreateLeagueWizardLayout.tsx
Normal file
24
apps/website/components/leagues/CreateLeagueWizardLayout.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
56
apps/website/components/races/RacesAllLayout.tsx
Normal file
56
apps/website/components/races/RacesAllLayout.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
48
apps/website/components/races/RacesLayout.tsx
Normal file
48
apps/website/components/races/RacesLayout.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
26
apps/website/components/shared/SharedEmptyState.tsx
Normal file
26
apps/website/components/shared/SharedEmptyState.tsx
Normal 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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
42
apps/website/components/shared/UIComponents.tsx
Normal file
42
apps/website/components/shared/UIComponents.tsx
Normal 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
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
45
apps/website/components/teams/TeamsDirectory.tsx
Normal file
45
apps/website/components/teams/TeamsDirectory.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user