AWSCLOUD/components/HomeClient.tsx

313 lines
14 KiB
TypeScript
Raw Permalink Normal View History

2025-09-16 15:24:39 +08:00
'use client';
import { useState, useEffect, useRef } from 'react';
import { useRouter } from 'next/navigation';
import AWSProductsSection from './AWSProductsSection';
import Navbar from './Navbar';
import Footer from './Footer';
import { content, slides } from '../data/content';
export default function HomeClient({ lang }: { lang: string }) {
const router = useRouter();
const currentLang = lang;
const [currentSlide, setCurrentSlide] = useState(0);
const [isAutoPlaying, setIsAutoPlaying] = useState(true);
const autoPlayTimeoutRef = useRef<NodeJS.Timeout | null>(null);
// Validate language and redirect if invalid
useEffect(() => {
const supportedLangs = ['zh-CN', 'zh-TW', 'en', 'ko', 'ja'];
if (!supportedLangs.includes(currentLang)) {
router.push('/en');
}
}, [currentLang, router]);
// Cleanup timeout on component unmount
useEffect(() => {
return () => {
if (autoPlayTimeoutRef.current) {
clearTimeout(autoPlayTimeoutRef.current);
}
};
}, []);
const currentContent = content[currentLang as keyof typeof content] || content.en;
const currentSlideData = slides[currentSlide];
// Carousel auto-play functionality
useEffect(() => {
if (!isAutoPlaying) return;
const interval = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
}, 5000); // Change slide every 5 seconds
return () => clearInterval(interval);
}, [isAutoPlaying, slides.length]);
const resumeAutoPlayWithDelay = () => {
if (autoPlayTimeoutRef.current) {
clearTimeout(autoPlayTimeoutRef.current);
}
autoPlayTimeoutRef.current = setTimeout(() => {
setIsAutoPlaying(true);
}, 10000); // Resume auto-play after 10 seconds
};
// Carousel navigation functions
const nextSlide = () => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
setIsAutoPlaying(false);
resumeAutoPlayWithDelay();
};
const prevSlide = () => {
setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length);
setIsAutoPlaying(false);
resumeAutoPlayWithDelay();
};
const goToSlide = (index: number) => {
setCurrentSlide(index);
setIsAutoPlaying(false);
resumeAutoPlayWithDelay();
};
const handleLanguageChange = (lang: string) => {
router.push(`/${lang}`);
};
return (
<div className="min-h-screen bg-gray-900 text-white">
<Navbar
currentLang={currentLang}
currentContent={currentContent}
handleLanguageChange={handleLanguageChange}
/>
{/* Hero Section */}
<div className="relative bg-black overflow-hidden min-h-screen flex items-center">
{/* Background with curved flowing design */}
<div className="absolute inset-0 transition-all duration-1000 ease-in-out">
<div
className={`absolute inset-0 bg-gradient-to-br ${currentSlideData.background.gradient} transition-all duration-1000 ease-in-out`}
></div>
<svg
className="absolute inset-0 w-full h-full"
viewBox="0 0 1200 800"
preserveAspectRatio="xMidYMid slice"
>
<defs>
<linearGradient
id={`gradient-${currentSlide}`}
x1="0%"
y1="0%"
x2="100%"
y2="100%"
>
<stop
offset="0%"
stopColor={currentSlideData.background.primaryColor}
/>
<stop
offset="100%"
stopColor={currentSlideData.background.accentColor}
/>
</linearGradient>
</defs>
<path
d="M0,400 Q300,200 600,400 T1200,400 L1200,800 L0,800 Z"
fill={`url(#gradient-${currentSlide})`}
className="transition-all duration-1000 ease-in-out"
/>
<path
d="M0,500 Q400,300 800,500 T1200,500 L1200,800 L0,800 Z"
fill={currentSlideData.background.secondaryColor}
className="transition-all duration-1000 ease-in-out"
/>
<path
d="M0,600 Q200,400 400,600 T800,600 Q1000,500 1200,600 L1200,800 L0,800 Z"
fill={currentSlideData.background.primaryColor}
className="transition-all duration-1000 ease-in-out"
/>
</svg>
{/* Additional animated elements for each slide */}
<div className="absolute inset-0 overflow-hidden">
{currentSlide === 0 && (
<div className="absolute top-20 right-20 w-32 h-32 bg-blue-500 rounded-full opacity-10 animate-pulse"></div>
)}
{currentSlide === 1 && (
<div className="absolute bottom-32 left-20 w-24 h-24 bg-purple-500 rounded-full opacity-20 animate-bounce"></div>
)}
{currentSlide === 2 && (
<div className="absolute top-32 left-32 w-28 h-28 bg-green-500 rounded-full opacity-15 animate-ping"></div>
)}
{currentSlide === 3 && (
<div className="absolute bottom-20 right-32 w-36 h-36 bg-orange-500 rounded-full opacity-10 animate-pulse"></div>
)}
</div>
</div>
{/* Navigation arrows */}
<button
onClick={prevSlide}
className="absolute left-4 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-black bg-opacity-50 rounded-full flex items-center justify-center text-white hover:bg-opacity-70 transition-all z-20"
>
<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 w-12 h-12 bg-black bg-opacity-50 rounded-full flex items-center justify-center text-white hover:bg-opacity-70 transition-all z-20"
>
<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>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 lg:py-32 z-10">
<div className="text-left max-w-3xl">
<div className="transition-all duration-500 ease-in-out">
<h1
className="text-4xl md:text-6xl font-bold leading-tight mb-6 text-white"
key={`title-${currentSlide}`}
>
{
currentSlideData.title[
currentLang as keyof typeof currentSlideData.title
]
}
</h1>
<h2
className="text-4xl md:text-6xl font-bold leading-tight mb-8 text-white"
key={`subtitle-${currentSlide}`}
>
{
currentSlideData.subtitle[
currentLang as keyof typeof currentSlideData.subtitle
]
}
</h2>
<p
className="text-lg text-gray-300 mb-12 leading-relaxed"
key={`description-${currentSlide}`}
>
{
currentSlideData.description[
currentLang as keyof typeof currentSlideData.description
]
}
</p>
</div>
<div className="flex flex-col sm:flex-row gap-4">
<button className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded text-lg font-medium transition-colors">
{currentContent.hero.cta}
</button>
<button className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded text-lg font-medium transition-colors">
{currentContent.hero.learnMore}
</button>
</div>
</div>
</div>
{/* Slide indicators */}
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 flex space-x-2 z-20">
{slides.map((_, index) => (
<button
key={index}
onClick={() => goToSlide(index)}
className={`w-3 h-3 rounded-full transition-all duration-300 ${
index === currentSlide
? 'bg-white scale-125'
: 'bg-gray-500 hover:bg-gray-300'
}`}
/>
))}
</div>
{/* Leave a Message button */}
<div className="fixed bottom-8 right-8 z-50">
<button className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg shadow-lg flex items-center space-x-2 transition-colors">
<svg
className="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M18 10c0 3.866-3.582 7-8 7a8.841 8.841 0 01-4.083-.98L2 17l1.338-3.123C2.493 12.767 2 11.434 2 10c0-3.866 3.582-7 8-7s8 3.134 8 7zM7 9H5v2h2V9zm8 0h-2v2h2V9zM9 9h2v2H9V9z"
clipRule="evenodd"
/>
</svg>
<span>Leave A Message</span>
</button>
</div>
</div>
{/* Features Section */}
<div className="py-24 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-gray-900">
{currentContent.features.title}
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{currentContent.features.items.map((feature, index) => (
<div
key={index}
className="text-center p-6 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"
>
<div className="w-12 h-12 bg-blue-600 rounded-lg flex items-center justify-center mx-auto mb-4">
<svg
className="w-6 h-6 text-white"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clipRule="evenodd"
/>
</svg>
</div>
<h3 className="text-xl font-semibold mb-2 text-gray-900">
{feature.title}
</h3>
<p className="text-gray-600">{feature.desc}</p>
</div>
))}
</div>
</div>
</div>
{/* AWS Products Section */}
<AWSProductsSection currentLang={currentLang} />
<Footer />
</div>
);
}