feat(pages): 添加联系、首页和作品页面,更新样式和配置文件

This commit is contained in:
2026-06-26 10:36:54 +08:00
commit 44f0b43fcc
31 changed files with 5557 additions and 0 deletions

28
src/App.tsx Normal file
View File

@@ -0,0 +1,28 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Navbar from './components/Navbar'
import Footer from './components/Footer'
import Home from './pages/Home'
import About from './pages/About'
import Works from './pages/Works'
import Contact from './pages/Contact'
function App() {
return (
<Router>
<div className="min-h-screen flex flex-col">
<Navbar />
<main className="flex-1">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/works" element={<Works />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</main>
<Footer />
</div>
</Router>
)
}
export default App

View File

@@ -0,0 +1,61 @@
import { useState, useEffect, useRef } from 'react'
interface AnimatedCounterProps {
end: number
suffix?: string
duration?: number
}
export default function AnimatedCounter({ end, suffix = '', duration = 2000 }: AnimatedCounterProps) {
const [count, setCount] = useState(0)
const [isVisible, setIsVisible] = useState(false)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true)
observer.disconnect()
}
},
{ threshold: 0.3 }
)
if (ref.current) {
observer.observe(ref.current)
}
return () => observer.disconnect()
}, [])
useEffect(() => {
if (!isVisible) return
let startTime: number
let animationId: number
const animate = (currentTime: number) => {
if (!startTime) startTime = currentTime
const elapsed = currentTime - startTime
const progress = Math.min(elapsed / duration, 1)
const easeOut = 1 - Math.pow(1 - progress, 3)
setCount(Math.floor(easeOut * end))
if (progress < 1) {
animationId = requestAnimationFrame(animate)
}
}
animationId = requestAnimationFrame(animate)
return () => cancelAnimationFrame(animationId)
}, [isVisible, end, duration])
return (
<div ref={ref} className="text-4xl md:text-5xl font-bold gradient-text">
{count}{suffix}
</div>
)
}

View File

@@ -0,0 +1,166 @@
import { useState } from 'react'
import ScrollReveal from './ScrollReveal'
const comparisons = [
{
id: 1,
title: '品牌宣传片',
traditional: {
time: '2-4周',
cost: '¥50,000-200,000',
team: '导演+摄影+后期+演员',
process: '脚本撰写→选角→拍摄→后期制作→修改→交付'
},
ai: {
time: '1-3天',
cost: '¥5,000-20,000',
team: 'AI工程师+创意策划',
process: '需求确认→AI生成→人工优化→交付'
}
},
{
id: 2,
title: '产品展示视频',
traditional: {
time: '1-2周',
cost: '¥20,000-80,000',
team: '摄影师+灯光师+后期',
process: '产品准备→场景搭建→拍摄→精修→交付'
},
ai: {
time: '4-8小时',
cost: '¥2,000-8,000',
team: 'AI工程师',
process: '产品图片→AI建模→动画生成→交付'
}
},
{
id: 3,
title: '社交媒体短视频',
traditional: {
time: '3-7天',
cost: '¥10,000-30,000',
team: '编导+拍摄+剪辑',
process: '策划→拍摄→剪辑→字幕→交付'
},
ai: {
time: '2-4小时',
cost: '¥1,000-3,000',
team: 'AI工程师',
process: '文案输入→AI生成→一键发布'
}
}
]
export default function CaseComparison() {
const [activeCase, setActiveCase] = useState(comparisons[0])
return (
<section className="py-24 px-4 bg-[#0d0d2b]/50">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-6">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-4xl md:text-5xl font-bold mb-4">
AI vs <span className="gradient-text"></span>
</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
AI制作效率提升10倍80%
</p>
</div>
</ScrollReveal>
{/* Case Tabs */}
<ScrollReveal delay={100}>
<div className="flex flex-wrap justify-center gap-3 mb-12">
{comparisons.map((comp) => (
<button
key={comp.id}
onClick={() => setActiveCase(comp)}
className={`px-5 py-2.5 rounded-xl font-medium transition-all duration-300 ${
activeCase.id === comp.id
? 'gradient-bg-animated text-white'
: 'glass-card text-gray-400 hover:text-white'
}`}
>
{comp.title}
</button>
))}
</div>
</ScrollReveal>
{/* Comparison Cards */}
<ScrollReveal delay={200}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Traditional */}
<div className="glass-card rounded-3xl p-8 border-red-500/20">
<div className="flex items-center gap-3 mb-8">
<div className="w-12 h-12 rounded-xl bg-red-500/20 flex items-center justify-center">
<svg className="w-6 h-6 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<h3 className="text-xl font-bold text-white"></h3>
</div>
<div className="space-y-6">
<div className="flex items-center justify-between py-4 border-b border-white/5">
<span className="text-gray-400"></span>
<span className="text-red-400 font-semibold">{activeCase.traditional.time}</span>
</div>
<div className="flex items-center justify-between py-4 border-b border-white/5">
<span className="text-gray-400"></span>
<span className="text-red-400 font-semibold">{activeCase.traditional.cost}</span>
</div>
<div className="flex items-center justify-between py-4 border-b border-white/5">
<span className="text-gray-400"></span>
<span className="text-gray-300 text-sm text-right">{activeCase.traditional.team}</span>
</div>
<div>
<span className="text-gray-400 block mb-3"></span>
<p className="text-gray-300 text-sm leading-relaxed">{activeCase.traditional.process}</p>
</div>
</div>
</div>
{/* AI */}
<div className="glass-card rounded-3xl p-8 border-green-500/20 relative overflow-hidden">
<div className="absolute top-4 right-4 px-3 py-1 rounded-full text-xs font-semibold gradient-bg-animated">
</div>
<div className="flex items-center gap-3 mb-8">
<div className="w-12 h-12 rounded-xl bg-green-500/20 flex items-center justify-center">
<svg className="w-6 h-6 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<h3 className="text-xl font-bold text-white">AI制作</h3>
</div>
<div className="space-y-6">
<div className="flex items-center justify-between py-4 border-b border-white/5">
<span className="text-gray-400"></span>
<span className="text-green-400 font-semibold">{activeCase.ai.time}</span>
</div>
<div className="flex items-center justify-between py-4 border-b border-white/5">
<span className="text-gray-400"></span>
<span className="text-green-400 font-semibold">{activeCase.ai.cost}</span>
</div>
<div className="flex items-center justify-between py-4 border-b border-white/5">
<span className="text-gray-400"></span>
<span className="text-gray-300 text-sm">{activeCase.ai.team}</span>
</div>
<div>
<span className="text-gray-400 block mb-3"></span>
<p className="text-gray-300 text-sm leading-relaxed">{activeCase.ai.process}</p>
</div>
</div>
</div>
</div>
</ScrollReveal>
</div>
</section>
)
}

88
src/components/FAQ.tsx Normal file
View File

