430 lines
17 KiB
TypeScript
430 lines
17 KiB
TypeScript
'use client';
|
||
|
||
import { motion, useReducedMotion } from 'framer-motion';
|
||
import { useState, useEffect } from 'react';
|
||
import { Box } from '@/ui/Box';
|
||
import { Text } from '@/ui/Text';
|
||
import { Stack } from '@/ui/Stack';
|
||
|
||
export function TeamCompetitionMockup() {
|
||
const shouldReduceMotion = useReducedMotion();
|
||
const [hoveredDriver, setHoveredDriver] = useState<number | null>(null);
|
||
const [hoveredTeam, setHoveredTeam] = useState<number | null>(null);
|
||
const [isMobile, setIsMobile] = useState(false);
|
||
|
||
useEffect(() => {
|
||
setIsMobile(window.innerWidth < 768);
|
||
}, []);
|
||
|
||
const teamColors = ['#198CFF', '#6FE37A', '#FFC556', '#43C9E6', '#9333EA'];
|
||
|
||
if (isMobile) {
|
||
return (
|
||
<Box position="relative" fullWidth fullHeight bg="bg-gradient-to-br from-deep-graphite via-iron-gray to-deep-graphite" rounded="lg" p={3} overflow="hidden">
|
||
<Stack gap={4}>
|
||
<Box>
|
||
<Text size="sm" weight="semibold" color="text-white" mb={3} block>Drivers</Text>
|
||
<Stack gap={2}>
|
||
{[1, 2, 3].map((i) => (
|
||
<Box
|
||
key={i}
|
||
position="relative"
|
||
display="flex"
|
||
alignItems="center"
|
||
gap={2}
|
||
bg="bg-iron-gray"
|
||
rounded="lg"
|
||
p={2}
|
||
border
|
||
borderColor="border-charcoal-outline"
|
||
overflow="hidden"
|
||
>
|
||
<Box
|
||
position="absolute"
|
||
left="0"
|
||
top="0"
|
||
bottom="0"
|
||
w="1"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: teamColors[i-1] }}
|
||
/>
|
||
<Box
|
||
h="5"
|
||
w="5"
|
||
rounded="full"
|
||
display="flex"
|
||
alignItems="center"
|
||
justifyContent="center"
|
||
weight="semibold"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{
|
||
fontSize: '10px',
|
||
borderColor: teamColors[i-1],
|
||
backgroundColor: `${teamColors[i-1]}20`,
|
||
borderWidth: '2px'
|
||
}}
|
||
>
|
||
<Text color="text-white">{i}</Text>
|
||
</Box>
|
||
<Box h="6" w="6" rounded="full" display="flex" alignItems="center" justifyContent="center"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: `${teamColors[i-1]}20`, borderWidth: '1px', borderColor: teamColors[i-1], fontSize: '14px' }}
|
||
>
|
||
<Text>🏎️</Text>
|
||
</Box>
|
||
<Box flexGrow={1}>
|
||
<Box h="2.5" w="full" bg="bg-white/10" rounded="sm" />
|
||
</Box>
|
||
<Box h="3" w="10" bg="bg-charcoal-outline" rounded="sm" display="flex" alignItems="center" justifyContent="center" color="text-white" opacity={0.7}
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ fontSize: '10px' }}
|
||
/>
|
||
</Box>
|
||
))}
|
||
</Stack>
|
||
</Box>
|
||
|
||
<Box h="px"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
className="bg-gradient-to-r from-transparent via-charcoal-outline to-transparent"
|
||
/>
|
||
|
||
<Box>
|
||
<Text size="sm" weight="semibold" color="text-white" mb={3} block>Constructors</Text>
|
||
<Stack gap={2}>
|
||
{[1, 2, 3].map((i) => (
|
||
<Box
|
||
key={i}
|
||
position="relative"
|
||
display="flex"
|
||
alignItems="center"
|
||
gap={2}
|
||
bg="bg-iron-gray"
|
||
rounded="lg"
|
||
p={2}
|
||
border
|
||
borderColor="border-charcoal-outline"
|
||
overflow="hidden"
|
||
>
|
||
<Box
|
||
position="absolute"
|
||
left="0"
|
||
top="0"
|
||
bottom="0"
|
||
w="1"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: teamColors[i-1] }}
|
||
/>
|
||
<Box
|
||
h="6"
|
||
w="6"
|
||
rounded="sm"
|
||
display="flex"
|
||
alignItems="center"
|
||
justifyContent="center"
|
||
border
|
||
borderWidth="2px"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{
|
||
borderColor: teamColors[i-1],
|
||
backgroundColor: `${teamColors[i-1]}20`,
|
||
fontSize: '14px'
|
||
}}
|
||
>
|
||
<Text>🏁</Text>
|
||
</Box>
|
||
<Box flexGrow={1}>
|
||
<Box h="2.5" w="full" bg="bg-white/10" rounded="sm" mb={1} />
|
||
<Box position="relative" h="1.5" bg="bg-charcoal-outline" rounded="full" overflow="hidden">
|
||
<Box
|
||
position="absolute"
|
||
insetY="0"
|
||
left="0"
|
||
rounded="full"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: teamColors[i-1], width: `${100 - (i-1) * 15}%` }}
|
||
/>
|
||
</Box>
|
||
</Box>
|
||
</Box>
|
||
))}
|
||
</Stack>
|
||
</Box>
|
||
</Stack>
|
||
</Box>
|
||
);
|
||
}
|
||
|
||
const leftColumnVariants = {
|
||
hidden: { opacity: 0, x: shouldReduceMotion ? 0 : -20 },
|
||
visible: {
|
||
opacity: 1,
|
||
x: 0,
|
||
transition: {
|
||
type: 'spring' as const,
|
||
stiffness: 100,
|
||
damping: 20
|
||
}
|
||
}
|
||
};
|
||
|
||
const rightColumnVariants = {
|
||
hidden: { opacity: 0, x: shouldReduceMotion ? 0 : 20 },
|
||
visible: {
|
||
opacity: 1,
|
||
x: 0,
|
||
transition: {
|
||
type: 'spring' as const,
|
||
stiffness: 100,
|
||
damping: 20
|
||
}
|
||
}
|
||
};
|
||
|
||
const rowVariants = {
|
||
hidden: { opacity: 0, scale: shouldReduceMotion ? 1 : 0.95 },
|
||
visible: (i: number) => ({
|
||
opacity: 1,
|
||
scale: 1,
|
||
transition: {
|
||
delay: shouldReduceMotion ? 0 : 0.3 + i * 0.05,
|
||
type: 'spring' as const,
|
||
stiffness: 300,
|
||
damping: 25
|
||
}
|
||
})
|
||
};
|
||
|
||
return (
|
||
<Box position="relative" fullWidth fullHeight bg="bg-gradient-to-br from-deep-graphite via-iron-gray to-deep-graphite" rounded="lg" p={{ base: 1.5, sm: 3, md: 4, lg: 6 }} overflow="hidden">
|
||
<Box display="grid" gridCols={2} gap={{ base: 2, sm: 3, md: 4, lg: 6 }} fullHeight>
|
||
<Box
|
||
as={motion.div}
|
||
variants={leftColumnVariants}
|
||
initial="hidden"
|
||
animate="visible"
|
||
position="relative"
|
||
>
|
||
<Box h={{ base: 3, sm: 4, md: 5 }} w={{ base: 16, sm: 20, md: 24 }} bg="bg-white/10" rounded="sm" mb={{ base: 1.5, sm: 2, md: 3, lg: 4 }} display="flex" alignItems="center" justifyContent="center">
|
||
<Text
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ fontSize: '10px' }}
|
||
color="text-white"
|
||
weight="semibold"
|
||
>
|
||
Drivers
|
||
</Text>
|
||
</Box>
|
||
<Stack gap={{ base: 1, sm: 1.5, md: 2 }}>
|
||
{[1, 2, 3, 4, 5].map((i) => (
|
||
<Box
|
||
key={i}
|
||
as={motion.div}
|
||
custom={i}
|
||
variants={rowVariants}
|
||
initial="hidden"
|
||
animate="visible"
|
||
position="relative"
|
||
display="flex"
|
||
alignItems="center"
|
||
gap={{ base: 1.5, sm: 2, md: 2.5, lg: 3 }}
|
||
bg="bg-iron-gray"
|
||
rounded="lg"
|
||
p={{ base: 1, sm: 1.5, md: 2, lg: 2.5 }}
|
||
border
|
||
borderColor="border-charcoal-outline"
|
||
overflow="hidden"
|
||
onHoverStart={() => !shouldReduceMotion && setHoveredDriver(i)}
|
||
onHoverEnd={() => setHoveredDriver(null)}
|
||
whileHover={shouldReduceMotion ? {} : {
|
||
scale: 1.02,
|
||
boxShadow: `0 0 20px ${teamColors[i-1]}40`,
|
||
transition: { duration: 0.15 }
|
||
}}
|
||
>
|
||
<Box
|
||
position="absolute"
|
||
left="0"
|
||
top="0"
|
||
bottom="0"
|
||
w="0.5"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: teamColors[i-1] }}
|
||
/>
|
||
<Box
|
||
h={{ base: 3.5, sm: 4, md: 5 }}
|
||
w={{ base: 3.5, sm: 4, md: 5 }}
|
||
rounded="full"
|
||
display="flex"
|
||
alignItems="center"
|
||
justifyContent="center"
|
||
weight="semibold"
|
||
border
|
||
borderWidth="2px"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{
|
||
fontSize: '10px',
|
||
borderColor: teamColors[i-1],
|
||
backgroundColor: `${teamColors[i-1]}20`
|
||
}}
|
||
>
|
||
<Text color="text-white">{i}</Text>
|
||
</Box>
|
||
<Box h={{ base: 5, sm: 6, md: 7 }} w={{ base: 5, sm: 6, md: 7 }} rounded="full" display="flex" alignItems="center" justifyContent="center"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: `${teamColors[i-1]}20`, borderWidth: '1px', borderColor: teamColors[i-1], fontSize: '12px' }}
|
||
>
|
||
<Text>🏎️</Text>
|
||
</Box>
|
||
<Box flexGrow={1} minWidth="0">
|
||
<Box h={{ base: 1.5, sm: 2, md: 2.5 }} w="full" bg="bg-white/10" rounded="sm" />
|
||
</Box>
|
||
<Box h={{ base: 2, sm: 2.5, md: 3 }} w={{ base: 8, sm: 10, md: 12 }} bg="bg-charcoal-outline" rounded="sm" font="mono" display="flex" alignItems="center" justifyContent="center" color="text-white" opacity={0.7}
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ fontSize: '10px' }}
|
||
/>
|
||
{hoveredDriver === i && (
|
||
<Box
|
||
as={motion.div}
|
||
position="absolute"
|
||
inset="0"
|
||
pointerEvents="none"
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{
|
||
background: `linear-gradient(90deg, ${teamColors[i-1]}10 0%, transparent 100%)`
|
||
}}
|
||
/>
|
||
)}
|
||
</Box>
|
||
))}
|
||
</Stack>
|
||
</Box>
|
||
|
||
<Box position="absolute" left="1/2" top="8" bottom="8" w="px"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
className="bg-gradient-to-b from-transparent via-charcoal-outline to-transparent backdrop-blur-sm"
|
||
/>
|
||
|
||
<Box
|
||
as={motion.div}
|
||
variants={rightColumnVariants}
|
||
initial="hidden"
|
||
animate="visible"
|
||
position="relative"
|
||
>
|
||
<Box h={{ base: 3, sm: 4, md: 5 }} w={{ base: 20, sm: 24, md: 32 }} bg="bg-white/10" rounded="sm" mb={{ base: 1.5, sm: 2, md: 3, lg: 4 }} display="flex" alignItems="center" justifyContent="center">
|
||
<Text
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ fontSize: '10px' }}
|
||
color="text-white"
|
||
weight="semibold"
|
||
>
|
||
Constructors
|
||
</Text>
|
||
</Box>
|
||
<Stack gap={{ base: 1, sm: 1.5, md: 2 }}>
|
||
{[1, 2, 3, 4, 5].map((i) => (
|
||
<Box
|
||
key={i}
|
||
as={motion.div}
|
||
custom={i}
|
||
variants={rowVariants}
|
||
initial="hidden"
|
||
animate="visible"
|
||
position="relative"
|
||
display="flex"
|
||
alignItems="center"
|
||
gap={{ base: 1.5, sm: 2, md: 2.5, lg: 3 }}
|
||
bg="bg-iron-gray"
|
||
rounded="lg"
|
||
p={{ base: 1, sm: 1.5, md: 2, lg: 2.5 }}
|
||
border
|
||
borderColor="border-charcoal-outline"
|
||
overflow="hidden"
|
||
onHoverStart={() => !shouldReduceMotion && setHoveredTeam(i)}
|
||
onHoverEnd={() => setHoveredTeam(null)}
|
||
whileHover={shouldReduceMotion ? {} : {
|
||
scale: 1.02,
|
||
boxShadow: `0 0 20px ${teamColors[i-1]}40`,
|
||
transition: { duration: 0.15 }
|
||
}}
|
||
>
|
||
<Box
|
||
position="absolute"
|
||
left="0"
|
||
top="0"
|
||
bottom="0"
|
||
w="0.5"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: teamColors[i-1] }}
|
||
/>
|
||
<Box
|
||
h={{ base: 5, sm: 6, md: 7 }}
|
||
w={{ base: 5, sm: 6, md: 7 }}
|
||
rounded="sm"
|
||
display="flex"
|
||
alignItems="center"
|
||
justifyContent="center"
|
||
border
|
||
borderWidth="2px"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{
|
||
fontSize: '12px',
|
||
borderColor: teamColors[i-1],
|
||
backgroundColor: `${teamColors[i-1]}20`
|
||
}}
|
||
>
|
||
<Text>🏁</Text>
|
||
</Box>
|
||
<Box flexGrow={1} minWidth="0">
|
||
<Box h={{ base: 1.5, sm: 2, md: 2.5 }} w="full" bg="bg-white/10" rounded="sm" mb={{ base: 0.5, sm: 1, md: 1.5 }} />
|
||
<Box position="relative" h={{ base: 0.5, sm: 1, md: 1.5 }} bg="bg-charcoal-outline" rounded="full" overflow="hidden">
|
||
<Box
|
||
as={motion.div}
|
||
position="absolute"
|
||
insetY="0"
|
||
left="0"
|
||
rounded="full"
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ backgroundColor: teamColors[i-1] }}
|
||
initial={{ width: '0%' }}
|
||
animate={{ width: `${100 - (i-1) * 15}%` }}
|
||
transition={{ duration: shouldReduceMotion ? 0 : 0.8, delay: 0.4 + i * 0.05 }}
|
||
/>
|
||
</Box>
|
||
</Box>
|
||
{i === 3 && (
|
||
<Box h={{ base: 3, sm: 3.5, md: 4 }} px={{ base: 0.5, sm: 1, md: 1.5 }} bg="bg-warning-amber/20" rounded="sm" display="flex" alignItems="center" justifyContent="center" color="text-warning-amber" weight="semibold" border borderColor="border-warning-amber/30">
|
||
<Text
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{ fontSize: '10px' }}
|
||
>
|
||
=
|
||
</Text>
|
||
</Box>
|
||
)}
|
||
{hoveredTeam === i && (
|
||
<Box
|
||
as={motion.div}
|
||
position="absolute"
|
||
inset="0"
|
||
pointerEvents="none"
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
// eslint-disable-next-line gridpilot-rules/component-classification
|
||
style={{
|
||
background: `linear-gradient(90deg, ${teamColors[i-1]}10 0%, transparent 100%)`
|
||
}}
|
||
/>
|
||
)}
|
||
</Box>
|
||
))}
|
||
</Stack>
|
||
</Box>
|
||
</Box>
|
||
</Box>
|
||
);
|
||
}
|