CloudPro/components/Banner/HeroBanner.tsx
2025-09-16 16:15:57 +08:00

604 lines
27 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 React from 'react';
import { useState, useEffect, useRef } from 'react';
import { ChevronLeft, ChevronRight, Play, Pause, Star, Clock, Gift, Zap } from 'lucide-react';
interface BannerSlide {
id: string;
type: 'hero' | 'product' | 'promotion';
title: string;
subtitle?: string;
description: string;
image?: string;
gradient: string;
cta: {
primary: { text: string; href: string };
secondary?: { text: string; href: string };
};
badge?: {
text: string;
type: 'new' | 'hot' | 'discount' | 'limited';
};
features?: string[];
price?: {
original?: string;
current: string;
discount?: string;
};
}
interface HeroBannerProps {
currentLang: string;
translations: any;
}
export function HeroBanner({ currentLang, translations }: HeroBannerProps) {
const [currentSlide, setCurrentSlide] = useState(0);
const [isPlaying, setIsPlaying] = useState(true);
const [isHovered, setIsHovered] = useState(false);
const intervalRef = useRef<NodeJS.Timeout | null>(null);
const t = translations[currentLang];
// Banner slides data
const slides: BannerSlide[] = [
{
id: 'hero-main',
type: 'hero',
title:
currentLang === 'zh'
? '专业云服务器解决方案'
: currentLang === 'zh-tw'
? '專業雲伺服器解決方案'
: 'Professional Cloud Server Solutions',
subtitle:
currentLang === 'zh'
? '为您的业务提供稳定、高效、安全的云计算服务'
: currentLang === 'zh-tw'
? '為您的業務提供穩定、高效、安全的雲端運算服務'
: 'Stable, Efficient, and Secure Cloud Computing Services',
description:
currentLang === 'zh'
? '我们是领先的云服务器代理商,提供全球顶级云服务商的产品与服务,助力企业数字化转型'
: currentLang === 'zh-tw'
? '我們是領先的雲伺服器代理商,提供全球頂級雲服務商的產品與服務,助力企業數位化轉型'
: 'Leading cloud server reseller providing top-tier global cloud services to accelerate your digital transformation',
gradient: 'from-amber-900 via-yellow-800 to-orange-700',
cta: {
primary: { text: t.hero.cta, href: '/contact' },
secondary: { text: t.hero.demo, href: '/demo' },
},
features: [
currentLang === 'zh'
? '99.9% 可用性保证'
: currentLang === 'zh-tw'
? '99.9% 可用性保證'
: '99.9% Uptime Guarantee',
currentLang === 'zh'
? '24/7 技术支持'
: currentLang === 'zh-tw'
? '24/7 技術支援'
: '24/7 Technical Support',
currentLang === 'zh'
? '全球数据中心'
: currentLang === 'zh-tw'
? '全球資料中心'
: 'Global Data Centers',
],
},
{
id: 'product-ecs',
type: 'product',
title:
currentLang === 'zh'
? '云服务器 ECS - 弹性计算'
: currentLang === 'zh-tw'
? '雲伺服器 ECS - 彈性運算'
: 'Cloud Server ECS - Elastic Computing',
description:
currentLang === 'zh'
? '高性能云服务器,支持弹性扩展,按需付费,助力业务快速发展'
: currentLang === 'zh-tw'
? '高效能雲伺服器,支援彈性擴展,按需付費,助力業務快速發展'
: 'High-performance cloud servers with elastic scaling and pay-as-you-go pricing',
gradient: 'from-blue-900 via-indigo-800 to-purple-700',
badge: {
text: currentLang === 'zh' ? '热销' : currentLang === 'zh-tw' ? '熱銷' : 'Hot',
type: 'hot',
},
cta: {
primary: {
text:
currentLang === 'zh'
? '立即购买'
: currentLang === 'zh-tw'
? '立即購買'
: 'Buy Now',
href: '/products/ecs',
},
secondary: {
text:
currentLang === 'zh'
? '免费试用'
: currentLang === 'zh-tw'
? '免費試用'
: 'Free Trial',
href: '/trial/ecs',
},
},
price: {
original:
currentLang === 'zh'
? '¥199/月'
: currentLang === 'zh-tw'
? 'NT$5,990/月'
: '$29/month',
current:
currentLang === 'zh'
? '¥99/月'
: currentLang === 'zh-tw'
? 'NT$2,990/月'
: '$15/month',
discount: '50%',
},
features: [
currentLang === 'zh'
? '2-64核 CPU'
: currentLang === 'zh-tw'
? '2-64核 CPU'
: '2-64 Core CPU',
currentLang === 'zh'
? '1GB-256GB 内存'
: currentLang === 'zh-tw'
? '1GB-256GB 記憶體'
: '1GB-256GB RAM',
currentLang === 'zh'
? 'SSD 高速存储'
: currentLang === 'zh-tw'
? 'SSD 高速儲存'
: 'SSD High-Speed Storage',
],
},
{
id: 'promotion-new-year',
type: 'promotion',
title:
currentLang === 'zh'
? '新年特惠 - 云服务大促销'
: currentLang === 'zh-tw'
? '新年特惠 - 雲服務大促銷'
: 'New Year Special - Cloud Services Sale',
description:
currentLang === 'zh'
? '限时优惠!所有云产品享受超低折扣,新用户更有专属礼包'
: currentLang === 'zh-tw'
? '限時優惠!所有雲產品享受超低折扣,新用戶更有專屬禮包'
: 'Limited time offer! All cloud products at super low prices, exclusive packages for new users',
gradient: 'from-red-900 via-pink-800 to-rose-700',
badge: {
text: currentLang === 'zh' ? '限时' : currentLang === 'zh-tw' ? '限時' : 'Limited',
type: 'limited',
},
cta: {
primary: {
text:
currentLang === 'zh'
? '抢购优惠'
: currentLang === 'zh-tw'
? '搶購優惠'
: 'Grab Deal',
href: '/promotions/new-year',
},
secondary: {
text:
currentLang === 'zh'
? '查看详情'
: currentLang === 'zh-tw'
? '查看詳情'
: 'View Details',
href: '/promotions',
},
},
features: [
currentLang === 'zh'
? '最高7折优惠'
: currentLang === 'zh-tw'
? '最高7折優惠'
: 'Up to 30% Off',
currentLang === 'zh'
? '免费迁移服务'
: currentLang === 'zh-tw'
? '免費遷移服務'
: 'Free Migration Service',
currentLang === 'zh'
? '专属技术支持'
: currentLang === 'zh-tw'
? '專屬技術支援'
: 'Dedicated Support',
],
},
{
id: 'product-database',
type: 'product',
title:
currentLang === 'zh'
? '云数据库 RDS - 高可用数据库'
: currentLang === 'zh-tw'
? '雲資料庫 RDS - 高可用資料庫'
: 'Cloud Database RDS - High Availability',
description:
currentLang === 'zh'
? '企业级云数据库服务支持MySQL、PostgreSQL等多种数据库引擎'
: currentLang === 'zh-tw'
? '企業級雲資料庫服務支援MySQL、PostgreSQL等多種資料庫引擎'
: 'Enterprise-grade cloud database service supporting MySQL, PostgreSQL and more',
gradient: 'from-green-900 via-emerald-800 to-teal-700',
badge: {
text: currentLang === 'zh' ? '新品' : currentLang === 'zh-tw' ? '新品' : 'New',
type: 'new',
},
cta: {
primary: {
text:
currentLang === 'zh'
? '立即体验'
: currentLang === 'zh-tw'
? '立即體驗'
: 'Try Now',
href: '/products/rds',
},
secondary: {
text:
currentLang === 'zh'
? '技术咨询'
: currentLang === 'zh-tw'
? '技術諮詢'
: 'Consultation',
href: '/support',
},
},
price: {
current:
currentLang === 'zh'
? '¥199/月起'
: currentLang === 'zh-tw'
? 'NT$5,990/月起'
: 'From $29/month',
},
features: [
currentLang === 'zh'
? '自动备份恢复'
: currentLang === 'zh-tw'
? '自動備份恢復'
: 'Auto Backup & Recovery',
currentLang === 'zh'
? '读写分离'
: currentLang === 'zh-tw'
? '讀寫分離'
: 'Read-Write Splitting',
currentLang === 'zh'
? '监控告警'
: currentLang === 'zh-tw'
? '監控告警'
: 'Monitoring & Alerts',
],
},
];
// Auto-play functionality
useEffect(() => {
if (isPlaying && !isHovered) {
intervalRef.current = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
}, 5000);
} else {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
}
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [isPlaying, isHovered, slides.length]);
const goToSlide = (index: number) => {
setCurrentSlide(index);
};
const nextSlide = () => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
};
const prevSlide = () => {
setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length);
};
const togglePlayPause = () => {
setIsPlaying(!isPlaying);
};
const getBadgeIcon = (type: string) => {
switch (type) {
case 'new':
return <Star className="w-3 h-3" />;
case 'hot':
return <Zap className="w-3 h-3" />;
case 'discount':
return <Gift className="w-3 h-3" />;
case 'limited':
return <Clock className="w-3 h-3" />;
default:
return null;
}
};
const getBadgeColor = (type: string) => {
switch (type) {
case 'new':
return 'bg-green-500 text-white';
case 'hot':
return 'bg-red-500 text-white';
case 'discount':
return 'bg-purple-500 text-white';
case 'limited':
return 'bg-orange-500 text-white';
default:
return 'bg-gray-500 text-white';
}
};
const currentSlideData = slides[currentSlide];
return (
<section
className="relative h-[600px] md:h-[700px] overflow-hidden"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
role="banner"
aria-label="Hero banner carousel"
>
{/* Background with fixed gradient - consistent with navigation */}
<div className="absolute inset-0 bg-gradient-to-r from-amber-900 to-yellow-800" />
{/* Background pattern */}
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0 bg-[url('data:image/svg+xml,%3Csvg%20width%3D%2260%22%20height%3D%2260%22%20viewBox%3D%220%200%2060%2060%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cg%20fill%3D%22%23ffffff%22%20fill-opacity%3D%220.1%22%3E%3Ccircle%20cx%3D%2230%22%20cy%3D%2230%22%20r%3D%222%22/%3E%3C/g%3E%3C/g%3E%3C/svg%3E')] bg-repeat" />
</div>
{/* Content */}
<div className="relative h-full flex items-center">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
{/* Left Content */}
<div
className="text-white space-y-6 banner-content-animate"
key={currentSlide}
>
{/* Badge */}
{currentSlideData.badge && (
<div className="inline-flex items-center space-x-2 banner-item">
<span
className={`inline-flex items-center space-x-1 px-3 py-1 rounded-full text-xs font-semibold ${getBadgeColor(currentSlideData.badge.type)}`}
>
{getBadgeIcon(currentSlideData.badge.type)}
<span>{currentSlideData.badge.text}</span>
</span>
</div>
)}
{/* Title */}
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold leading-tight banner-item">
{currentSlideData.title}
</h1>
{/* Subtitle */}
{currentSlideData.subtitle && (
<p className="text-xl md:text-2xl text-white/90 leading-relaxed banner-item">
{currentSlideData.subtitle}
</p>
)}
{/* Description */}
<p className="text-lg text-white/80 leading-relaxed max-w-2xl banner-item">
{currentSlideData.description}
</p>
{/* Features */}
{currentSlideData.features && (
<div className="flex flex-wrap gap-4 banner-item">
{currentSlideData.features.map((feature, index) => (
<div
key={index}
className="flex items-center space-x-2 bg-white/10 backdrop-blur-sm rounded-full px-4 py-2"
>
<div className="w-2 h-2 bg-yellow-400 rounded-full" />
<span className="text-sm font-medium">{feature}</span>
</div>
))}
</div>
)}
{/* Price */}
{currentSlideData.price && (
<div className="flex items-center space-x-4 banner-item">
<div className="text-3xl font-bold text-yellow-300">
{currentSlideData.price.current}
</div>
{currentSlideData.price.original && (
<div className="flex items-center space-x-2">
<span className="text-lg text-white/60 line-through">
{currentSlideData.price.original}
</span>
{currentSlideData.price.discount && (
<span className="bg-red-500 text-white px-2 py-1 rounded text-sm font-semibold">
-{currentSlideData.price.discount}
</span>
)}
</div>
)}
</div>
)}
{/* CTA Buttons */}
<div className="flex flex-col sm:flex-row gap-4 pt-4 banner-item">
<a
href={currentSlideData.cta.primary.href}
className="inline-flex items-center justify-center px-8 py-4 bg-yellow-500 hover:bg-yellow-600 text-white font-semibold rounded-lg transition-all duration-200 transform hover:scale-105 shadow-lg hover:shadow-xl"
>
{currentSlideData.cta.primary.text}
</a>
{currentSlideData.cta.secondary && (
<a
href={currentSlideData.cta.secondary.href}
className="inline-flex items-center justify-center px-8 py-4 border-2 border-white/30 text-white hover:bg-white/10 font-semibold rounded-lg transition-all duration-200 backdrop-blur-sm"
>
{currentSlideData.cta.secondary.text}
</a>
)}
</div>
</div>
{/* Right Content - Visual Element */}
<div className="hidden lg:block">
<div className="relative">
{/* Floating Cards */}
<div className="space-y-4">
<div className="bg-white/10 backdrop-blur-md rounded-xl p-6 transform rotate-3 hover:rotate-0 transition-transform duration-300">
<div className="flex items-center space-x-3 mb-3">
<div className="w-3 h-3 bg-green-400 rounded-full" />
<span className="text-white font-medium">
{currentLang === 'zh'
? '服务状态:正常'
: currentLang === 'zh-tw'
? '服務狀態:正常'
: 'Service Status: Normal'}
</span>
</div>
<div className="text-2xl font-bold text-white">99.9%</div>
<div className="text-white/70 text-sm">
{currentLang === 'zh'
? '可用性保证'
: currentLang === 'zh-tw'
? '可用性保證'
: 'Uptime Guarantee'}
</div>
</div>
<div className="bg-white/10 backdrop-blur-md rounded-xl p-6 transform -rotate-2 hover:rotate-0 transition-transform duration-300 ml-8">
<div className="flex items-center space-x-3 mb-3">
<div className="w-3 h-3 bg-blue-400 rounded-full" />
<span className="text-white font-medium">
{currentLang === 'zh'
? '全球节点'
: currentLang === 'zh-tw'
? '全球節點'
: 'Global Nodes'}
</span>
</div>
<div className="text-2xl font-bold text-white">50+</div>
<div className="text-white/70 text-sm">
{currentLang === 'zh'
? '数据中心'
: currentLang === 'zh-tw'
? '資料中心'
: 'Data Centers'}
</div>
</div>
<div className="bg-white/10 backdrop-blur-md rounded-xl p-6 transform rotate-1 hover:rotate-0 transition-transform duration-300">
<div className="flex items-center space-x-3 mb-3">
<div className="w-3 h-3 bg-yellow-400 rounded-full" />
<span className="text-white font-medium">
{currentLang === 'zh'
? '客户满意度'
: currentLang === 'zh-tw'
? '客戶滿意度'
: 'Customer Satisfaction'}
</span>
</div>
<div className="text-2xl font-bold text-white">4.9/5</div>
<div className="text-white/70 text-sm">
{currentLang === 'zh'
? '用户评分'
: currentLang === 'zh-tw'
? '用戶評分'
: 'User Rating'}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Navigation Controls */}
<div className="absolute bottom-6 left-1/2 transform -translate-x-1/2 flex items-center space-x-4">
{/* Slide Indicators */}
<div className="flex space-x-2">
{slides.map((_, index) => (
<button
key={index}
onClick={() => goToSlide(index)}
className={`w-3 h-3 rounded-full transition-all duration-200 ${
index === currentSlide
? 'bg-yellow-400 w-8'
: 'bg-white/30 hover:bg-white/50'
}`}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
{/* Play/Pause Button */}
<button
onClick={togglePlayPause}
className="p-2 bg-white/10 backdrop-blur-sm rounded-full hover:bg-white/20 transition-colors duration-200"
aria-label={isPlaying ? 'Pause slideshow' : 'Play slideshow'}
>
{isPlaying ? (
<Pause className="w-4 h-4 text-white" />
) : (
<Play className="w-4 h-4 text-white" />
)}
</button>
</div>
{/* Navigation Arrows */}
<button
onClick={prevSlide}
className="absolute left-4 top-1/2 transform -translate-y-1/2 p-3 bg-white/10 backdrop-blur-sm rounded-full hover:bg-white/20 transition-colors duration-200 group"
aria-label="Previous slide"
>
<ChevronLeft className="w-6 h-6 text-white group-hover:scale-110 transition-transform" />
</button>
<button
onClick={nextSlide}
className="absolute right-4 top-1/2 transform -translate-y-1/2 p-3 bg-white/10 backdrop-blur-sm rounded-full hover:bg-white/20 transition-colors duration-200 group"
aria-label="Next slide"
>
<ChevronRight className="w-6 h-6 text-white group-hover:scale-110 transition-transform" />
</button>
{/* Progress Bar */}
<div className="absolute bottom-0 left-0 w-full h-1 bg-white/20">
<div
className="h-full bg-yellow-400 transition-all duration-300 ease-linear"
style={{
width: `${((currentSlide + 1) / slides.length) * 100}%`,
}}
/>
</div>
</section>
);
}