first commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
17402
package-lock.json
generated
Normal file
17402
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
package.json
Normal file
35
package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "ai-company-website",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"framer-motion": "^10.16.4",
|
||||
"react-scripts": "5.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
35
public/index.html
Normal file
35
public/index.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="AI公司官网 - 创新科技,引领未来" />
|
||||
<title>Radiant AI - 创新科技,引领未来</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||
overflow-x: hidden;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>您需要启用JavaScript来运行此应用程序。</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
1468
src/App.css
Normal file
1468
src/App.css
Normal file
File diff suppressed because it is too large
Load Diff
171
src/App.js
Normal file
171
src/App.js
Normal file
@@ -0,0 +1,171 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { motion, useScroll, useTransform, AnimatePresence } from 'framer-motion';
|
||||
import Navigation from './components/Navigation';
|
||||
import HeroSection from './components/HeroSection';
|
||||
import ProductSection from './components/ProductSection';
|
||||
import TeamSection from './components/TeamSection';
|
||||
import CaseSection from './components/CaseSection';
|
||||
import ContactSection from './components/ContactSection';
|
||||
import './App.css';
|
||||
|
||||
const App = () => {
|
||||
const containerRef = useRef(null);
|
||||
const [currentSection, setCurrentSection] = useState(0);
|
||||
const [isScrolling, setIsScrolling] = useState(false);
|
||||
const isScrollingRef = useRef(false);
|
||||
const currentSectionRef = useRef(0);
|
||||
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: containerRef,
|
||||
offset: ["start start", "end start"]
|
||||
});
|
||||
|
||||
const sections = [
|
||||
{ id: 'hero', component: HeroSection, title: '发现新视界', subtitle: 'Discover New Horizons' },
|
||||
{ id: 'product', component: ProductSection, title: 'AI产品', subtitle: 'Innovative Solutions' },
|
||||
{ id: 'team', component: TeamSection, title: '专业团队', subtitle: 'Expert Team' },
|
||||
{ id: 'cases', component: CaseSection, title: '成功案例', subtitle: 'Success Stories' },
|
||||
{ id: 'contact', component: ContactSection, title: '联系我们', subtitle: 'Get In Touch' }
|
||||
];
|
||||
|
||||
// 同步 ref 值
|
||||
useEffect(() => {
|
||||
isScrollingRef.current = isScrolling;
|
||||
currentSectionRef.current = currentSection;
|
||||
}, [isScrolling, currentSection]);
|
||||
|
||||
useEffect(() => {
|
||||
let timeout;
|
||||
|
||||
const handleWheel = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// 如果正在滚动中,忽略新的滚动事件
|
||||
if (isScrollingRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置滚动状态
|
||||
isScrollingRef.current = true;
|
||||
setIsScrolling(true);
|
||||
|
||||
// 计算新的section索引
|
||||
let newSection = currentSectionRef.current;
|
||||
if (e.deltaY > 0 && currentSectionRef.current < sections.length - 1) {
|
||||
newSection = currentSectionRef.current + 1;
|
||||
} else if (e.deltaY < 0 && currentSectionRef.current > 0) {
|
||||
newSection = currentSectionRef.current - 1;
|
||||
}
|
||||
|
||||
// 如果section有变化,更新状态
|
||||
if (newSection !== currentSectionRef.current) {
|
||||
setCurrentSection(newSection);
|
||||
}
|
||||
|
||||
// 清除之前的超时
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
// 设置超时来重置滚动状态
|
||||
timeout = setTimeout(() => {
|
||||
isScrollingRef.current = false;
|
||||
setIsScrolling(false);
|
||||
}, 1200); // 增加到1.2秒,与动画时间匹配
|
||||
};
|
||||
|
||||
const container = containerRef.current;
|
||||
if (container) {
|
||||
container.addEventListener('wheel', handleWheel, { passive: false });
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (container) {
|
||||
container.removeEventListener('wheel', handleWheel);
|
||||
}
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
};
|
||||
}, [sections.length]);
|
||||
|
||||
const backgroundOpacity = useTransform(scrollYProgress, [0, 1], [1, 0.3]);
|
||||
const scale = useTransform(scrollYProgress, [0, 1], [1, 1.2]);
|
||||
|
||||
return (
|
||||
<div className="app" ref={containerRef}>
|
||||
<Navigation
|
||||
currentSection={currentSection}
|
||||
sections={sections}
|
||||
onSectionChange={setCurrentSection}
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
className="background-gradient"
|
||||
style={{ opacity: backgroundOpacity, scale }}
|
||||
/>
|
||||
|
||||
<div className="sections-container">
|
||||
<AnimatePresence mode="wait">
|
||||
{sections.map((section, index) => {
|
||||
const Component = section.component;
|
||||
const isActive = index === currentSection;
|
||||
|
||||
return isActive ? (
|
||||
<motion.div
|
||||
key={section.id}
|
||||
className="section"
|
||||
initial={{ opacity: 0, scale: 0.8, rotateX: 15 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
rotateX: 0,
|
||||
transition: {
|
||||
duration: 1.2,
|
||||
ease: [0.25, 0.1, 0.25, 1],
|
||||
staggerChildren: 0.1
|
||||
}
|
||||
}}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
scale: 1.1,
|
||||
rotateX: -15,
|
||||
transition: { duration: 0.8 }
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="section-title"
|
||||
initial={{ y: 100, opacity: 0 }}
|
||||
animate={{
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { delay: 0.3, duration: 0.8 }
|
||||
}}
|
||||
>
|
||||
<h1>{section.title}</h1>
|
||||
<span className="subtitle">{section.subtitle}</span>
|
||||
</motion.div>
|
||||
|
||||
<Component sectionIndex={index} isActive={isActive} />
|
||||
</motion.div>
|
||||
) : null;
|
||||
})}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className="section-indicators">
|
||||
{sections.map((_, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className={`indicator ${index === currentSection ? 'active' : ''}`}
|
||||
onClick={() => setCurrentSection(index)}
|
||||
whileHover={{ scale: 1.2 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
140
src/components/CaseSection.js
Normal file
140
src/components/CaseSection.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import React, { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
const CaseSection = ({ isActive }) => {
|
||||
const [selectedCase, setSelectedCase] = useState(0);
|
||||
|
||||
const cases = [
|
||||
{
|
||||
id: 1,
|
||||
title: '智能金融风控系统',
|
||||
client: '某大型银行',
|
||||
category: '金融科技',
|
||||
description: '基于机器学习的实时风险评估系统,将欺诈检测准确率提升至99.8%',
|
||||
results: ['风险识别提升85%', '处理速度提高300%', '年节省成本2000万'],
|
||||
image: '🏦',
|
||||
technologies: ['深度学习', '实时计算', '大数据分析']
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '智能医疗诊断助手',
|
||||
client: '顶级三甲医院',
|
||||
category: '医疗健康',
|
||||
description: 'AI辅助医生进行疾病诊断,显著提高诊断效率和准确性',
|
||||
results: ['诊断准确率提升20%', '诊疗时间缩短40%', '患者满意度95%'],
|
||||
image: '🏥',
|
||||
technologies: ['计算机视觉', '自然语言处理', '知识图谱']
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '智能制造优化平台',
|
||||
client: '制造业龙头企业',
|
||||
category: '工业4.0',
|
||||
description: '通过AI优化生产流程,实现智能化生产管理和质量控制',
|
||||
results: ['生产效率提升45%', '次品率降低90%', 'ROI达到280%'],
|
||||
image: '🏭',
|
||||
technologies: ['预测性维护', 'IoT集成', '优化算法']
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="case-section">
|
||||
<motion.div
|
||||
className="case-header"
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
>
|
||||
<h2>成功案例</h2>
|
||||
<p>见证AI技术如何转化为实际商业价值</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="case-container">
|
||||
<motion.div
|
||||
className="case-navigation"
|
||||
initial={{ opacity: 0, x: -50 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.4 }}
|
||||
>
|
||||
{cases.map((caseItem, index) => (
|
||||
<motion.div
|
||||
key={caseItem.id}
|
||||
className={`case-nav-item ${index === selectedCase ? 'active' : ''}`}
|
||||
onClick={() => setSelectedCase(index)}
|
||||
whileHover={{ scale: 1.02, x: 10 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<div className="nav-icon">{caseItem.image}</div>
|
||||
<div className="nav-content">
|
||||
<h4>{caseItem.title}</h4>
|
||||
<span className="nav-category">{caseItem.category}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="case-details"
|
||||
initial={{ opacity: 0, x: 50 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={selectedCase}
|
||||
className="case-content"
|
||||
initial={{ opacity: 0, y: 30, scale: 0.95 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: -30, scale: 1.05 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="case-meta">
|
||||
<span className="case-category">{cases[selectedCase].category}</span>
|
||||
<span className="case-client">{cases[selectedCase].client}</span>
|
||||
</div>
|
||||
|
||||
<h3 className="case-title">{cases[selectedCase].title}</h3>
|
||||
<p className="case-description">{cases[selectedCase].description}</p>
|
||||
|
||||
<div className="case-technologies">
|
||||
<h4>核心技术</h4>
|
||||
<div className="tech-tags">
|
||||
{cases[selectedCase].technologies.map((tech, idx) => (
|
||||
<span key={idx} className="tech-tag">{tech}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="case-results">
|
||||
<h4>项目成果</h4>
|
||||
<div className="results-grid">
|
||||
{cases[selectedCase].results.map((result, idx) => (
|
||||
<motion.div
|
||||
key={idx}
|
||||
className="result-item"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: idx * 0.1 }}
|
||||
>
|
||||
✓ {result}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.button
|
||||
className="case-cta"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
查看详细案例
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CaseSection;
|
||||
168
src/components/ContactSection.js
Normal file
168
src/components/ContactSection.js
Normal file
@@ -0,0 +1,168 @@
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const ContactSection = ({ isActive }) => {
|
||||
const contactMethods = [
|
||||
{
|
||||
icon: '📧',
|
||||
title: '邮件联系',
|
||||
content: 'contact@radiant-ai.com',
|
||||
description: '7x24小时响应您的咨询'
|
||||
},
|
||||
{
|
||||
icon: '📞',
|
||||
title: '电话咨询',
|
||||
content: '+86 400-888-9999',
|
||||
description: '专业顾问为您答疑解惑'
|
||||
},
|
||||
{
|
||||
icon: '📍',
|
||||
title: '公司地址',
|
||||
content: '北京市朝阳区',
|
||||
description: '欢迎莅临参观交流'
|
||||
}
|
||||
];
|
||||
|
||||
const formVariants = {
|
||||
hidden: { opacity: 0, x: 50 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: {
|
||||
duration: 0.8,
|
||||
staggerChildren: 0.1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fieldVariants = {
|
||||
hidden: { opacity: 0, y: 30 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.6 }
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="contact-section">
|
||||
<motion.div
|
||||
className="contact-header"
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
>
|
||||
<h2>联系我们</h2>
|
||||
<p>让我们一起探索AI的无限可能</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="contact-container">
|
||||
<motion.div
|
||||
className="contact-info"
|
||||
initial={{ opacity: 0, x: -50 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.4 }}
|
||||
>
|
||||
<div className="contact-methods">
|
||||
{contactMethods.map((method, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className="contact-method"
|
||||
whileHover={{ scale: 1.05, y: -5 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<div className="method-icon">{method.icon}</div>
|
||||
<div className="method-content">
|
||||
<h4>{method.title}</h4>
|
||||
<div className="method-value">{method.content}</div>
|
||||
<p className="method-description">{method.description}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="contact-social"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.8 }}
|
||||
>
|
||||
<h4>关注我们</h4>
|
||||
<div className="social-links">
|
||||
{['微信', '微博', 'LinkedIn', 'GitHub'].map((platform, idx) => (
|
||||
<motion.div
|
||||
key={idx}
|
||||
className="social-link"
|
||||
whileHover={{ scale: 1.2, rotate: 5 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
>
|
||||
{platform}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="contact-form"
|
||||
variants={formVariants}
|
||||
initial="hidden"
|
||||
animate={isActive ? "visible" : "hidden"}
|
||||
>
|
||||
<motion.form variants={formVariants}>
|
||||
<motion.div className="form-group" variants={fieldVariants}>
|
||||
<label>姓名</label>
|
||||
<input type="text" placeholder="请输入您的姓名" />
|
||||
</motion.div>
|
||||
|
||||
<motion.div className="form-group" variants={fieldVariants}>
|
||||
<label>公司</label>
|
||||
<input type="text" placeholder="请输入公司名称" />
|
||||
</motion.div>
|
||||
|
||||
<motion.div className="form-group" variants={fieldVariants}>
|
||||
<label>邮箱</label>
|
||||
<input type="email" placeholder="请输入邮箱地址" />
|
||||
</motion.div>
|
||||
|
||||
<motion.div className="form-group" variants={fieldVariants}>
|
||||
<label>需求类型</label>
|
||||
<select>
|
||||
<option>产品咨询</option>
|
||||
<option>技术合作</option>
|
||||
<option>商务合作</option>
|
||||
<option>其他</option>
|
||||
</select>
|
||||
</motion.div>
|
||||
|
||||
<motion.div className="form-group" variants={fieldVariants}>
|
||||
<label>详细需求</label>
|
||||
<textarea placeholder="请详细描述您的需求和期望..."></textarea>
|
||||
</motion.div>
|
||||
|
||||
<motion.button
|
||||
type="submit"
|
||||
className="form-submit"
|
||||
variants={fieldVariants}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
提交咨询
|
||||
</motion.button>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="contact-footer"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isActive ? { opacity: 1 } : {}}
|
||||
transition={{ duration: 1, delay: 1.2 }}
|
||||
>
|
||||
<p>© 2024 Radiant AI. 创新科技,引领未来。</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactSection;
|
||||
124
src/components/HeroSection.js
Normal file
124
src/components/HeroSection.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const HeroSection = ({ isActive }) => {
|
||||
return (
|
||||
<div className="hero-section-minimal">
|
||||
{/* 左侧主要内容 */}
|
||||
<motion.div
|
||||
className="hero-left"
|
||||
initial={{ opacity: 0, x: -60 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 1.2, delay: 0.3 }}
|
||||
>
|
||||
<motion.h1
|
||||
className="hero-main-title"
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
>
|
||||
推动变革
|
||||
</motion.h1>
|
||||
|
||||
<motion.h2
|
||||
className="hero-subtitle"
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.8 }}
|
||||
>
|
||||
<span className="highlight-text">通过</span> 创新的
|
||||
<br />
|
||||
人工智能技术
|
||||
</motion.h2>
|
||||
|
||||
<motion.div
|
||||
className="hero-quote"
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 1.2 }}
|
||||
>
|
||||
<div className="quote-line"></div>
|
||||
<p>
|
||||
通过利用战略洞察和行业网络,
|
||||
<br />
|
||||
Radiant 作为增长催化剂,为我们的
|
||||
<br />
|
||||
投资组合公司和投资者创造卓越价值。
|
||||
</p>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* 右侧几何形状 */}
|
||||
<motion.div
|
||||
className="hero-right"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={isActive ? { opacity: 1, scale: 1 } : {}}
|
||||
transition={{ duration: 1.5, delay: 0.5 }}
|
||||
>
|
||||
<div className="geometric-container">
|
||||
<motion.div
|
||||
className="cube-main"
|
||||
initial={{ rotateY: 0, rotateX: 0 }}
|
||||
animate={isActive ? {
|
||||
rotateY: [0, 15, 0],
|
||||
rotateX: [0, -10, 0]
|
||||
} : {}}
|
||||
transition={{
|
||||
duration: 8,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
>
|
||||
<div className="cube-face front"></div>
|
||||
<div className="cube-face back"></div>
|
||||
<div className="cube-face right"></div>
|
||||
<div className="cube-face left"></div>
|
||||
<div className="cube-face top"></div>
|
||||
<div className="cube-face bottom"></div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="cube-small"
|
||||
initial={{ rotateY: 0 }}
|
||||
animate={isActive ? { rotateY: 360 } : {}}
|
||||
transition={{
|
||||
duration: 12,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
>
|
||||
<div className="cube-face front"></div>
|
||||
<div className="cube-face back"></div>
|
||||
<div className="cube-face right"></div>
|
||||
<div className="cube-face left"></div>
|
||||
<div className="cube-face top"></div>
|
||||
<div className="cube-face bottom"></div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* 底部进度指示器 */}
|
||||
<motion.div
|
||||
className="hero-progress"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 1.5 }}
|
||||
>
|
||||
<div className="progress-bar">
|
||||
<motion.div
|
||||
className="progress-fill"
|
||||
initial={{ width: "0%" }}
|
||||
animate={isActive ? { width: "23%" } : {}}
|
||||
transition={{ duration: 2, delay: 2 }}
|
||||
></motion.div>
|
||||
</div>
|
||||
<div className="progress-info">
|
||||
<span className="progress-time">00:04</span>
|
||||
<span className="progress-total">00:18</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSection;
|
||||
148
src/components/Navigation.js
Normal file
148
src/components/Navigation.js
Normal file
@@ -0,0 +1,148 @@
|
||||
import React, { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
const Navigation = ({ currentSection, sections, onSectionChange }) => {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
|
||||
const menuItems = [
|
||||
{ name: '发现', engName: 'Discover', sectionIndex: 0 },
|
||||
{ name: '产品', engName: 'Products', sectionIndex: 1 },
|
||||
{ name: '团队', engName: 'Team', sectionIndex: 2 },
|
||||
{ name: '案例', engName: 'Cases', sectionIndex: 3 },
|
||||
{ name: '联系', engName: 'Contact', sectionIndex: 4 }
|
||||
];
|
||||
|
||||
const handleItemClick = (sectionIndex) => {
|
||||
onSectionChange(sectionIndex);
|
||||
setIsMobileMenuOpen(false);
|
||||
};
|
||||
|
||||
const toggleMobileMenu = () => {
|
||||
setIsMobileMenuOpen(!isMobileMenuOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<motion.nav
|
||||
className="navigation-glass"
|
||||
initial={{ y: -50, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
>
|
||||
{/* Logo */}
|
||||
<motion.div
|
||||
className="logo-glass"
|
||||
whileHover={{
|
||||
scale: 1.02,
|
||||
y: -1
|
||||
}}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => handleItemClick(0)}
|
||||
>
|
||||
<motion.div
|
||||
className="logo-icon-glass"
|
||||
whileHover={{
|
||||
rotate: [0, -5, 5, 0],
|
||||
scale: 1.1
|
||||
}}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
Q
|
||||
</motion.div>
|
||||
<motion.span
|
||||
className="logo-text"
|
||||
>
|
||||
Quant Speed
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
|
||||
{/* 桌面端菜单 */}
|
||||
<div className="nav-menu-glass">
|
||||
{menuItems.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className={`nav-item-glass ${currentSection === item.sectionIndex ? 'active' : ''}`}
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
y: -2
|
||||
}}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
onClick={() => handleItemClick(item.sectionIndex)}
|
||||
>
|
||||
<span className="nav-item-main">{item.name}</span>
|
||||
<span className="nav-item-sub">{item.engName}</span>
|
||||
{currentSection === item.sectionIndex && (
|
||||
<motion.div
|
||||
className="nav-item-indicator"
|
||||
layoutId="activeIndicator"
|
||||
initial={false}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||
/>
|
||||
)}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 移动端汉堡菜单按钮 */}
|
||||
<motion.div
|
||||
className={`hamburger-glass ${isMobileMenuOpen ? 'active' : ''}`}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
onClick={toggleMobileMenu}
|
||||
>
|
||||
<motion.div
|
||||
className="hamburger-line"
|
||||
animate={isMobileMenuOpen ? { rotate: 45, y: 6 } : { rotate: 0, y: 0 }}
|
||||
/>
|
||||
<motion.div
|
||||
className="hamburger-line"
|
||||
animate={isMobileMenuOpen ? { opacity: 0 } : { opacity: 1 }}
|
||||
/>
|
||||
<motion.div
|
||||
className="hamburger-line"
|
||||
animate={isMobileMenuOpen ? { rotate: -45, y: -6 } : { rotate: 0, y: 0 }}
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.nav>
|
||||
|
||||
{/* 移动端菜单 */}
|
||||
<AnimatePresence>
|
||||
{isMobileMenuOpen && (
|
||||
<motion.div
|
||||
className="mobile-menu-glass"
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<motion.div
|
||||
className="mobile-menu-content"
|
||||
initial={{ scale: 0.95 }}
|
||||
animate={{ scale: 1 }}
|
||||
exit={{ scale: 0.95 }}
|
||||
>
|
||||
{menuItems.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className={`mobile-nav-item ${currentSection === item.sectionIndex ? 'active' : ''}`}
|
||||
whileHover={{ x: 10 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={() => handleItemClick(item.sectionIndex)}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
>
|
||||
<span className="mobile-nav-main">{item.name}</span>
|
||||
<span className="mobile-nav-sub">{item.engName}</span>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
101
src/components/ProductSection.js
Normal file
101
src/components/ProductSection.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const ProductSection = ({ isActive }) => {
|
||||
return (
|
||||
<div className="product-section-minimal">
|
||||
<motion.div
|
||||
className="product-content"
|
||||
initial={{ opacity: 0, y: 60 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 1.2, delay: 0.3 }}
|
||||
>
|
||||
<motion.h1
|
||||
className="product-main-title"
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
>
|
||||
我们的战略
|
||||
<br />
|
||||
<span className="highlight-text">针对</span>
|
||||
<br />
|
||||
远见项目
|
||||
</motion.h1>
|
||||
|
||||
<motion.div
|
||||
className="product-quote"
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 1 }}
|
||||
>
|
||||
<div className="quote-line"></div>
|
||||
<p>
|
||||
Radiant的战略投资框架旨在
|
||||
<br />
|
||||
赋能创业者。我们专注于与创始人
|
||||
<br />
|
||||
建立持久关系,推动有意义的变革。
|
||||
</p>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="product-visual"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={isActive ? { opacity: 1, scale: 1 } : {}}
|
||||
transition={{ duration: 1.5, delay: 0.5 }}
|
||||
>
|
||||
<div className="visual-container">
|
||||
<motion.div
|
||||
className="visual-element-1"
|
||||
animate={isActive ? {
|
||||
rotateY: [0, 360],
|
||||
scale: [1, 1.1, 1]
|
||||
} : {}}
|
||||
transition={{
|
||||
duration: 20,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="visual-element-2"
|
||||
animate={isActive ? {
|
||||
rotateX: [0, 360],
|
||||
y: [0, -20, 0]
|
||||
} : {}}
|
||||
transition={{
|
||||
duration: 15,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* 进度指示器 */}
|
||||
<motion.div
|
||||
className="product-progress"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 1.5 }}
|
||||
>
|
||||
<div className="progress-bar">
|
||||
<motion.div
|
||||
className="progress-fill"
|
||||
initial={{ width: "0%" }}
|
||||
animate={isActive ? { width: "44%" } : {}}
|
||||
transition={{ duration: 2, delay: 2 }}
|
||||
></motion.div>
|
||||
</div>
|
||||
<div className="progress-info">
|
||||
<span className="progress-time">00:08</span>
|
||||
<span className="progress-total">00:18</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductSection;
|
||||
101
src/components/TeamSection.js
Normal file
101
src/components/TeamSection.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const TeamSection = ({ isActive }) => {
|
||||
return (
|
||||
<div className="team-section-minimal">
|
||||
<motion.div
|
||||
className="team-content"
|
||||
initial={{ opacity: 0, y: 60 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 1.2, delay: 0.3 }}
|
||||
>
|
||||
<motion.h1
|
||||
className="team-main-title"
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
>
|
||||
团队专业
|
||||
<br />
|
||||
<span className="highlight-text">知识</span>
|
||||
<br />
|
||||
与经验
|
||||
</motion.h1>
|
||||
|
||||
<motion.div
|
||||
className="team-quote"
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={isActive ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 1 }}
|
||||
>
|
||||
<div className="quote-line"></div>
|
||||
<p>
|
||||
我们的团队汇聚了行业顶尖人才,
|
||||
<br />
|
||||
拥有深厚的技术背景和丰富的
|
||||
<br />
|
||||
创新经验,致力于推动AI技术发展。
|
||||
</p>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="team-visual"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={isActive ? { opacity: 1, scale: 1 } : {}}
|
||||
transition={{ duration: 1.5, delay: 0.5 }}
|
||||
>
|
||||
<div className="team-visual-container">
|
||||
<motion.div
|
||||
className="team-visual-element-1"
|
||||
animate={isActive ? {
|
||||
rotateZ: [0, 180, 360],
|
||||
scale: [1, 1.2, 1]
|
||||
} : {}}
|
||||
transition={{
|
||||
duration: 18,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="team-visual-element-2"
|
||||
animate={isActive ? {
|
||||
rotateY: [0, 180, 360],
|
||||
x: [0, 20, 0]
|
||||
} : {}}
|
||||
transition={{
|
||||
duration: 12,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* 进度指示器 */}
|
||||
<motion.div
|
||||
className="team-progress"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isActive ? { opacity: 1, y: 0 } : {}}
|
||||
transition={{ duration: 0.8, delay: 1.5 }}
|
||||
>
|
||||
<div className="progress-bar">
|
||||
<motion.div
|
||||
className="progress-fill"
|
||||
initial={{ width: "0%" }}
|
||||
animate={isActive ? { width: "67%" } : {}}
|
||||
transition={{ duration: 2, delay: 2 }}
|
||||
></motion.div>
|
||||
</div>
|
||||
<div className="progress-info">
|
||||
<span className="progress-time">00:12</span>
|
||||
<span className="progress-total">00:18</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeamSection;
|
||||
10
src/index.js
Normal file
10
src/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
Reference in New Issue
Block a user