Files
gridpilot.gg/apps/website/components/mockups/TeamCompetitionMockup.tsx
2026-01-15 17:12:24 +01:00

430 lines
17 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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>
);
}