website refactor
This commit is contained in:
129
apps/website/ui/AlternatingSection.tsx
Normal file
129
apps/website/ui/AlternatingSection.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
|
||||
import { useParallax } from "@/hooks/useScrollProgress";
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Container } from '@/ui/Container';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { useRef } from 'react';
|
||||
|
||||
interface AlternatingSectionProps {
|
||||
heading: string;
|
||||
description: string | React.ReactNode;
|
||||
mockup: React.ReactNode;
|
||||
layout: 'text-left' | 'text-right';
|
||||
backgroundImage?: string;
|
||||
backgroundVideo?: string;
|
||||
}
|
||||
|
||||
export function AlternatingSection({
|
||||
heading,
|
||||
description,
|
||||
mockup,
|
||||
layout,
|
||||
backgroundImage,
|
||||
backgroundVideo
|
||||
}: AlternatingSectionProps) {
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
|
||||
const bgParallax = useParallax(sectionRef, 0.2);
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="section"
|
||||
ref={sectionRef}
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
bg="bg-deep-graphite"
|
||||
px={{ base: 'calc(1rem+var(--sal))', lg: 8 }}
|
||||
py={{ base: 20, sm: 24, md: 32 }}
|
||||
>
|
||||
{backgroundVideo && (
|
||||
<>
|
||||
<Box
|
||||
as="video"
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
position="absolute"
|
||||
inset="0"
|
||||
fullWidth
|
||||
fullHeight
|
||||
objectFit="cover"
|
||||
opacity={0.2}
|
||||
maskImage="radial-gradient(ellipse at center, black 0%, rgba(0,0,0,0.8) 40%, transparent 70%)"
|
||||
webkitMaskImage="radial-gradient(ellipse at center, black 0%, rgba(0,0,0,0.8) 40%, transparent 70%)"
|
||||
>
|
||||
<Box as="source" src={backgroundVideo} type="video/mp4" />
|
||||
</Box>
|
||||
{/* Racing red accent for sections with background videos */}
|
||||
<Box position="absolute" top="0" left="0" right="0" h="px" bg="linear-gradient(to right, transparent, rgba(239, 68, 68, 0.3), transparent)" />
|
||||
</>
|
||||
)}
|
||||
{backgroundImage && !backgroundVideo && (
|
||||
<>
|
||||
<Box
|
||||
position="absolute"
|
||||
inset="0"
|
||||
bg={`url(${backgroundImage})`}
|
||||
backgroundSize="cover"
|
||||
backgroundPosition="center"
|
||||
maskImage="radial-gradient(ellipse at center, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.1) 40%, transparent 70%)"
|
||||
webkitMaskImage="radial-gradient(ellipse at center, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.1) 40%, transparent 70%)"
|
||||
transform={`translateY(${bgParallax * 0.3}px)`}
|
||||
/>
|
||||
{/* Racing red accent for sections with background images */}
|
||||
<Box position="absolute" top="0" left="0" right="0" h="px" bg="linear-gradient(to right, transparent, rgba(239, 68, 68, 0.3), transparent)" />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Carbon fiber texture on sections without images or videos */}
|
||||
{!backgroundImage && !backgroundVideo && (
|
||||
<Box position="absolute" inset="0" opacity={0.3} bg="carbon-fiber" />
|
||||
)}
|
||||
|
||||
{/* Checkered pattern accent */}
|
||||
<Box position="absolute" inset="0" opacity={0.1} bg="checkered-pattern" />
|
||||
|
||||
<Container size="lg" position="relative" zIndex={10}>
|
||||
<Box display="grid" gridCols={{ base: 1, lg: 2 }} gap={{ base: 8, md: 12, lg: 16 }} alignItems="center">
|
||||
{/* Text Content - Always first on mobile, respects layout on desktop */}
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
gap={{ base: 4, md: 6, lg: 8 }}
|
||||
order={{ lg: layout === 'text-right' ? 2 : 1 }}
|
||||
>
|
||||
<Heading level={2} fontSize={{ base: 'xl', md: '2xl', lg: '3xl', xl: '4xl' }} weight="medium" style={{ background: 'linear-gradient(to right, #dc2626, #ffffff, #2563eb)', backgroundClip: 'text', WebkitBackgroundClip: 'text', color: 'transparent', filter: 'drop-shadow(0 0 15px rgba(220,0,0,0.4))', WebkitTextStroke: '0.5px rgba(220,0,0,0.2)' }}>
|
||||
{heading}
|
||||
</Heading>
|
||||
<Box display="flex" flexDirection="column" gap={{ base: 3, md: 5 }}>
|
||||
<Text size={{ base: 'sm', md: 'base', lg: 'lg' }} color="text-slate-400" weight="light" leading="relaxed">
|
||||
{description}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Mockup - Always second on mobile, respects layout on desktop */}
|
||||
<Box
|
||||
position="relative"
|
||||
order={{ lg: layout === 'text-right' ? 1 : 2 }}
|
||||
group
|
||||
>
|
||||
<Box
|
||||
fullWidth
|
||||
minHeight={{ base: '240px', md: '380px', lg: '440px' }}
|
||||
transition
|
||||
hoverScale
|
||||
maskImage={`linear-gradient(to ${layout === 'text-left' ? 'right' : 'left'}, white 50%, rgba(255,255,255,0.8) 70%, rgba(255,255,255,0.4) 85%, transparent 100%)`}
|
||||
webkitMaskImage={`linear-gradient(to ${layout === 'text-left' ? 'right' : 'left'}, white 50%, rgba(255,255,255,0.8) 70%, rgba(255,255,255,0.4) 85%, transparent 100%)`}
|
||||
>
|
||||
{mockup}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Container>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user