HaoAws/components/HomePageClient.tsx

272 lines
13 KiB
TypeScript
Raw Normal View History

2025-09-16 16:37:48 +08:00
'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import { Locale, generateLocalizedPath } from '@/lib/i18n';
import { NewsArticle } from '@/lib/markdown';
interface HomePageClientProps {
locale: Locale;
home: any;
common: any;
latestNews: NewsArticle[];
}
export default function HomePageClient({ locale, home, common, latestNews }: HomePageClientProps) {
const [currentSlide, setCurrentSlide] = useState(0);
// 生成新闻文章的链接
const getNewsArticleUrl = (articleId: string) => {
return generateLocalizedPath(`/news/${articleId}`, locale);
};
// 生成新闻缩略图使用Unsplash随机图片作为占位符
const getNewsImage = (index: number) => {
const imageIds = [
'photo-1560472354-b33ff0c44a43', // 科技主题
'photo-1551434678-e076c223a692', // 云计算主题
'photo-1581091226825-a6a2a5aee158' // AI主题
];
const imageId = imageIds[index % imageIds.length];
return `https://images.unsplash.com/${imageId}?w=400&h=225&fit=crop`;
};
// Banner carousel data
const bannerSlides = [
{
id: 1,
image: 'https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=1200&h=600&fit=crop',
},
{
id: 2,
image: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=1200&h=600&fit=crop',
},
{
id: 3,
image: 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=600&fit=crop',
},
];
// Auto-advance carousel
useEffect(() => {
const timer = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % bannerSlides.length);
}, 5000);
return () => clearInterval(timer);
}, []);
const nextSlide = () => {
setCurrentSlide((prev) => (prev + 1) % bannerSlides.length);
};
const prevSlide = () => {
setCurrentSlide((prev) => (prev - 1 + bannerSlides.length) % bannerSlides.length);
};
return (
<>
{/* Banner Carousel */}
<section className="relative h-screen overflow-hidden">
<div className="relative w-full h-full">
{bannerSlides.map((slide, index) => (
<div
key={slide.id}
className={`absolute inset-0 transition-opacity duration-1000 ${
index === currentSlide ? 'opacity-100' : 'opacity-0'
}`}
>
<div
className="w-full h-full bg-cover bg-center bg-gray-900"
style={{ backgroundImage: `url(${slide.image})` }}
>
<div className="absolute inset-0 bg-black/40"></div>
<div className="relative z-10 flex items-center justify-center h-full">
<div className="text-center text-white max-w-4xl px-4">
<h2 className="text-4xl md:text-6xl font-light mb-6 leading-tight">
{home.banner[index]?.title}
</h2>
<p className="text-xl md:text-2xl font-light opacity-90">
{home.banner[index]?.subtitle}
</p>
</div>
</div>
</div>
</div>
))}
</div>
{/* Carousel Controls */}
<button
onClick={prevSlide}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-white/20 hover:bg-white/30 text-white p-2 rounded-full transition-colors"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"
/>
</svg>
</button>
<button
onClick={nextSlide}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-white/20 hover:bg-white/30 text-white p-2 rounded-full transition-colors"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</button>
{/* Carousel Indicators */}
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2">
{bannerSlides.map((_, index) => (
<button
key={index}
onClick={() => setCurrentSlide(index)}
className={`w-3 h-3 rounded-full transition-colors ${
index === currentSlide ? 'bg-white' : 'bg-white/50'
}`}
/>
))}
</div>
</section>
{/* Hero Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-6xl font-light leading-tight mb-8 text-gray-900">
{home.hero.title}
</h1>
<p className="text-xl md:text-2xl text-gray-600 mb-12 font-light">
{home.hero.subtitle}
</p>
<button className="bg-gray-900 text-white px-8 py-3 rounded-full hover:bg-gray-800 transition-colors font-light">
{home.hero.button}
</button>
</div>
</section>
{/* Services Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8 bg-gray-50">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-light mb-4 text-gray-900">
{home.services.title}
</h2>
<p className="text-xl text-gray-600 font-light">{home.services.subtitle}</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
{home.services.items.map((service: any, index: number) => (
<div
key={index}
className="bg-white p-8 rounded-lg shadow-sm hover:shadow-md transition-shadow"
>
<h3 className="text-xl font-light mb-4 text-gray-900">
{service.title}
</h3>
<p className="text-gray-600 font-light leading-relaxed">
{service.description}
</p>
</div>
))}
</div>
</div>
</section>
{/* News Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-light mb-4 text-gray-900">
{home.news.title}
</h2>
</div>
<div className="grid md:grid-cols-3 gap-8">
{latestNews.length > 0 ? latestNews.map((article, index) => (
<Link key={article.id} href={getNewsArticleUrl(article.id)}>
<article className="group cursor-pointer">
<div className="aspect-video bg-gray-200 rounded-lg mb-4 overflow-hidden">
<img
src={getNewsImage(index)}
alt={article.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
/>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2 text-xs text-gray-500">
<span className="bg-blue-100 text-blue-600 px-2 py-1 rounded">
{article.category}
</span>
<span>{article.date}</span>
<span></span>
<span>{article.readTime}</span>
</div>
<h3 className="text-lg font-light mb-2 text-gray-900 group-hover:text-gray-600 transition-colors line-clamp-2">
{article.title}
</h3>
<p className="text-gray-600 font-light text-sm line-clamp-3">
{article.excerpt}
</p>
{article.author && (
<p className="text-xs text-gray-500 mt-2">
{home.news.author}: {article.author}
</p>
)}
</div>
</article>
</Link>
)) : (
// 如果没有新闻数据,显示占位符
[1, 2, 3].map((item) => (
<article key={item} className="group cursor-pointer">
<div className="aspect-video bg-gray-200 rounded-lg mb-4 overflow-hidden">
<div className="w-full h-full bg-gradient-to-br from-gray-100 to-gray-200 group-hover:from-gray-200 group-hover:to-gray-300 transition-colors"></div>
</div>
<h3 className="text-lg font-light mb-2 text-gray-900 group-hover:text-gray-600 transition-colors">
{home.news.sampleTitle} {item}
</h3>
<p className="text-gray-600 font-light text-sm">
{home.news.sampleDate}
</p>
</article>
))
)}
</div>
{/* 查看更多新闻按钮 */}
{latestNews.length > 0 && (
<div className="text-center mt-12">
<Link
href={generateLocalizedPath('/news', locale)}
className="inline-flex items-center px-6 py-3 border border-gray-300 text-gray-700 hover:text-gray-900 hover:border-gray-400 rounded-full transition-colors font-light"
>
{home.news.viewMore}
<svg className="ml-2 w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</Link>
</div>
)}
</div>
</section>
{/* Contact Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8 bg-gray-900 text-white">
<div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl md:text-4xl font-light mb-4">{home.contact.title}</h2>
<p className="text-xl font-light mb-8 opacity-90">{home.contact.description}</p>
<button className="bg-white text-gray-900 px-8 py-3 rounded-full hover:bg-gray-100 transition-colors font-light">
{common.common.contactNow}
</button>
</div>
</section>
</>
);
}