Files
gridpilot.gg/apps/website/ui/TeamCard.tsx
2026-01-15 19:55:46 +01:00

178 lines
4.9 KiB
TypeScript

import {
ChevronRight,
Globe,
UserPlus,
Users
} from 'lucide-react';
import { ReactNode } from 'react';
import { Badge } from './Badge';
import { Box } from './Box';
import { Card } from './Card';
import { Heading } from './Heading';
import { Icon } from './Icon';
import { Image } from './Image';
import { PlaceholderImage } from './PlaceholderImage';
import { Stack } from './Stack';
import { Text } from './Text';
interface TeamCardProps {
name: string;
description?: string;
logo?: string;
memberCount: number;
isRecruiting?: boolean;
performanceBadge?: ReactNode;
specializationContent?: ReactNode;
categoryBadge?: ReactNode;
region?: string;
languagesContent?: ReactNode;
statsContent?: ReactNode;
onClick?: () => void;
}
export function TeamCard({
name,
description,
logo,
memberCount,
isRecruiting,
performanceBadge,
specializationContent,
categoryBadge,
region,
languagesContent,
statsContent,
onClick,
}: TeamCardProps) {
return (
<Box onClick={onClick} h="full" cursor={onClick ? 'pointer' : 'default'}>
<Card h="full" p={0} display="flex" flexDirection="col" overflow="hidden">
{/* Header with Logo */}
<Box p={4} pb={0}>
<Stack direction="row" align="start" gap={4}>
{/* Logo */}
<Box
w="14"
h="14"
rounded="lg"
bg="bg-deep-graphite"
display="flex"
center
overflow="hidden"
border
borderColor="border-charcoal-outline"
>
{logo ? (
<Image
src={logo}
alt={name}
width={56}
height={56}
fullWidth
fullHeight
objectFit="cover"
/>
) : (
<PlaceholderImage size={56} />
)}
</Box>
{/* Title & Badges */}
<Box flexGrow={1} minWidth="0">
<Stack direction="row" align="start" justify="between" gap={2}>
<Heading level={4}>
{name}
</Heading>
{isRecruiting && (
<Badge variant="success" icon={UserPlus}>
Recruiting
</Badge>
)}
</Stack>
{/* Performance Level & Category */}
<Stack direction="row" align="center" gap={2} wrap mt={1.5}>
{performanceBadge}
{specializationContent}
{categoryBadge}
</Stack>
</Box>
</Stack>
</Box>
{/* Content */}
<Box p={4} display="flex" flexDirection="col" flexGrow={1}>
{/* Description */}
<Text
size="xs"
color="text-gray-500"
mb={3}
lineClamp={2}
block
>
{description || 'No description available'}
</Text>
{/* Region & Languages */}
{(region || languagesContent) && (
<Stack direction="row" align="center" gap={2} wrap mb={3}>
{region && (
<Box
display="flex"
alignItems="center"
gap={1.5}
px={2}
py={1}
rounded="md"
bg="bg-iron-gray/50"
border
style={{ borderColor: 'rgba(38, 38, 38, 0.3)' }}
>
<Icon icon={Globe} size={3} color="var(--neon-aqua)" />
<Text size="xs" color="text-gray-400">{region}</Text>
</Box>
)}
{languagesContent}
</Stack>
)}
{/* Stats Grid */}
{statsContent && (
<Box display="grid" gridCols={3} gap={2} mb={4}>
{statsContent}
</Box>
)}
{/* Spacer */}
<Box flexGrow={1} />
{/* Footer */}
<Box
display="flex"
alignItems="center"
justifyContent="between"
pt={3}
borderTop
style={{ borderColor: 'rgba(38, 38, 38, 0.5)' }}
mt="auto"
>
<Stack direction="row" align="center" gap={2}>
<Icon icon={Users} size={3} color="var(--text-gray-600)" />
<Text size="xs" color="text-gray-500">
{memberCount} {memberCount === 1 ? 'member' : 'members'}
</Text>
</Stack>
<Stack direction="row" align="center" gap={1}>
<Text size="xs" color="text-gray-500">View</Text>
<Icon icon={ChevronRight} size={3} color="var(--text-gray-600)" />
</Stack>
</Box>
</Box>
</Card>
</Box>
);
}