hero entrance

This commit is contained in:
2026-01-26 22:04:49 +01:00
parent 0094871358
commit 615757963c

View File

@@ -1,6 +1,7 @@
'use client';
import React, { useState, useEffect } from 'react';
import React from 'react';
import { motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { Container, Button, Section, Heading } from '@/components/ui';
import Scribble from '@/components/Scribble';
@@ -9,50 +10,160 @@ import HeroIllustration from './HeroIllustration';
export default function Hero() {
const t = useTranslations('Home.hero');
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<Section className="relative min-h-[85vh] md:h-[90vh] flex items-center justify-center overflow-hidden bg-primary py-12 md:py-0 lg:py-0">
<div className={`absolute inset-0 z-0 opacity-0 scale-[0.96] blur-lg transition-all duration-[2200ms] ease-out delay-[50ms] ${mounted ? 'opacity-100 scale-100 blur-0' : ''}`}>
<motion.div
className="absolute inset-0 z-0"
initial={{ opacity: 0, scale: 0.95, filter: 'blur(20px)' }}
animate={{ opacity: 1, scale: 1, filter: 'blur(0px)' }}
transition={{ duration: 2.2, ease: 'easeOut', delay: 0.05 }}
>
<HeroIllustration />
</div>
</motion.div>
<Container className="relative z-10 text-left text-white w-full">
<div className="max-w-5xl">
<Heading level={1} className="mb-6 md:mb-8 max-w-[12ch] md:max-w-none text-white text-4xl sm:text-5xl md:text-7xl opacity-0 translate-y-12 scale-[0.88] transition-all duration-[1400ms] ease-out delay-[450ms] ${mounted ? 'opacity-100 translate-y-0 scale-100' : ''}">
{t.rich('title', {
green: (chunks) => (
<span className="relative inline-block">
<span className={`relative z-10 text-accent italic opacity-0 scale-[0.92] transition-all duration-[900ms] ease-out delay-[650ms] ${mounted ? 'opacity-100 scale-100' : ''}`}>{chunks}</span>
<Scribble variant="circle" className={`w-[140%] h-[140%] -top-[20%] -left-[20%] text-accent/30 hidden md:block opacity-0 scale-0 origin-center transition-all duration-[800ms] ease-out delay-[850ms] ${mounted ? 'opacity-100 scale-100' : ''}`} />
</span>
)
})}
</Heading>
<p className="text-lg md:text-xl text-white/90 leading-relaxed max-w-2xl mb-10 md:mb-12 opacity-0 translate-y-8 scale-[0.94] transition-all duration-[1100ms] ease-out delay-[850ms] ${mounted ? 'opacity-100 translate-y-0 scale-100' : ''}">
{t('subtitle')}
</p>
<div className="flex flex-col sm:flex-row gap-4 md:gap-6">
<Button href="/contact" variant="accent" size="lg" className="group w-full sm:w-auto h-14 md:h-16 px-8 md:px-10 text-base md:text-lg opacity-0 translate-y-6 scale-[0.92] transition-all duration-[900ms] ease-out delay-[1250ms] ${mounted ? 'opacity-100 translate-y-0 scale-100' : ''}">
{t('cta')}
<span className="ml-3 transition-transform group-hover:translate-x-1">&rarr;</span>
</Button>
<Button href="/products" variant="ghost" size="lg" className="group w-full sm:w-auto h-14 md:h-16 px-8 md:px-10 text-base md:text-lg text-white border-white/20 hover:bg-white/10 md:bg-white md:text-saturated md:hover:bg-neutral-light md:border-none opacity-0 translate-y-6 scale-[0.92] transition-all duration-[900ms] ease-out delay-[1550ms] ${mounted ? 'opacity-100 translate-y-0 scale-100' : ''}">
{t('exploreProducts')}
</Button>
</div>
</div>
<motion.div
className="max-w-5xl"
initial="hidden"
animate="visible"
variants={containerVariants}
>
<motion.div variants={headingVariants}>
<Heading level={1} className="mb-6 md:mb-8 max-w-[12ch] md:max-w-none text-white text-4xl sm:text-5xl md:text-7xl">
{t.rich('title', {
green: (chunks) => (
<span className="relative inline-block">
<motion.span
className="relative z-10 text-accent italic"
variants={accentVariants}
>
{chunks}
</motion.span>
<motion.div
variants={scribbleVariants}
className="w-[140%] h-[140%] -top-[20%] -left-[20%] text-accent/30 hidden md:block absolute"
>
<Scribble variant="circle" />
</motion.div>
</span>
)
})}
</Heading>
</motion.div>
<motion.div variants={subtitleVariants}>
<p className="text-lg md:text-xl text-white/90 leading-relaxed max-w-2xl mb-10 md:mb-12">
{t('subtitle')}
</p>
</motion.div>
<motion.div
className="flex flex-col sm:flex-row gap-4 md:gap-6"
variants={buttonContainerVariants}
>
<motion.div variants={buttonVariants}>
<Button href="/contact" variant="accent" size="lg" className="group w-full sm:w-auto h-14 md:h-16 px-8 md:px-10 text-base md:text-lg">
{t('cta')}
<span className="ml-3 transition-transform group-hover:translate-x-1">&rarr;</span>
</Button>
</motion.div>
<motion.div variants={buttonVariants}>
<Button href="/products" variant="ghost" size="lg" className="group w-full sm:w-auto h-14 md:h-16 px-8 md:px-10 text-base md:text-lg text-white border-white/20 hover:bg-white/10 md:bg-white md:text-saturated md:hover:bg-neutral-light md:border-none">
{t('exploreProducts')}
</Button>
</motion.div>
</motion.div>
</motion.div>
</Container>
<div className={`absolute bottom-6 md:bottom-10 left-1/2 -translate-x-1/2 animate-bounce opacity-0 translate-y-4 transition-all duration-[1000ms] ease-out delay-[3000ms] ${mounted ? 'opacity-100 translate-y-0' : ''} hidden sm:block`}>
<motion.div
className="absolute bottom-6 md:bottom-10 left-1/2 -translate-x-1/2 hidden sm:block"
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1, ease: "easeOut", delay: 3 }}
>
<div className="w-6 h-10 border-2 border-white/30 rounded-full flex justify-center p-1">
<div className="w-1 h-2 bg-white rounded-full" />
<motion.div
className="w-1 h-2 bg-white rounded-full"
animate={{ y: [0, -10, 0] }}
transition={{
duration: 1.5,
repeat: Infinity,
ease: "easeInOut"
}}
/>
</div>
</div>
</motion.div>
</Section>
);
}
const containerVariants = {
hidden: { opacity: 1 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.12,
delayChildren: 0.4
}
}
} as const;
const headingVariants = {
hidden: { opacity: 0, y: 60, scale: 0.85 },
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: { duration: 1.2, ease: [0.25, 0.46, 0.45, 0.94] }
}
} as const;
const accentVariants = {
hidden: { opacity: 0, scale: 0.9, rotate: -5 },
visible: {
opacity: 1,
scale: 1,
rotate: 0,
transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] }
}
} as const;
const scribbleVariants = {
hidden: { opacity: 0, scale: 0, rotate: 180 },
visible: {
opacity: 1,
scale: 1,
rotate: 0,
transition: { duration: 1, type: "spring", stiffness: 300, damping: 20 }
}
} as const;
const subtitleVariants = {
hidden: { opacity: 0, y: 40, scale: 0.95 },
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: { duration: 1, ease: [0.25, 0.46, 0.45, 0.94] }
}
} as const;
const buttonContainerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.15,
delayChildren: 0.4
}
}
} as const;
const buttonVariants = {
hidden: { opacity: 0, y: 30, scale: 0.9 },
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: { type: "spring", stiffness: 400, damping: 20 }
}
} as const;