Files
gridpilot.gg/apps/website/components/landing/BenefitCard.tsx
2026-01-19 18:01:30 +01:00

119 lines
3.1 KiB
TypeScript

import { Box } from '@/ui/Box';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
import { motion, useReducedMotion } from 'framer-motion';
import { LucideIcon } from 'lucide-react';
import { useEffect, useState } from 'react';
interface BenefitCardProps {
icon: LucideIcon;
title: string;
description: string;
stats?: {
value: string;
label: string;
};
variant?: 'default' | 'highlight';
delay?: number;
}
export function BenefitCard({
icon,
title,
description,
stats,
variant = 'default',
delay = 0,
}: BenefitCardProps) {
const shouldReduceMotion = useReducedMotion();
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
const isHighlight = variant === 'highlight';
const cardContent = (
<Surface
variant="muted"
rounded="xl"
border={true}
padding={6}
borderColor={isHighlight ? 'rgba(25, 140, 255, 0.3)' : 'var(--ui-color-border-low)'}
hoverBorderColor={isHighlight ? 'rgba(25, 140, 255, 0.5)' : 'var(--ui-color-border-default)'}
transition="all 0.3s ease"
group
position="relative"
fullHeight
bg={isHighlight ? 'linear-gradient(to bottom right, rgba(25, 140, 255, 0.1), rgba(25, 140, 255, 0.05))' : undefined}
>
{/* Icon */}
<Box
width="12"
height="12"
rounded="xl"
display="flex"
center
mb={4}
bg={isHighlight ? 'rgba(25, 140, 255, 0.2)' : 'var(--ui-color-bg-surface-muted)'}
border={!isHighlight}
borderColor="var(--ui-color-border-low)"
>
<Icon icon={icon} size={6} intent={isHighlight ? 'primary' : 'low'} />
</Box>
{/* Content */}
<Heading level={3} mb={2}>{title}</Heading>
<Text size="sm" variant="low" block leading="relaxed">{description}</Text>
{/* Stats */}
{stats && (
<Box mt={4} pt={4} borderTop={true} borderColor="var(--ui-color-border-low)">
<Box display="flex" alignItems="baseline" gap={2}>
<Text size="2xl" weight="bold" variant={isHighlight ? 'primary' : 'high'}>
{stats.value}
</Text>
<Text size="sm" variant="low">{stats.label}</Text>
</Box>
</Box>
)}
{/* Highlight Glow Effect */}
{isHighlight && (
<Box
position="absolute"
inset="0"
rounded="xl"
bg="linear-gradient(to bottom right, rgba(25, 140, 255, 0.2), transparent)"
opacity={0}
groupHoverOpacity={1}
transition="opacity 0.3s ease"
pointerEvents="none"
/>
)}
</Surface>
);
if (!isMounted || shouldReduceMotion) {
return <Box fullHeight>{cardContent}</Box>;
}
return (
<Box
as={motion.div}
fullHeight
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
>
{cardContent}
</Box>
);
}