Files
novalon-website/src/components/sections/cases-section.tsx
T
张翔 fecbfd1990 feat: 添加预览效果页面并优化交互效果
refactor: 优化代码健壮性和类型安全

style: 更新字体样式和全局CSS

fix: 修复IntersectionObserver潜在空引用问题

chore: 更新依赖和ESLint配置

build: 更新构建ID和路由配置
2026-02-24 10:24:05 +08:00

151 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { GlassCard } from '@/components/ui/glass-card';
import { CASES } from '@/lib/constants';
import { ArrowRight, Building2, TrendingUp } from 'lucide-react';
export function CasesSection() {
const [isVisible, setIsVisible] = useState(false);
const sectionRef = useRef<HTMLElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry?.isIntersecting) {
setIsVisible(true);
}
},
{ threshold: 0.1 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section
ref={sectionRef}
id="cases"
className="py-24 md:py-32 relative overflow-hidden bg-[#FAFAFA]"
>
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#E5E5E5] to-transparent" />
<div className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-[#E5E5E5] to-transparent" />
</div>
<div className="container-wide relative z-10">
<div className="text-center mb-16">
<div
className={`
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up' : ''}
`}
>
<span className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-[#C41E3A]/10 text-[#C41E3A] text-sm font-medium mb-4">
<TrendingUp className="w-4 h-4" />
</span>
</div>
<h2
className={`
text-3xl sm:text-4xl font-semibold text-[#171717] mb-4
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up stagger-1' : ''}
`}
>
</h2>
<p
className={`
text-lg text-[#525252] max-w-2xl mx-auto
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up stagger-2' : ''}
`}
>
</p>
</div>
<div className="grid lg:grid-cols-3 gap-6 md:gap-8">
{CASES.map((caseItem, index) => (
<Link key={caseItem.id} href={`/cases/${caseItem.id}`}>
<GlassCard
variant="elevated"
className="overflow-hidden group cursor-pointer"
>
<div
className={`
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up' : ''}
`}
style={{ animationDelay: `${(index + 3) * 100}ms` }}
>
<div className="relative h-48 bg-gradient-to-br from-[#C41E3A]/10 to-[#D4A574]/10 overflow-hidden">
<div className="absolute inset-0 flex items-center justify-center">
<Building2 className="w-16 h-16 text-[#C41E3A]/30 group-hover:scale-110 transition-transform duration-500" />
</div>
<div className="absolute top-4 left-4">
<span className="px-3 py-1 bg-white/90 backdrop-blur-sm rounded-full text-xs font-medium text-[#C41E3A]">
{caseItem.industry}
</span>
</div>
</div>
<div className="p-6">
<h3 className="text-lg font-semibold text-[#171717] mb-2 group-hover:text-[#C41E3A] transition-colors duration-300">
{caseItem.title}
</h3>
<p className="text-sm text-[#525252] mb-4 line-clamp-2">
{caseItem.description}
</p>
<div className="grid grid-cols-3 gap-2 mb-4">
{caseItem.results.map((result) => (
<div
key={result.label}
className="text-center p-2 bg-[#FAFAFA] rounded-lg"
>
<div className="text-sm font-semibold text-[#C41E3A]">
{result.value}
</div>
<div className="text-xs text-[#737373] truncate">
{result.label}
</div>
</div>
))}
</div>
<div className="flex flex-wrap gap-2 mb-4">
{caseItem.tags.map((tag) => (
<span
key={tag}
className="px-2 py-1 bg-[#171717]/5 rounded text-xs text-[#525252]"
>
{tag}
</span>
))}
</div>
<div className="flex items-center justify-center text-sm font-medium text-[#C41E3A] group-hover:gap-2 transition-all">
<ArrowRight className="w-4 h-4 ml-1" />
</div>
</div>
</div>
</GlassCard>
</Link>
))}
</div>
</div>
</section>
);
}