@@ -0,0 +1,88 @@
import { useState } from 'react'
import ScrollReveal from './ScrollReveal'
const faqs = [
{
question: 'AI生成的视频质量如何能达到商用标准吗',
answer: '我们的AI视频已经可以达到商用标准。通过多轮优化和人工精修最终输出的视频在画面质量、流畅度和创意表现上都能满足品牌宣传、社交媒体等商业场景的需求。我们服务过的100+客户中98%对最终效果表示满意。'
},
{
question: '制作一个AI视频需要多长时间',
answer: '根据视频复杂度不同制作周期从2小时到3天不等。简单的社交媒体短视频通常4-8小时即可完成而复杂的品牌宣传片可能需要1-3天。相比传统制作方式效率提升10倍以上。'
},
{
question: 'AI视频的版权归属如何',
answer: '所有通过我们生成的AI视频版权完全归属客户所有。我们使用的AI工具均拥有合法授权生成的内容不存在版权纠纷风险。同时我们会提供完整的版权证明文件。'
},
{
question: '你们使用哪些AI技术',
answer: '我们综合使用业界领先的AI工具包括Midjourney/Stable Diffusion图像生成、Runway/Pika Labs视频生成、HeyGen/D-ID数字人、ElevenLabs语音合成等。根据项目需求选择最合适的工具组合。'
},
{
question: '如何保证视频符合品牌调性?',
answer: '我们有专业的创意团队会在项目初期深入了解您的品牌调性、目标受众和传播目标。通过品牌指南学习、风格参考收集和多轮沟通确认确保AI生成的视频精准传达品牌价值。'
},
{
question: '支持哪些视频格式和尺寸?',
answer: '我们支持所有主流视频格式和尺寸包括横屏16:91920x1080/3840x2160、竖屏9:161080x1920、方形1:11080x1080等。同时支持MP4、MOV、AVI等格式输出满足不同平台的发布需求。'
}
]
export default function FAQ() {
const [openIndex, setOpenIndex] = useState<number | null>(0)
return (
<section className="py-24 px-4">
<div className="max-w-4xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-6">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-4xl md:text-5xl font-bold mb-4">
<span className="gradient-text">FAQ</span>
</h2>
<p className="text-gray-400 text-lg">
AI视频制作
</p>
</div>
</ScrollReveal>
<div className="space-y-4">
{faqs.map((faq, index) => (
<ScrollReveal key={index} delay={index * 50}>
<div className="glass-card rounded-2xl overflow-hidden">
<button
onClick={() => setOpenIndex(openIndex === index ? null : index)}
className="w-full text-left p-6 flex items-center justify-between gap-4"
>
<span className="text-white font-medium pr-4">{faq.question}</span>
<svg
className={`w-5 h-5 text-purple-400 flex-shrink-0 transition-transform duration-300 ${
openIndex === index ? 'rotate-180' : ''
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
<div
className={`overflow-hidden transition-all duration-300 ${
openIndex === index ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
}`}
>
<div className="px-6 pb-6">
<div className="h-px bg-white/10 mb-4" />
<p className="text-gray-400 leading-relaxed">{faq.answer}</p>
</div>
</div>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
)
}

46
src/components/Footer.tsx Normal file
View File

@@ -0,0 +1,46 @@
import { Link } from 'react-router-dom'
export default function Footer() {
return (
<footer className="bg-[#0d0d2b] border-t border-white/10">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div>
<div className="flex items-center space-x-2 mb-4">
<div className="w-10 h-10 gradient-bg rounded-lg flex items-center justify-center">
<span className="text-white font-bold text-xl">C</span>
</div>
<span className="text-xl font-bold gradient-text">CYH Technology</span>
</div>
<p className="text-gray-400 text-sm">
AI短视频制作公司
</p>
</div>
<div>
<h3 className="text-white font-semibold mb-4"></h3>
<div className="flex flex-col space-y-2">
<Link to="/" className="text-gray-400 hover:text-white text-sm transition-colors"></Link>
<Link to="/about" className="text-gray-400 hover:text-white text-sm transition-colors"></Link>
<Link to="/works" className="text-gray-400 hover:text-white text-sm transition-colors"></Link>
<Link to="/contact" className="text-gray-400 hover:text-white text-sm transition-colors"></Link>
</div>
</div>
<div>
<h3 className="text-white font-semibold mb-4"></h3>
<div className="flex flex-col space-y-2 text-gray-400 text-sm">
<p>邮箱: info@cyhtechnology.com</p>
<p>: +852 XXXX XXXX</p>
<p>地址: 香港九龙湾XX大厦</p>
</div>
</div>
</div>
<div className="border-t border-white/10 mt-8 pt-8 text-center text-gray-500 text-sm">
<p>&copy; 2024 HK CYH Technology. All rights reserved.</p>
</div>
</div>
</footer>
)
}

View File

@@ -0,0 +1,22 @@
const partners = [
'腾讯', '阿里巴巴', '字节跳动', '华为', '小米',
'百度', '京东', '美团', '网易', '快手',
'B站', '小红书', '滴滴', '拼多多', '携程'
]
export default function MarqueeTicker() {
return (
<div className="overflow-hidden py-8">
<div className="flex animate-marquee">
{[...partners, ...partners].map((partner, index) => (
<div
key={index}
className="flex-shrink-0 mx-8 px-6 py-3 glass-card rounded-full"
>
<span className="text-gray-400 font-medium whitespace-nowrap">{partner}</span>
</div>
))}
</div>
</div>
)
}

109
src/components/Navbar.tsx Normal file
View File

@@ -0,0 +1,109 @@
import { useState, useEffect } from 'react'
import { Link, useLocation } from 'react-router-dom'
const navLinks = [
{ path: '/', label: '首页' },
{ path: '/about', label: '关于我们' },
{ path: '/works', label: '作品展示' },
{ path: '/contact', label: '联系我们' },
]
export default function Navbar() {
const [isOpen, setIsOpen] = useState(false)
const [scrolled, setScrolled] = useState(false)
const location = useLocation()
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50)
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])
return (
<nav className={`fixed top-0 left-0 right-0 z-50 transition-all duration-500 ${
scrolled
? 'bg-[#0a0a1a]/90 backdrop-blur-xl shadow-2xl shadow-purple-500/10'
: 'bg-transparent'
}`}>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-20">
<Link to="/" className="flex items-center space-x-3 group">
<div className="relative">
<div className="w-12 h-12 gradient-bg-animated rounded-xl flex items-center justify-center transform group-hover:rotate-12 transition-transform duration-300">
<span className="text-white font-bold text-2xl">C</span>
</div>
<div className="absolute inset-0 gradient-bg rounded-xl blur-lg opacity-50 group-hover:opacity-100 transition-opacity" />
</div>
<div>
<span className="text-xl font-bold gradient-text">CYH Technology</span>
<div className="h-0.5 w-0 group-hover:w-full gradient-bg transition-all duration-300" />
</div>
</Link>
<div className="hidden md:flex items-center space-x-1">
{navLinks.map((link) => (
<Link
key={link.path}
to={link.path}
className="relative px-4 py-2 text-sm font-medium transition-colors duration-300 group"
>
<span className={
location.pathname === link.path
? 'text-white'
: 'text-gray-400 group-hover:text-white'
}>
{link.label}
</span>
<div className={`absolute bottom-0 left-1/2 -translate-x-1/2 h-0.5 gradient-bg rounded-full transition-all duration-300 ${
location.pathname === link.path ? 'w-8' : 'w-0 group-hover:w-8'
}`} />
{location.pathname === link.path && (
<div className="absolute inset-0 bg-white/5 rounded-lg" />
)}
</Link>
))}
</div>
<button
onClick={() => setIsOpen(!isOpen)}
className="md:hidden relative w-10 h-10 flex items-center justify-center"
>
<div className={`w-6 h-0.5 bg-white transition-all duration-300 ${
isOpen ? 'rotate-45 translate-y-0' : '-translate-y-1.5'
}`} />
<div className={`w-6 h-0.5 bg-white absolute transition-all duration-300 ${
isOpen ? 'opacity-0' : 'opacity-100'
}`} />
<div className={`w-6 h-0.5 bg-white transition-all duration-300 ${
isOpen ? '-rotate-45 translate-y-0' : 'translate-y-1.5'
}`} />
</button>
</div>
</div>
<div className={`md:hidden transition-all duration-500 overflow-hidden ${
isOpen ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
}`}>
<div className="bg-[#0a0a1a]/95 backdrop-blur-xl border-t border-white/10 px-4 py-4 space-y-2">
{navLinks.map((link, index) => (
<Link
key={link.path}
to={link.path}
onClick={() => setIsOpen(false)}
className={`block px-4 py-3 rounded-xl transition-all duration-300 ${
location.pathname === link.path
? 'text-white bg-gradient-to-r from-purple-500/20 to-transparent'
: 'text-gray-400 hover:text-white hover:bg-white/5'
}`}
style={{ animationDelay: `${index * 100}ms` }}
>
{link.label}
</Link>
))}
</div>
</div>
</nav>
)
}

View File

@@ -0,0 +1,126 @@
import { useEffect, useRef } from 'react'
interface Particle {
x: number
y: number
size: number
speedX: number
speedY: number
opacity: number
}
export default function ParticleBackground() {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext('2d')
if (!ctx) return
let animationId: number
let particles: Particle[] = []
let mouseX = 0
let mouseY = 0
const resize = () => {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
}
const createParticles = () => {
particles = []
const count = Math.floor((canvas.width * canvas.height) / 15000)
for (let i = 0; i < count; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
size: Math.random() * 2 + 0.5,
speedX: (Math.random() - 0.5) * 0.5,
speedY: (Math.random() - 0.5) * 0.5,
opacity: Math.random() * 0.5 + 0.1
})
}
}
const drawParticles = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
particles.forEach((particle, i) => {
particle.x += particle.speedX
particle.y += particle.speedY
if (particle.x < 0) particle.x = canvas.width
if (particle.x > canvas.width) particle.x = 0
if (particle.y < 0) particle.y = canvas.height
if (particle.y > canvas.height) particle.y = 0
ctx.beginPath()
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2)
ctx.fillStyle = `rgba(102, 126, 234, ${particle.opacity})`
ctx.fill()
particles.forEach((particle2, j) => {
if (i === j) return
const dx = particle.x - particle2.x
const dy = particle.y - particle2.y
const distance = Math.sqrt(dx * dx + dy * dy)
if (distance < 150) {
ctx.beginPath()
ctx.strokeStyle = `rgba(102, 126, 234, ${0.15 * (1 - distance / 150)})`
ctx.lineWidth = 0.5
ctx.moveTo(particle.x, particle.y)
ctx.lineTo(particle2.x, particle2.y)
ctx.stroke()
}
})
const dx = particle.x - mouseX
const dy = particle.y - mouseY
const distance = Math.sqrt(dx * dx + dy * dy)
if (distance < 200) {
const force = (200 - distance) / 200
particle.speedX += (dx / distance) * force * 0.02
particle.speedY += (dy / distance) * force * 0.02
}
particle.speedX *= 0.99
particle.speedY *= 0.99
})
animationId = requestAnimationFrame(drawParticles)
}
const handleMouseMove = (e: MouseEvent) => {
mouseX = e.clientX
mouseY = e.clientY
}
resize()
createParticles()
drawParticles()
window.addEventListener('resize', () => {
resize()
createParticles()
})
window.addEventListener('mousemove', handleMouseMove)
return () => {
cancelAnimationFrame(animationId)
window.removeEventListener('resize', resize)
window.removeEventListener('mousemove', handleMouseMove)
}
}, [])
return (
<canvas
ref={canvasRef}
className="absolute inset-0 pointer-events-none"
style={{ zIndex: 1 }}
/>
)
}

View File

@@ -0,0 +1,159 @@
import { useState } from 'react'
import ScrollReveal from './ScrollReveal'
const steps = [
{
id: 1,
title: '需求沟通',
desc: '深入了解您的品牌、目标受众和传播目标',
detail: '我们会安排专属项目经理与您进行1对1沟通了解视频用途、风格偏好、核心卖点等关键信息并输出详细的需求文档。',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
),
gradient: 'from-purple-500 to-pink-500'
},
{
id: 2,
title: '创意策划',
desc: 'AI辅助生成创意方案快速产出多版脚本',
detail: '基于需求文档我们使用AI快速生成多个创意方案和脚本草稿。您可以从中选择最喜欢的方案或融合多个方案的优点。',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
),
gradient: 'from-blue-500 to-cyan-500'
},
{
id: 3,
title: 'AI生成',
desc: '使用前沿AI技术高效生成视频素材',
detail: '根据确认的脚本我们使用Midjourney、Runway、Stable Diffusion等AI工具生成视频素材包括画面、配音、字幕等。',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
),
gradient: 'from-green-500 to-emerald-500'
},
{
id: 4,
title: '人工精修',
desc: '专业团队优化细节,确保品质达标',
detail: 'AI生成的初稿会由专业后期团队进行精修包括画面调色、节奏调整、特效添加等确保最终效果达到商用标准。',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
),
gradient: 'from-orange-500 to-yellow-500'
},
{
id: 5,
title: '交付验收',
desc: '多轮修改直至满意,提供完整源文件',
detail: '我们提供2-3轮免费修改直至您完全满意。交付内容包括成品视频、源文件、字体版权证明等方便您后续二次编辑。',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
gradient: 'from-pink-500 to-rose-500'
}
]
export default function ProcessAnimation() {
const [activeStep, setActiveStep] = useState(0)
return (
<section className="py-24 px-4 bg-[#0d0d2b]/50">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-6">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-4xl md:text-5xl font-bold mb-4">
<span className="gradient-text"></span>
</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
{/* Steps Timeline */}
<div className="lg:col-span-5">
<div className="space-y-4">
{steps.map((step, index) => (
<button
key={step.id}
onClick={() => setActiveStep(index)}
className={`w-full text-left p-5 rounded-2xl transition-all duration-300 ${
activeStep === index
? 'glass-card border-purple-500/50'
: 'hover:bg-white/5'
}`}
>
<div className="flex items-start gap-4">
<div className={`w-12 h-12 rounded-xl bg-gradient-to-br ${step.gradient} flex items-center justify-center text-white flex-shrink-0 transition-transform duration-300 ${
activeStep === index ? 'scale-110' : ''
}`}>
{step.icon}
</div>
<div>
<div className="flex items-center gap-2 mb-1">
<span className="text-xs text-gray-500"> {step.id}</span>
<h3 className={`font-semibold transition-colors ${
activeStep === index ? 'text-white' : 'text-gray-400'
}`}>
{step.title}
</h3>
</div>
<p className="text-sm text-gray-500">{step.desc}</p>
</div>
</div>
</button>
))}
</div>
</div>
{/* Step Detail */}
<div className="lg:col-span-7">
<div className="glass-card rounded-3xl p-8 md:p-10 h-full">
<div className="flex items-center gap-4 mb-6">
<div className={`w-16 h-16 rounded-2xl bg-gradient-to-br ${steps[activeStep].gradient} flex items-center justify-center text-white`}>
{steps[activeStep].icon}
</div>
<div>
<span className="text-sm text-gray-500"> {steps[activeStep].id}</span>
<h3 className="text-2xl font-bold text-white">{steps[activeStep].title}</h3>
</div>
</div>
<p className="text-gray-400 text-lg leading-relaxed mb-8">
{steps[activeStep].detail}
</p>
{/* Visual Indicator */}
<div className="relative h-2 bg-white/5 rounded-full overflow-hidden">
<div
className={`absolute inset-y-0 left-0 bg-gradient-to-r ${steps[activeStep].gradient} rounded-full transition-all duration-500`}
style={{ width: `${((activeStep + 1) / steps.length) * 100}%` }}
/>
</div>
<div className="flex justify-between mt-3 text-sm text-gray-500">
<span></span>
<span>{activeStep + 1}/{steps.length}</span>
<span></span>
</div>
</div>
</div>
</div>
</div>
</section>
)
}

View File

@@ -0,0 +1,69 @@
import { useEffect, useRef, ReactNode } from 'react'
interface ScrollRevealProps {
children: ReactNode
direction?: 'up' | 'down' | 'left' | 'right'
delay?: number
className?: string
}
export default function ScrollReveal({
children,
direction = 'up',
delay = 0,
className = ''
}: ScrollRevealProps) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setTimeout(() => {
entry.target.classList.add('animate-visible')
}, delay)
observer.disconnect()
}
},
{ threshold: 0.1 }
)
if (ref.current) {
observer.observe(ref.current)
}
return () => observer.disconnect()
}, [delay])
const getInitialTransform = () => {
switch (direction) {
case 'up': return 'translateY(60px)'
case 'down': return 'translateY(-60px)'
case 'left': return 'translateX(-60px)'
case 'right': return 'translateX(60px)'
}
}
return (
<div
ref={ref}
className={className}
style={{
opacity: 0,
transform: getInitialTransform(),
transition: `all 0.8s cubic-bezier(0.4, 0, 0.2, 1) ${delay}ms`
}}
>
{children}
</div>
)
}
const style = document.createElement('style')
style.textContent = `
.animate-visible {
opacity: 1 !important;
transform: translateY(0) translateX(0) !important;
}
`
document.head.appendChild(style)

View File

@@ -0,0 +1,148 @@
import { useState } from 'react'
import ScrollReveal from './ScrollReveal'
const scenes = [
{
id: 'social',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2m-9 0h10m-10 0H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2h-2" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 11v6m-3-3h6" />
</svg>
),
title: '社交媒体',
desc: '抖音、小红书、Instagram等平台爆款内容',
features: ['15秒竖屏视频', '高完播率设计', '爆款文案生成', '多平台适配'],
gradient: 'from-pink-500 to-rose-500'
},
{
id: 'ecommerce',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
</svg>
),
title: '电商营销',
desc: '产品展示、直播切片、详情页视频',
features: ['3D产品展示', '卖点可视化', '多角度展示', '批量生成'],
gradient: 'from-orange-500 to-yellow-500'
},
{
id: 'education',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
),
title: '教育培训',
desc: '在线课程、知识科普、企业内训',
features: ['知识可视化', 'AI讲师生成', '课程片头制作', '互动元素'],
gradient: 'from-blue-500 to-cyan-500'
},
{
id: 'brand',
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
),
title: '企业宣传',
desc: '品牌故事、企业宣传片、招聘视频',
features: ['品牌形象塑造', '企业文化展示', '数字人代言', '多语言版本'],
gradient: 'from-purple-500 to-violet-500'
}
]
export default function ServiceScenes() {
const [activeScene, setActiveScene] = useState(scenes[0])
return (
<section className="py-24 px-4">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-6">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-4xl md:text-5xl font-bold mb-4">
<span className="gradient-text">AI视频</span>
</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
AI视频解决方案
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8">
{/* Scene Tabs */}
<div className="lg:col-span-4 space-y-3">
{scenes.map((scene) => (
<button
key={scene.id}
onClick={() => setActiveScene(scene)}
className={`w-full text-left p-5 rounded-2xl transition-all duration-300 ${
activeScene.id === scene.id
? 'glass-card border-purple-500/50'
: 'hover:bg-white/5'
}`}
>
<div className="flex items-center gap-4">
<div className={`w-12 h-12 rounded-xl bg-gradient-to-br ${scene.gradient} flex items-center justify-center text-white flex-shrink-0`}>
{scene.icon}
</div>
<div>
<h3 className={`font-semibold transition-colors ${
activeScene.id === scene.id ? 'text-white' : 'text-gray-400'
}`}>
{scene.title}
</h3>
<p className="text-sm text-gray-500">{scene.desc}</p>
</div>
</div>
</button>
))}
</div>
{/* Scene Detail */}
<div className="lg:col-span-8">
<div className="glass-card rounded-3xl p-8 md:p-10">
<div className="flex items-center gap-4 mb-8">
<div className={`w-16 h-16 rounded-2xl bg-gradient-to-br ${activeScene.gradient} flex items-center justify-center text-white`}>
{activeScene.icon}
</div>
<div>
<h3 className="text-2xl font-bold text-white">{activeScene.title}</h3>
<p className="text-gray-400">{activeScene.desc}</p>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-8">
{activeScene.features.map((feature, index) => (
<div key={index} className="flex items-center gap-3 p-4 rounded-xl bg-white/5">
<div className={`w-8 h-8 rounded-lg bg-gradient-to-br ${activeScene.gradient} flex items-center justify-center flex-shrink-0`}>
<svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<span className="text-gray-300">{feature}</span>
</div>
))}
</div>
<div className="aspect-video rounded-2xl overflow-hidden bg-gradient-to-br from-purple-900/50 to-blue-900/50 flex items-center justify-center">
<div className="text-center">
<div className="w-20 h-20 mx-auto mb-4 rounded-full gradient-bg-animated flex items-center justify-center">
<svg className="w-10 h-10 text-white ml-1" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
</div>
<p className="text-gray-400"> {activeScene.title} </p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
)
}

View File

@@ -0,0 +1,37 @@
interface Testimonial {
name: string
role: string
company: string
content: string
avatar: string
}
interface TestimonialCardProps {
testimonial: Testimonial
}
export default function TestimonialCard({ testimonial }: TestimonialCardProps) {
return (
<div className="glass-card rounded-2xl p-8 hover-lift">
<div className="flex items-center mb-6">
<div className="w-14 h-14 rounded-full overflow-hidden mr-4 border-2 border-purple-500/30">
<img
src={testimonial.avatar}
alt={testimonial.name}
className="w-full h-full object-cover"
/>
</div>
<div>
<h4 className="text-white font-semibold">{testimonial.name}</h4>
<p className="text-gray-400 text-sm">{testimonial.role} · {testimonial.company}</p>
</div>
</div>
<div className="mb-4">
{[...Array(5)].map((_, i) => (
<span key={i} className="text-yellow-400 text-lg"></span>
))}
</div>
<p className="text-gray-300 leading-relaxed">"{testimonial.content}"</p>
</div>
)
}

View File

@@ -0,0 +1,73 @@
import { useState, useRef } from 'react'
import { Video } from '../data/videos'
interface VideoCardProps {
video: Video
onClick: (video: Video) => void
}
export default function VideoCard({ video, onClick }: VideoCardProps) {
const [tilt, setTilt] = useState({ x: 0, y: 0 })
const cardRef = useRef<HTMLDivElement>(null)
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!cardRef.current) return
const rect = cardRef.current.getBoundingClientRect()
const x = (e.clientX - rect.left) / rect.width
const y = (e.clientY - rect.top) / rect.height
setTilt({
x: (y - 0.5) * 10,
y: (x - 0.5) * -10
})
}
const handleMouseLeave = () => {
setTilt({ x: 0, y: 0 })
}
return (
<div
ref={cardRef}
className="group cursor-pointer rounded-2xl overflow-hidden gradient-border glow-on-hover"
onClick={() => onClick(video)}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{
transform: `perspective(1000px) rotateX(${tilt.x}deg) rotateY(${tilt.y}deg)`,
transition: 'transform 0.3s ease'
}}
>
<div className="relative aspect-video overflow-hidden">
<img
src={video.thumbnail}
alt={video.title}
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-all duration-500" />
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-20 h-20 rounded-full gradient-bg-animated flex items-center justify-center opacity-0 group-hover:opacity-100 transform scale-0 group-hover:scale-100 transition-all duration-500 shadow-2xl shadow-purple-500/50">
<svg className="w-10 h-10 text-white ml-1" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
</div>
</div>
<div className="absolute top-4 right-4 px-3 py-1.5 rounded-full text-xs font-semibold gradient-bg-animated shadow-lg">
{video.category}
</div>
<div className="absolute bottom-0 left-0 right-0 h-1 gradient-bg-animated transform scale-x-0 group-hover:scale-x-100 transition-transform duration-500 origin-left" />
</div>
<div className="p-6 bg-[#0d0d2b]">
<h3 className="text-white font-bold text-lg mb-2 group-hover:text-transparent group-hover:bg-clip-text group-hover:bg-gradient-to-r group-hover:from-purple-400 group-hover:to-pink-400 transition-all duration-300">
{video.title}
</h3>
<p className="text-gray-400 text-sm line-clamp-2 group-hover:text-gray-300 transition-colors">
{video.description}
</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,70 @@
import { useEffect, useRef } from 'react'
import { Video } from '../data/videos'
interface VideoModalProps {
video: Video | null
onClose: () => void
}
export default function VideoModal({ video, onClose }: VideoModalProps) {
const videoRef = useRef<HTMLVideoElement>(null)
useEffect(() => {
if (video && videoRef.current) {
videoRef.current.play()
}
}, [video])
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose()
}
document.addEventListener('keydown', handleEscape)
return () => document.removeEventListener('keydown', handleEscape)
}, [onClose])
if (!video) return null
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/80 backdrop-blur-sm"
onClick={onClose}
>
<div
className="relative w-full max-w-4xl bg-[#1a1a2e] rounded-2xl overflow-hidden animate-fade-in-up"
onClick={(e) => e.stopPropagation()}
>
<button
onClick={onClose}
className="absolute top-4 right-4 z-10 w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors"
>
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<div className="aspect-video">
<video
ref={videoRef}
src={video.url}
controls
className="w-full h-full"
poster={video.thumbnail}
>
</video>
</div>
<div className="p-6">
<div className="flex items-center gap-3 mb-2">
<h2 className="text-2xl font-bold text-white">{video.title}</h2>
<span className="px-3 py-1 rounded-full text-sm gradient-bg">
{video.category}
</span>
</div>
<p className="text-gray-400">{video.description}</p>
</div>
</div>
</div>
)
}

148
src/data/videos.ts Normal file
View File

@@ -0,0 +1,148 @@
export interface Video {
id: number
title: string
description: string
url: string
thumbnail: string
category: string
duration: string
tech: string[]
client?: string
}
export const videos: Video[] = [
{
id: 1,
title: 'AI智能城市宣传片',
description: '利用AI技术生成的未来城市概念视频展示智慧城市蓝图融合3D建模与实拍素材',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh1/640/360',
category: '宣传片',
duration: '2:30',
tech: ['Stable Diffusion', 'Runway Gen-2', 'After Effects'],
client: '某市政府'
},
{
id: 2,
title: '电商产品展示动画',
description: 'AI驱动的产品3D展示动画多角度展示产品细节适用于电商平台',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh2/640/360',
category: '产品展示',
duration: '0:45',
tech: ['Midjourney', 'Blender', 'ComfyUI'],
client: '某电商品牌'
},
{
id: 3,
title: '品牌故事短片',
description: '用AI讲述品牌故事情感与技术的完美结合传递品牌价值观',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh3/640/360',
category: '品牌故事',
duration: '3:15',
tech: ['Pika Labs', 'ElevenLabs', 'Premiere Pro'],
client: '某新消费品牌'
},
{
id: 4,
title: '抖音爆款短视频',
description: '为社交媒体平台定制的AI短视频内容高完播率引爆流量',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh4/640/360',
category: '社交媒体',
duration: '0:15',
tech: ['HeyGen', 'CapCut', 'D-ID'],
client: '某MCN机构'
},
{
id: 5,
title: '在线课程片头',
description: 'AI生成的教育内容片头让知识传播更生动有趣',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh5/640/360',
category: '教育培训',
duration: '1:00',
tech: ['Synthesia', 'D-ID', 'After Effects'],
client: '某在线教育平台'
},
{
id: 6,
title: 'AI数字人主播',
description: 'AI数字人技术7x24小时不间断直播降低人力成本',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh6/640/360',
category: '数字人',
duration: '1:30',
tech: ['HeyGen', 'D-ID', 'ElevenLabs'],
client: '某电商平台'
},
{
id: 7,
title: '房地产虚拟看房',
description: 'AI生成的房产展示视频虚拟漫游+实景融合,提升看房体验',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh7/640/360',
category: '产品展示',
duration: '2:00',
tech: ['Unreal Engine', 'Stable Diffusion', 'Runway'],
client: '某地产开发商'
},
{
id: 8,
title: '游戏宣传CG',
description: 'AI辅助生成的游戏宣传CG史诗级视觉效果成本仅为传统1/10',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh8/640/360',
category: '宣传片',
duration: '1:45',
tech: ['Midjourney', 'Runway Gen-2', 'Nuke'],
client: '某游戏公司'
},
{
id: 9,
title: '医疗科普动画',
description: '专业医疗知识可视化AI生成的医学动画让复杂概念通俗易懂',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh9/640/360',
category: '教育培训',
duration: '2:20',
tech: ['Stable Diffusion', 'After Effects', 'Blender'],
client: '某医疗机构'
},
{
id: 10,
title: '餐饮品牌宣传片',
description: 'AI生成的美食展示视频诱人画面+品牌故事,提升品牌调性',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh10/640/360',
category: '品牌故事',
duration: '1:50',
tech: ['Midjourney', 'Pika Labs', 'Premiere Pro'],
client: '某连锁餐饮品牌'
},
{
id: 11,
title: '小红书种草视频',
description: '为小红书平台定制的种草视频,高转化率,精准触达目标用户',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh11/640/360',
category: '社交媒体',
duration: '0:30',
tech: ['HeyGen', 'CapCut', 'ComfyUI'],
client: '某美妆品牌'
},
{
id: 12,
title: 'AI虚拟偶像直播',
description: '全栈AI虚拟偶像解决方案从形象设计到实时驱动一站式服务',
url: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
thumbnail: 'https://picsum.photos/seed/cyh12/640/360',
category: '数字人',
duration: '3:00',
tech: ['D-ID', 'ElevenLabs', 'OBS'],
client: '某直播平台'
}
]
export const categories = ['全部', '宣传片', '产品展示', '品牌故事', '社交媒体', '教育培训', '数字人']

249
src/index.css Normal file
View File

@@ -0,0 +1,249 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background-color: #0a0a1a;
color: #ffffff;
min-height: 100vh;
overflow-x: hidden;
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #1a1a2e;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, #667eea, #764ba2);
border-radius: 4px;
}
.gradient-text {
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
background-size: 200% 200%;
animation: gradientShift 3s ease infinite;
}
@keyframes gradientShift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.gradient-bg-animated {
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 200% 200%;
animation: gradientShift 3s ease infinite;
}
.glass-effect {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.glass-card {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.glass-card:hover {
background: rgba(255, 255, 255, 0.08);
border-color: rgba(102, 126, 234, 0.3);
box-shadow: 0 0 30px rgba(102, 126, 234, 0.15);
}
@keyframes float {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-20px) rotate(2deg); }
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.8s ease-out forwards;
}
@keyframes fadeInLeft {
from {
opacity: 0;
transform: translateX(-40px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.animate-fade-in-left {
animation: fadeInLeft 0.8s ease-out forwards;
}
@keyframes fadeInRight {
from {
opacity: 0;
transform: translateX(40px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.animate-fade-in-right {
animation: fadeInRight 0.8s ease-out forwards;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
.animate-scale-in {
animation: scaleIn 0.6s ease-out forwards;
}
@keyframes pulse-glow {
0%, 100% {
box-shadow: 0 0 20px rgba(102, 126, 234, 0.3);
}
50% {
box-shadow: 0 0 40px rgba(102, 126, 234, 0.6);
}
}
.animate-pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
.gradient-border {
position: relative;
background: #0a0a1a;
border-radius: 1rem;
}
.gradient-border::before {
content: '';
position: absolute;
inset: -2px;
border-radius: inherit;
background: linear-gradient(135deg, #667eea, #764ba2, #f093fb, #667eea);
background-size: 300% 300%;
animation: gradientShift 4s ease infinite;
z-index: -1;
}
.tilt-card {
transition: transform 0.3s ease;
transform-style: preserve-3d;
}
.tilt-card:hover {
transform: perspective(1000px) rotateX(5deg) rotateY(5deg) scale(1.02);
}
.glow-on-hover {
transition: all 0.3s ease;
}
.glow-on-hover:hover {
box-shadow: 0 0 30px rgba(102, 126, 234, 0.4),
0 0 60px rgba(118, 75, 162, 0.2);
}
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
.animate-marquee {
animation: marquee 30s linear infinite;
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.animate-shimmer {
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0) 100%
);
background-size: 200% 100%;
animation: shimmer 2s infinite;
}
@keyframes spin-slow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.animate-spin-slow {
animation: spin-slow 20s linear infinite;
}
.text-shadow-glow {
text-shadow: 0 0 20px rgba(102, 126, 234, 0.5),
0 0 40px rgba(118, 75, 162, 0.3);
}
.section-divider {
height: 1px;
background: linear-gradient(90deg, transparent, rgba(102, 126, 234, 0.3), transparent);
}
input:focus, textarea:focus {
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.3);
}
.hover-lift {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.hover-lift:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}

10
src/main.tsx Normal file
View File

@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)

290
src/pages/About.tsx Normal file
View File

@@ -0,0 +1,290 @@
import AnimatedCounter from '../components/AnimatedCounter'
import ScrollReveal from '../components/ScrollReveal'
const timeline = [
{ year: '2020', title: '公司成立', desc: '在香港成立专注于AI视频技术研发' },
{ year: '2021', title: '技术突破', desc: '自研AI视频生成算法效率提升5倍' },
{ year: '2022', title: '业务拓展', desc: '服务客户超过50家覆盖多个行业' },
{ year: '2023', title: '团队壮大', desc: '团队扩展至50人建立完整服务体系' },
{ year: '2024', title: '行业领先', desc: '累计服务500+项目,成为行业标杆' }
]
const team = [
{ name: '陈博士', role: '首席技术官', desc: '前Google AI研究员10年深度学习经验', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=cto' },
{ name: '林总监', role: '创意总监', desc: '资深广告人服务过50+知名品牌', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=cd' },
{ name: '王经理', role: '项目总监', desc: 'PMP认证管理过200+视频项目', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=pm' },
{ name: '张工程师', role: 'AI工程师', desc: 'Stable Diffusion专家精通多款AI工具', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ai' }
]
export default function About() {
return (
<div className="pt-20">
{/* Hero */}
<section className="py-20 px-4 relative overflow-hidden">
<div className="absolute inset-0">
<div className="absolute top-1/3 left-1/4 w-96 h-96 bg-purple-600/10 rounded-full blur-[128px]" />
<div className="absolute bottom-1/3 right-1/4 w-96 h-96 bg-blue-600/10 rounded-full blur-[128px]" />
</div>
<div className="max-w-7xl mx-auto relative z-10">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h1 className="text-4xl md:text-5xl font-bold mb-4">
<span className="gradient-text">CYH Technology</span>
</h1>
<p className="text-lg text-gray-400 max-w-2xl mx-auto">
AI短视频制作公司沿
</p>
</div>
</ScrollReveal>
</div>
</section>
{/* Story Section */}
<section className="py-20 px-4">
<div className="max-w-7xl mx-auto">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
<ScrollReveal direction="left">
<div>
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-white">
AI <span className="gradient-text"></span>
</h2>
<div className="space-y-4 text-gray-400 leading-relaxed">
<p>
HK CYH Technology AI短视频制作的创新科技公司
沿
</p>
<p>
AI算法专家
</p>
<p>
AI技术重新定义视频制作的边界
</p>
</div>
</div>
</ScrollReveal>
<ScrollReveal direction="right">
<div className="grid grid-cols-2 gap-4">
{[
{ end: 500, suffix: '+', label: '完成项目', gradient: 'from-purple-500 to-pink-500' },
{ end: 100, suffix: '+', label: '合作客户', gradient: 'from-blue-500 to-cyan-500' },
{ end: 50, suffix: '+', label: '团队成员', gradient: 'from-green-500 to-emerald-500' },
{ end: 98, suffix: '%', label: '客户满意度', gradient: 'from-yellow-500 to-orange-500' }
].map((stat, index) => (
<div key={index} className="glass-card rounded-2xl p-6 text-center hover-lift group">
<div className={`w-14 h-14 mx-auto mb-3 rounded-xl bg-gradient-to-br ${stat.gradient} flex items-center justify-center opacity-80 group-hover:opacity-100 transition-opacity`}>
<span className="text-xl font-bold text-white">{stat.suffix === '%' ? '%' : '+'}</span>
</div>
<AnimatedCounter end={stat.end} suffix={stat.suffix} />
<p className="text-gray-400 mt-2 text-sm">{stat.label}</p>
</div>
))}
</div>
</ScrollReveal>
</div>
</div>
</section>
{/* Timeline */}
<section className="py-20 px-4 bg-[#0d0d2b]/50">
<div className="max-w-5xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold">
<span className="gradient-text"></span>
</h2>
</div>
</ScrollReveal>
<div className="relative">
{/* Timeline Line */}
<div className="absolute left-1/2 transform -translate-x-1/2 w-0.5 h-full bg-gradient-to-b from-purple-500 to-blue-500 hidden md:block" />
<div className="space-y-8">
{timeline.map((item, index) => (
<ScrollReveal key={index} delay={index * 100}>
<div className={`flex items-center gap-8 ${index % 2 === 0 ? 'md:flex-row' : 'md:flex-row-reverse'}`}>
<div className={`flex-1 ${index % 2 === 0 ? 'md:text-right' : 'md:text-left'}`}>
<div className="glass-card rounded-2xl p-6 inline-block">
<div className="text-2xl font-bold gradient-text mb-2">{item.year}</div>
<h3 className="text-white font-semibold mb-1">{item.title}</h3>
<p className="text-gray-400 text-sm">{item.desc}</p>
</div>
</div>
<div className="hidden md:flex w-4 h-4 rounded-full gradient-bg flex-shrink-0" />
<div className="flex-1" />
</div>
</ScrollReveal>
))}
</div>
</div>
</div>
</section>
{/* Team */}
<section className="py-20 px-4">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-4">
<span className="gradient-text"></span>
</h2>
<p className="text-gray-400 max-w-xl mx-auto">
AI专家+
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{team.map((member, index) => (
<ScrollReveal key={index} delay={index * 100}>
<div className="glass-card rounded-2xl p-6 text-center hover-lift group">
<div className="w-20 h-20 mx-auto mb-4 rounded-full overflow-hidden border-2 border-purple-500/30 group-hover:border-purple-500 transition-colors">
<img src={member.avatar} alt={member.name} className="w-full h-full object-cover" />
</div>
<h3 className="text-white font-semibold mb-1">{member.name}</h3>
<p className="text-purple-400 text-sm mb-2">{member.role}</p>
<p className="text-gray-500 text-sm">{member.desc}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
{/* Tech Advantages */}
<section className="py-20 px-4 bg-[#0d0d2b]/50">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold">
<span className="gradient-text"></span>
</h2>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{[
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
),
title: 'AI生成技术',
desc: '先进的深度学习模型,实现高质量视频内容自动生成',
gradient: 'from-violet-500 to-purple-500'
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
title: '智能编辑',
desc: 'AI驱动的智能剪辑系统自动优化视频节奏和效果',
gradient: 'from-blue-500 to-cyan-500'
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
</svg>
),
title: '风格迁移',
desc: '独特的艺术风格迁移技术,让视频呈现多样化视觉效果',
gradient: 'from-pink-500 to-rose-500'
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
),
title: '数字人技术',
desc: '逼真的AI数字人生成打造虚拟形象代言人',
gradient: 'from-green-500 to-emerald-500'
}
].map((tech, index) => (
<ScrollReveal key={index} delay={index * 100}>
<div className="group glass-card rounded-2xl p-6 hover-lift relative overflow-hidden h-full">
<div className={`absolute -top-10 -right-10 w-40 h-40 bg-gradient-to-br ${tech.gradient} opacity-10 rounded-full blur-3xl group-hover:opacity-20 transition-opacity`} />
<div className={`w-14 h-14 rounded-xl bg-gradient-to-br ${tech.gradient} flex items-center justify-center mb-4 text-white shadow-lg group-hover:scale-110 transition-transform duration-300`}>
{tech.icon}
</div>
<h3 className="text-lg font-bold text-white mb-2">{tech.title}</h3>
<p className="text-gray-400 text-sm leading-relaxed">{tech.desc}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
{/* Service Process */}
<section className="py-20 px-4">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold">
<span className="gradient-text"></span>
</h2>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
{[
{ step: '01', title: '需求沟通', desc: '深入了解客户需求和品牌调性', gradient: 'from-purple-500 to-pink-500' },
{ step: '02', title: '创意策划', desc: 'AI辅助生成创意方案和脚本', gradient: 'from-blue-500 to-cyan-500' },
{ step: '03', title: '视频制作', desc: 'AI技术驱动的高效视频生成', gradient: 'from-green-500 to-emerald-500' },
{ step: '04', title: '交付优化', desc: '专业团队审核优化,确保品质', gradient: 'from-yellow-500 to-orange-500' }
].map((process, index) => (
<ScrollReveal key={index} delay={index * 100}>
<div className="relative group">
<div className="glass-card rounded-2xl p-6 text-center hover-lift h-full">
<div className={`w-14 h-14 gradient-bg-animated rounded-xl flex items-center justify-center mx-auto mb-4 shadow-lg`}>
<span className="text-xl font-bold text-white">{process.step}</span>
</div>
<h3 className="text-lg font-bold text-white mb-2">{process.title}</h3>
<p className="text-gray-400 text-sm">{process.desc}</p>
</div>
{index < 3 && (
<div className="hidden md:block absolute top-1/2 -right-3 transform -translate-y-1/2 z-10">
<svg className="w-6 h-6 text-purple-500/50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
)}
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
</div>
)
}

247
src/pages/Contact.tsx Normal file
View File

@@ -0,0 +1,247 @@
import { useState } from 'react'
import ScrollReveal from '../components/ScrollReveal'
import FAQ from '../components/FAQ'
export default function Contact() {
const [formData, setFormData] = useState({
name: '',
email: '',
phone: '',
company: '',
budget: '',
message: ''
})
const [isSubmitting, setIsSubmitting] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
await new Promise(resolve => setTimeout(resolve, 1500))
alert('感谢您的留言,我们会尽快与您联系!')
setFormData({ name: '', email: '', phone: '', company: '', budget: '', message: '' })
setIsSubmitting(false)
}
return (
<div className="pt-20">
{/* Hero */}
<section className="py-20 px-4 relative overflow-hidden">
<div className="absolute inset-0">
<div className="absolute top-1/3 left-1/4 w-96 h-96 bg-purple-600/10 rounded-full blur-[128px]" />
<div className="absolute bottom-1/3 right-1/4 w-96 h-96 bg-blue-600/10 rounded-full blur-[128px]" />
</div>
<div className="max-w-7xl mx-auto relative z-10">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h1 className="text-4xl md:text-5xl font-bold mb-4">
<span className="gradient-text"></span>
</h1>
<p className="text-lg text-gray-400 max-w-2xl mx-auto">
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
{/* Form */}
<ScrollReveal direction="left">
<div className="glass-card rounded-3xl p-8">
<h2 className="text-2xl font-bold mb-6 text-white"></h2>
<form onSubmit={handleSubmit} className="space-y-5">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
<div>
<label className="block text-gray-400 mb-2 text-sm font-medium"> *</label>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:border-purple-500/50 transition-all placeholder-gray-500"
placeholder="请输入您的姓名"
required
/>
</div>
<div>
<label className="block text-gray-400 mb-2 text-sm font-medium"> *</label>
<input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:border-purple-500/50 transition-all placeholder-gray-500"
placeholder="请输入您的邮箱"
required
/>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
<div>
<label className="block text-gray-400 mb-2 text-sm font-medium"></label>
<input
type="tel"
value={formData.phone}
onChange={(e) => setFormData({ ...formData, phone: e.target.value })}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:border-purple-500/50 transition-all placeholder-gray-500"
placeholder="请输入您的电话"
/>
</div>
<div>
<label className="block text-gray-400 mb-2 text-sm font-medium"></label>
<input
type="text"
value={formData.company}
onChange={(e) => setFormData({ ...formData, company: e.target.value })}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:border-purple-500/50 transition-all placeholder-gray-500"
placeholder="请输入您的公司名称"
/>
</div>
</div>
<div>
<label className="block text-gray-400 mb-2 text-sm font-medium"></label>
<select
value={formData.budget}
onChange={(e) => setFormData({ ...formData, budget: e.target.value })}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:border-purple-500/50 transition-all appearance-none"
>
<option value="" className="bg-[#0a0a1a]"></option>
<option value="5000" className="bg-[#0a0a1a]">5,000 </option>
<option value="10000" className="bg-[#0a0a1a]">5,000 - 10,000</option>
<option value="30000" className="bg-[#0a0a1a]">10,000 - 30,000</option>
<option value="50000" className="bg-[#0a0a1a]">30,000 - 50,000</option>
<option value="more" className="bg-[#0a0a1a]">50,000 </option>
</select>
</div>
<div>
<label className="block text-gray-400 mb-2 text-sm font-medium"> *</label>
<textarea
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
rows={4}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:border-purple-500/50 transition-all resize-none placeholder-gray-500"
placeholder="请描述您的需求,包括视频类型、时长、用途等"
required
/>
</div>
<button
type="submit"
disabled={isSubmitting}
className="w-full py-4 gradient-bg-animated rounded-xl text-white font-bold text-lg hover:shadow-2xl hover:shadow-purple-500/25 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed relative overflow-hidden"
>
{isSubmitting ? (
<div className="flex items-center justify-center">
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin mr-2" />
...
</div>
) : (
'发送消息'
)}
</button>
</form>
</div>
</ScrollReveal>
{/* Contact Info */}
<ScrollReveal direction="right">
<div className="space-y-6">
<div className="glass-card rounded-3xl p-8">
<h2 className="text-2xl font-bold mb-6 text-white"></h2>
<div className="space-y-6">
{[
{
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
),
title: '邮箱',
content: 'info@cyhtechnology.com',
gradient: 'from-purple-500 to-pink-500'
},
{
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
),
title: '电话',
content: '+852 XXXX XXXX',
gradient: 'from-blue-500 to-cyan-500'
},
{
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
),
title: '地址',
content: '香港九龙湾XX大厦',
gradient: 'from-green-500 to-emerald-500'
}
].map((contact, index) => (
<div key={index} className="flex items-start gap-4 group">
<div className={`w-12 h-12 rounded-xl bg-gradient-to-br ${contact.gradient} flex items-center justify-center flex-shrink-0 shadow-lg group-hover:scale-110 transition-transform duration-300`}>
{contact.icon}
</div>
<div>
<h3 className="text-white font-semibold mb-1">{contact.title}</h3>
<p className="text-gray-400">{contact.content}</p>
</div>
</div>
))}
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<div className="glass-card rounded-2xl p-6">
<h3 className="text-lg font-bold text-white mb-4"></h3>
<div className="space-y-3 text-sm">
<div className="flex justify-between">
<span className="text-gray-400"></span>
<span className="text-white">9:00-18:00</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400"></span>
<span className="text-white">10:00-14:00</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400"></span>
<span className="text-gray-500"></span>
</div>
</div>
</div>
<div className="glass-card rounded-2xl p-6 gradient-bg-animated">
<h3 className="text-lg font-bold text-white mb-4"></h3>
<p className="text-white/80 text-sm mb-4">
24线
</p>
<div className="text-2xl font-bold text-white">+852 XXXX XXXX</div>
</div>
</div>
{/* Map Placeholder */}
<div className="glass-card rounded-2xl overflow-hidden">
<div className="aspect-[16/9] bg-gradient-to-br from-purple-900/50 to-blue-900/50 flex items-center justify-center">
<div className="text-center">
<svg className="w-12 h-12 text-gray-500 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<p className="text-gray-400"></p>
</div>
</div>
</div>
</div>
</ScrollReveal>
</div>
</div>
</section>
{/* FAQ */}
<FAQ />
</div>
)
}

380
src/pages/Home.tsx Normal file
View File

@@ -0,0 +1,380 @@
import { useState } from 'react'
import { Link } from 'react-router-dom'
import VideoCard from '../components/VideoCard'
import VideoModal from '../components/VideoModal'
import ParticleBackground from '../components/ParticleBackground'
import AnimatedCounter from '../components/AnimatedCounter'
import MarqueeTicker from '../components/MarqueeTicker'
import TestimonialCard from '../components/TestimonialCard'
import ScrollReveal from '../components/ScrollReveal'
import ServiceScenes from '../components/ServiceScenes'
import CaseComparison from '../components/CaseComparison'
import ProcessAnimation from '../components/ProcessAnimation'
import FAQ from '../components/FAQ'
import { videos, Video } from '../data/videos'
const testimonials = [
{
name: '张总',
role: '市场总监',
company: '某科技公司',
content: 'CYH Technology 的 AI 短视频制作效率令人惊叹,原本需要两周的工作现在一天就能完成,而且质量非常出色!',
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=zhang'
},
{
name: '李经理',
role: '品牌负责人',
company: '某电商平台',
content: '他们的创意团队非常专业,能够精准把握我们的品牌调性,制作出的视频在社交媒体上获得了极高的传播率。',
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=li'
},
{
name: '王女士',
role: '创始人',
company: '某新消费品牌',
content: '作为初创公司CYH Technology 帮我们用有限预算实现了高品质的品牌视频,性价比非常高!',
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=wang'
}
]
export default function Home() {
const [selectedVideo, setSelectedVideo] = useState<Video | null>(null)
const featuredVideos = videos.slice(0, 6)
return (
<div>
{/* Hero Section */}
<section className="relative min-h-screen flex items-center justify-center overflow-hidden">
<ParticleBackground />
<div className="absolute inset-0">
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-purple-600/20 rounded-full blur-[128px] animate-float" />
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-blue-600/20 rounded-full blur-[128px] animate-float" style={{ animationDelay: '2s' }} />
</div>
<div className="relative z-10 px-4 max-w-7xl mx-auto">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
{/* Left Content */}
<div className="animate-fade-in-up">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-6">
<span className="w-2 h-2 bg-green-400 rounded-full mr-2 animate-pulse" />
<span className="text-gray-300 text-sm"> AI </span>
</div>
<h1 className="text-5xl md:text-6xl font-bold mb-6 leading-tight">
<span className="gradient-text">AI短视频</span>
<br />
<span className="text-white"></span>
</h1>
<p className="text-lg text-gray-400 mb-8 max-w-lg leading-relaxed">
沿 AI 1080%
</p>
<div className="flex flex-col sm:flex-row gap-4 mb-12">
<Link
to="/works"
className="group px-8 py-4 gradient-bg-animated rounded-2xl text-white font-bold text-lg overflow-hidden relative"
>
<span className="relative z-10 flex items-center justify-center">
<svg className="w-5 h-5 ml-2 transform group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</span>
</Link>
<Link
to="/contact"
className="px-8 py-4 border-2 border-purple-500/50 rounded-2xl text-purple-400 font-bold text-lg hover:border-purple-400 hover:bg-purple-500/10 transition-all duration-300"
>
</Link>
</div>
{/* Quick Stats */}
<div className="flex gap-8">
{[
{ value: '500+', label: '成功案例' },
{ value: '98%', label: '满意度' },
{ value: '10x', label: '效率提升' }
].map((stat, index) => (
<div key={index}>
<div className="text-2xl font-bold gradient-text">{stat.value}</div>
<div className="text-sm text-gray-500">{stat.label}</div>
</div>
))}
</div>
</div>
{/* Right - Video Showcase */}
<div className="hidden lg:block relative">
<div className="relative">
{/* Main Video Card */}
<div className="glass-card rounded-3xl overflow-hidden transform rotate-2 hover:rotate-0 transition-transform duration-500">
<div className="aspect-video bg-gradient-to-br from-purple-900/50 to-blue-900/50 flex items-center justify-center">
<div className="text-center">
<div className="w-20 h-20 mx-auto mb-4 rounded-full gradient-bg-animated flex items-center justify-center animate-pulse-glow">
<svg className="w-10 h-10 text-white ml-1" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
</div>
<p className="text-gray-400">AI生成的品牌宣传片</p>
</div>
</div>
</div>
{/* Floating Cards */}
<div className="absolute -bottom-6 -left-6 glass-card rounded-2xl p-4 animate-float" style={{ animationDelay: '1s' }}>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-green-500/20 flex items-center justify-center">
<svg className="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<div>
<div className="text-sm font-semibold text-white">10x </div>
<div className="text-xs text-gray-500"></div>
</div>
</div>
</div>
<div className="absolute -top-6 -right-6 glass-card rounded-2xl p-4 animate-float" style={{ animationDelay: '2s' }}>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-purple-500/20 flex items-center justify-center">
<svg className="w-5 h-5 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div>
<div className="text-sm font-semibold text-white">80% </div>
<div className="text-xs text-gray-500"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="absolute bottom-12 left-1/2 transform -translate-x-1/2 animate-bounce">
<div className="w-6 h-10 border-2 border-white/30 rounded-full flex justify-center">
<div className="w-1.5 h-3 bg-white/50 rounded-full mt-2 animate-pulse" />
</div>
</div>
</section>
{/* Partners Marquee */}
<section className="py-12 bg-[#0d0d2b]/50">
<ScrollReveal>
<div className="text-center mb-6">
<p className="text-gray-500 text-sm uppercase tracking-widest"></p>
</div>
</ScrollReveal>
<MarqueeTicker />
</section>
{/* Stats Section */}
<section className="py-20 px-4 relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-b from-purple-900/10 to-transparent" />
<div className="max-w-7xl mx-auto relative z-10">
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
{[
{ end: 500, suffix: '+', label: '完成项目' },
{ end: 100, suffix: '+', label: '合作客户' },
{ end: 50, suffix: '+', label: '团队成员' },
{ end: 98, suffix: '%', label: '客户满意度' }
].map((stat, index) => (
<ScrollReveal key={index} delay={index * 100}>
<div className="text-center glass-card rounded-2xl p-6 hover-lift">
<AnimatedCounter end={stat.end} suffix={stat.suffix} />
<p className="text-gray-400 mt-2 font-medium">{stat.label}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
{/* Features Section */}
<section className="py-20 px-4">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-4">
<span className="gradient-text">CYH</span>
</h2>
<p className="text-gray-400 max-w-xl mx-auto">
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
),
title: '高效产出',
desc: 'AI驱动的制作流程将传统数周的制作周期缩短至数小时',
gradient: 'from-yellow-500 to-orange-500'
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
</svg>
),
title: '创意无限',
desc: '突破传统制作限制,实现任何想象中的视觉效果',
gradient: 'from-purple-500 to-pink-500'
},
{
icon: (
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
title: '成本优化',
desc: '大幅降低视频制作成本,让高品质视频触手可及',
gradient: 'from-green-500 to-emerald-500'
}
].map((feature, index) => (
<ScrollReveal key={index} delay={index * 150}>
<div className="group glass-card rounded-2xl p-8 hover-lift relative overflow-hidden">
<div className={`absolute top-0 right-0 w-32 h-32 bg-gradient-to-br ${feature.gradient} opacity-10 rounded-full blur-3xl group-hover:opacity-20 transition-opacity`} />
<div className={`w-14 h-14 rounded-xl bg-gradient-to-br ${feature.gradient} flex items-center justify-center mb-5 text-white shadow-lg`}>
{feature.icon}
</div>
<h3 className="text-xl font-bold text-white mb-3">{feature.title}</h3>
<p className="text-gray-400 leading-relaxed">{feature.desc}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
{/* Service Scenes */}
<ServiceScenes />
{/* Process Animation */}
<ProcessAnimation />
{/* Featured Videos */}
<section className="py-20 px-4 bg-[#0d0d2b]/50 relative overflow-hidden">
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-purple-500/50 to-transparent" />
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-4">
<span className="gradient-text">AI创作</span>
</h2>
<p className="text-gray-400">
AI生成的精彩视频
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
{featuredVideos.map((video, index) => (
<ScrollReveal key={video.id} delay={index * 100}>
<VideoCard video={video} onClick={setSelectedVideo} />
</ScrollReveal>
))}
</div>
<ScrollReveal>
<div className="text-center">
<Link
to="/works"
className="group inline-flex items-center px-8 py-4 gradient-bg-animated rounded-2xl text-white font-bold hover:shadow-2xl hover:shadow-purple-500/25 transition-all duration-300"
>
<svg className="w-5 h-5 ml-2 transform group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</Link>
</div>
</ScrollReveal>
</div>
</section>
{/* Case Comparison */}
<CaseComparison />
{/* Testimonials */}
<section className="py-20 px-4">
<div className="max-w-7xl mx-auto">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h2 className="text-3xl md:text-4xl font-bold mb-4">
</h2>
<p className="text-gray-400">
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{testimonials.map((testimonial, index) => (
<ScrollReveal key={index} delay={index * 150}>
<TestimonialCard testimonial={testimonial} />
</ScrollReveal>
))}
</div>
</div>
</section>
{/* FAQ */}
<FAQ />
{/* CTA Section */}
<section className="py-24 px-4 relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-b from-purple-900/20 to-[#0a0a1a]" />
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px] bg-purple-500/10 rounded-full blur-[128px]" />
<div className="max-w-4xl mx-auto text-center relative z-10">
<ScrollReveal>
<h2 className="text-4xl md:text-5xl font-bold mb-6">
<span className="gradient-text">AI视频之旅</span>
</h2>
<p className="text-gray-400 text-lg mb-10 max-w-2xl mx-auto">
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
to="/contact"
className="px-10 py-5 gradient-bg-animated rounded-2xl text-white font-bold text-lg hover:shadow-2xl hover:shadow-purple-500/25 transition-all duration-300"
>
</Link>
<Link
to="/works"
className="px-10 py-5 border-2 border-purple-500/50 rounded-2xl text-purple-400 font-bold text-lg hover:border-purple-400 hover:bg-purple-500/10 transition-all duration-300"
>
</Link>
</div>
</ScrollReveal>
</div>
</section>
<VideoModal video={selectedVideo} onClose={() => setSelectedVideo(null)} />
</div>
)
}

91
src/pages/Works.tsx Normal file
View File

@@ -0,0 +1,91 @@
import { useState } from 'react'
import VideoCard from '../components/VideoCard'
import VideoModal from '../components/VideoModal'
import ScrollReveal from '../components/ScrollReveal'
import { videos, categories, Video } from '../data/videos'
export default function Works() {
const [selectedVideo, setSelectedVideo] = useState<Video | null>(null)
const [activeCategory, setActiveCategory] = useState('全部')
const filteredVideos = activeCategory === '全部'
? videos
: videos.filter(v => v.category === activeCategory)
return (
<div className="pt-20">
{/* Hero */}
<section className="py-20 px-4 relative overflow-hidden">
<div className="absolute inset-0">
<div className="absolute top-1/3 left-1/4 w-96 h-96 bg-purple-600/10 rounded-full blur-[128px]" />
<div className="absolute bottom-1/3 right-1/4 w-96 h-96 bg-blue-600/10 rounded-full blur-[128px]" />
</div>
<div className="max-w-7xl mx-auto relative z-10">
<ScrollReveal>
<div className="text-center mb-16">
<div className="inline-flex items-center px-4 py-2 rounded-full glass-card mb-4">
<span className="text-purple-400 text-sm font-medium"></span>
</div>
<h1 className="text-4xl md:text-5xl font-bold mb-4">
<span className="gradient-text"></span>
</h1>
<p className="text-lg text-gray-400 max-w-2xl mx-auto">
AI技术创作的精彩短视频作品
</p>
</div>
</ScrollReveal>
{/* Category Filter */}
<ScrollReveal delay={100}>
<div className="flex flex-wrap justify-center gap-3 mb-12">
{categories.map((category) => (
<button
key={category}
onClick={() => setActiveCategory(category)}
className={`px-5 py-2.5 rounded-xl font-medium transition-all duration-300 ${
activeCategory === category
? 'gradient-bg-animated text-white'
: 'glass-card text-gray-400 hover:text-white'
}`}
>
{category}
</button>
))}
</div>
</ScrollReveal>
{/* Video Count */}
<div className="text-center mb-8">
<p className="text-gray-500 text-sm">
<span className="text-purple-400 font-semibold">{filteredVideos.length}</span>
</p>
</div>
{/* Video Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredVideos.map((video, index) => (
<ScrollReveal key={video.id} delay={index * 50}>
<VideoCard video={video} onClick={setSelectedVideo} />
</ScrollReveal>
))}
</div>
{filteredVideos.length === 0 && (
<div className="text-center py-20">
<div className="w-20 h-20 mx-auto mb-4 rounded-full glass-card flex items-center justify-center">
<svg className="w-10 h-10 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 4v16M17 4v16M3 8h4m10 0h4M3 12h18M3 16h4m10 0h4M4 20h16a1 1 0 001-1V5a1 1 0 00-1-1H4a1 1 0 00-1 1v14a1 1 0 001 1z" />
</svg>
</div>
<p className="text-gray-400 text-lg mb-2"></p>
<p className="text-gray-500 text-sm"></p>
</div>
)}
</div>
</section>
<VideoModal video={selectedVideo} onClose={() => setSelectedVideo(null)} />
</div>
)
}