HaoAws/components/HomePageClient.tsx
2025-09-16 16:37:48 +08:00

272 lines
13 KiB
TypeScript
Raw Permalink 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 { 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>
</>
);
}