feat: add HeroSectionV2 with Atlassian-style clean layout and stats bar

This commit is contained in:
张翔
2026-04-30 19:11:43 +08:00
parent 6a098d115d
commit 14ca4b104f
+125
View File
@@ -0,0 +1,125 @@
'use client';
import { useEffect, useRef, useState } from 'react';
import { motion } from 'framer-motion';
import { StaticLink } from '@/components/ui/static-link';
import { Button } from '@/components/ui/button';
import { COMPANY_INFO, STATS } from '@/lib/constants';
import { ArrowRight } from 'lucide-react';
import { useReducedMotion } from '@/hooks/use-reduced-motion';
export function HeroSectionV2() {
const [isVisible, setIsVisible] = useState(false);
const sectionRef = useRef<HTMLElement>(null);
const shouldReduceMotion = useReducedMotion();
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry?.isIntersecting) {
setIsVisible(true);
}
},
{ threshold: 0.1 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
const fadeUp = {
initial: shouldReduceMotion ? {} : { opacity: 0, y: 24 },
animate: isVisible ? { opacity: 1, y: 0 } : {},
};
return (
<section
id="home"
ref={sectionRef}
aria-labelledby="hero-heading"
className="relative min-h-screen flex flex-col justify-center overflow-hidden bg-[#FAFAFA]"
>
<div className="container-wide py-24 md:py-32 lg:py-40 relative z-10 flex-1 flex items-center">
<div className="max-w-3xl">
<motion.div
{...fadeUp}
transition={{ duration: 0.5, ease: [0.16, 1, 0.3, 1] }}
className="mb-6"
>
<span className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-[#FEF2F4] text-[#C41E3A] text-sm font-medium border border-[#C41E3A]/10">
</span>
</motion.div>
<motion.h1
id="hero-heading"
{...fadeUp}
transition={{ duration: 0.5, delay: 0.1, ease: [0.16, 1, 0.3, 1] }}
className="text-5xl sm:text-6xl lg:text-7xl tracking-tight mb-6 font-brand"
style={{ fontWeight: 'normal' }}
>
{COMPANY_INFO.shortName}
</motion.h1>
<motion.p
{...fadeUp}
transition={{ duration: 0.5, delay: 0.2, ease: [0.16, 1, 0.3, 1] }}
className="text-xl sm:text-2xl text-[#3D3D3D] mb-4"
>
<span className="font-semibold text-[#C41E3A]"></span>
</motion.p>
<motion.p
{...fadeUp}
transition={{ duration: 0.5, delay: 0.3, ease: [0.16, 1, 0.3, 1] }}
className="text-lg text-[#595959] max-w-2xl leading-relaxed mb-10"
>
</motion.p>
<motion.div
{...fadeUp}
transition={{ duration: 0.5, delay: 0.4, ease: [0.16, 1, 0.3, 1] }}
className="flex flex-col sm:flex-row items-start gap-4"
>
<Button size="lg" asChild>
<StaticLink href="/contact">
<ArrowRight className="w-4 h-4 ml-2" />
</StaticLink>
</Button>
<Button size="lg" variant="outline" asChild>
<StaticLink href="/products">
</StaticLink>
</Button>
</motion.div>
</div>
</div>
<motion.div
{...fadeUp}
transition={{ duration: 0.5, delay: 0.5, ease: [0.16, 1, 0.3, 1] }}
className="border-t border-[#E5E5E5] bg-white"
>
<div className="container-wide py-8">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-12">
{STATS.map((stat) => (
<div key={stat.label} className="text-center">
<div className="text-3xl sm:text-4xl font-bold text-[#C41E3A] mb-1">
{stat.value}
</div>
<div className="text-sm text-[#595959]">
{stat.label}
</div>
</div>
))}
</div>
</div>
</motion.div>
</section>
);
}