feat: 初始化多Agent协作系统项目并添加直播回放功能

- 添加导航栏组件及直播回放按钮
- 实现视频播放模态框
- 配置赛博朋克风格主题
- 添加课程首页和课程页面

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
KQL
2025-11-03 14:36:16 +08:00
commit cc390fc756
107 changed files with 31444 additions and 0 deletions

32
src/App.tsx Normal file
View File

@@ -0,0 +1,32 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navigation from './components/Navigation';
import ScrollToTop from './components/ScrollToTop';
import CyberpunkBackground from './components/CyberpunkBackground';
import CyberpunkVignette from './components/CyberpunkVignette';
import HomePage from './pages/HomePage';
import CoursePage from './pages/CoursePage';
const App: React.FC = () => {
return (
<Router>
<ScrollToTop />
<div className="min-h-screen relative">
<CyberpunkBackground />
<CyberpunkVignette
intensity="strong"
variant="neon"
/>
<Navigation />
<div className="container mx-auto px-4 pt-20 relative z-10">
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/course" element={<CoursePage />} />
</Routes>
</div>
</div>
</Router>
);
};
export default App;

43
src/AppOptimized.tsx Normal file
View File

@@ -0,0 +1,43 @@
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navigation from './components/Navigation';
import ScrollToTop from './components/ScrollToTop';
import CyberpunkBackgroundOptimized from './components/CyberpunkBackgroundOptimized';
import CyberpunkVignette from './components/CyberpunkVignette';
// 懒加载页面组件
const HomePage = lazy(() => import('./pages/HomePage'));
// 加载指示器组件
const LoadingFallback: React.FC = () => (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<div className="inline-flex items-center space-x-2">
<div className="w-8 h-8 border-4 border-cyber-pink-500 border-t-transparent rounded-full animate-spin"></div>
<span className="text-cyber-pink-400 font-medium">...</span>
</div>
</div>
</div>
);
const AppOptimized: React.FC = () => {
return (
<Router>
<ScrollToTop />
<div className="min-h-screen relative">
<CyberpunkBackgroundOptimized />
<CyberpunkVignette intensity="light" variant="minimal" />
<Navigation />
<div className="container mx-auto px-4 pt-20 relative z-10">
<Suspense fallback={<LoadingFallback />}>
<Routes>
<Route path="/" element={<HomePage />} />
</Routes>
</Suspense>
</div>
</div>
</Router>
);
};
export default AppOptimized;

View File

@@ -0,0 +1,359 @@
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
// 网络节点组件 - 代表Agent
const NetworkNode: React.FC<{
id: number;
onConnect: (id: number) => void;
connections: number[];
}> = ({ id, onConnect, connections }) => {
const [position] = useState({
x: Math.random() * 90 + 5,
y: Math.random() * 90 + 5,
size: Math.random() * 8 + 4,
});
const [isActive, setIsActive] = useState(false);
useEffect(() => {
const interval = setInterval(() => {
if (Math.random() < 0.3) {
setIsActive(true);
onConnect(id);
setTimeout(() => setIsActive(false), 2000);
}
}, Math.random() * 8000 + 5000);
return () => clearInterval(interval);
}, [id, onConnect]);
return (
<motion.div
className="absolute"
style={{
left: `${position.x}%`,
top: `${position.y}%`,
width: `${position.size}px`,
height: `${position.size}px`,
}}
initial={{ opacity: 0, scale: 0 }}
animate={{
opacity: isActive ? 0.9 : 0.4,
scale: isActive ? 1.5 : 1,
}}
transition={{
duration: 0.5,
opacity: { duration: 0.3 }
}}
>
{/* 节点核心 */}
<div
className={`w-full h-full rounded-full transition-all duration-500 ${
isActive
? 'bg-gradient-to-r from-cyber-pink-400 to-neon-purple-400 shadow-lg'
: 'bg-gradient-to-r from-cyber-pink-500/50 to-neon-purple-500/50'
}`}
style={{
boxShadow: isActive
? `0 0 ${position.size * 2}px rgba(6, 182, 212, 0.6), 0 0 ${position.size * 4}px rgba(16, 185, 129, 0.3)`
: `0 0 ${position.size}px rgba(6, 182, 212, 0.2)`
}}
/>
{/* 活跃时的脉冲效果 */}
{isActive && (
<motion.div
className="absolute inset-0 rounded-full border-2 border-neon-cyan-300"
initial={{ scale: 1, opacity: 0.6 }}
animate={{ scale: 3, opacity: 0 }}
transition={{ duration: 1.5, ease: "easeOut" }}
/>
)}
</motion.div>
);
};
// 数据流粒子组件
const DataParticle: React.FC<{ path: { start: {x: number, y: number}, end: {x: number, y: number} } }> = ({ path }) => {
const [isVisible, setIsVisible] = useState(true);
useEffect(() => {
const timer = setTimeout(() => setIsVisible(false), 3000);
return () => clearTimeout(timer);
}, []);
if (!isVisible) return null;
const distance = Math.sqrt(
Math.pow(path.end.x - path.start.x, 2) + Math.pow(path.end.y - path.start.y, 2)
);
return (
<motion.div
className="absolute w-2 h-2 bg-neon-purple-400 rounded-full"
style={{
left: `${path.start.x}%`,
top: `${path.start.y}%`,
boxShadow: '0 0 8px rgba(16, 185, 129, 0.8)'
}}
initial={{
x: 0,
y: 0,
opacity: 0,
scale: 0.5
}}
animate={{
x: `${(path.end.x - path.start.x) * (100/100)}%`,
y: `${(path.end.y - path.start.y) * (100/100)}%`,
opacity: [0, 1, 1, 0],
scale: [0.5, 1, 1, 0.5]
}}
transition={{
duration: Math.max(distance / 20, 2),
ease: "easeInOut"
}}
/>
);
};
// 连接线组件
const ConnectionLine: React.FC<{
start: {x: number, y: number};
end: {x: number, y: number};
isActive: boolean;
}> = ({ start, end, isActive }) => {
const length = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2));
const angle = Math.atan2(end.y - start.y, end.x - start.x) * 180 / Math.PI;
return (
<motion.div
className="absolute origin-left"
style={{
left: `${start.x}%`,
top: `${start.y}%`,
width: `${length}%`,
height: '1px',
transform: `rotate(${angle}deg)`,
background: isActive
? 'linear-gradient(90deg, rgba(6, 182, 212, 0.8), rgba(16, 185, 129, 0.8))'
: 'linear-gradient(90deg, rgba(6, 182, 212, 0.2), rgba(16, 185, 129, 0.2))',
boxShadow: isActive ? '0 0 4px rgba(6, 182, 212, 0.5)' : 'none'
}}
initial={{ scaleX: 0, opacity: 0 }}
animate={{
scaleX: 1,
opacity: isActive ? 0.8 : 0.3
}}
exit={{ scaleX: 0, opacity: 0 }}
transition={{ duration: 0.5 }}
/>
);
};
// 主背景组件
const AgentNetworkBackground: React.FC = () => {
const [activeConnections, setActiveConnections] = useState<{
start: {x: number, y: number};
end: {x: number, y: number};
id: string;
}[]>([]);
const [dataParticles, setDataParticles] = useState<{
path: { start: {x: number, y: number}, end: {x: number, y: number} };
id: string;
}[]>([]);
const nodePositions = React.useRef<{[key: number]: {x: number, y: number}}>({});
// 初始化节点位置
React.useEffect(() => {
for (let i = 0; i < 12; i++) {
nodePositions.current[i] = {
x: Math.random() * 90 + 5,
y: Math.random() * 90 + 5
};
}
}, []);
const handleNodeConnect = (nodeId: number) => {
// 随机选择其他节点连接
const otherNodes = Object.keys(nodePositions.current)
.map(Number)
.filter(id => id !== nodeId);
if (otherNodes.length === 0) return;
const targetId = otherNodes[Math.floor(Math.random() * otherNodes.length)];
const start = nodePositions.current[nodeId];
const end = nodePositions.current[targetId];
if (!start || !end) return;
const connectionId = `${nodeId}-${targetId}-${Date.now()}`;
// 添加连接线
const newConnection = { start, end, id: connectionId };
setActiveConnections(prev => [...prev, newConnection]);
// 添加数据粒子
const particleId = `particle-${Date.now()}`;
setDataParticles(prev => [...prev, { path: { start, end }, id: particleId }]);
// 清除连接线
setTimeout(() => {
setActiveConnections(prev => prev.filter(conn => conn.id !== connectionId));
}, 3000);
// 清除数据粒子
setTimeout(() => {
setDataParticles(prev => prev.filter(p => p.id !== particleId));
}, 3000);
};
return (
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
{/* 基础深色技术背景 */}
<div
className="absolute inset-0"
style={{
background: `
radial-gradient(circle at 25% 25%, rgba(15, 23, 42, 0.8) 0%, transparent 50%),
radial-gradient(circle at 75% 75%, rgba(8, 145, 178, 0.1) 0%, transparent 50%),
linear-gradient(135deg,
#0f172a 0%,
#1e293b 25%,
#0f172a 50%,
#164e63 75%,
#0f172a 100%
)
`
}}
/>
{/* 网格背景 - 体现技术感 */}
<div
className="absolute inset-0 opacity-[0.08]"
style={{
backgroundImage: `
linear-gradient(rgba(6, 182, 212, 0.3) 1px, transparent 1px),
linear-gradient(90deg, rgba(6, 182, 212, 0.3) 1px, transparent 1px)
`,
backgroundSize: '50px 50px'
}}
/>
{/* 动态光晕效果 */}
<motion.div
className="absolute inset-0"
style={{
background: `
radial-gradient(600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
rgba(6, 182, 212, 0.1) 0%,
rgba(16, 185, 129, 0.05) 40%,
transparent 100%
)
`
}}
animate={{
'--mouse-x': ['30%', '70%', '30%'],
'--mouse-y': ['40%', '60%', '40%']
} as any}
transition={{
duration: 20,
repeat: Infinity,
ease: "easeInOut"
}}
/>
{/* 数据流背景效果 */}
<motion.div
className="absolute inset-0"
style={{
background: `
linear-gradient(45deg,
transparent 0%,
rgba(6, 182, 212, 0.05) 25%,
transparent 50%,
rgba(16, 185, 129, 0.05) 75%,
transparent 100%
)
`,
transform: 'translateX(-100%)'
}}
animate={{
transform: ['translateX(-100%)', 'translateX(100%)']
}}
transition={{
duration: 15,
repeat: Infinity,
ease: "linear"
}}
/>
{/* 连接线层 */}
<div className="absolute inset-0">
<AnimatePresence>
{activeConnections.map(connection => (
<ConnectionLine
key={connection.id}
start={connection.start}
end={connection.end}
isActive={true}
/>
))}
</AnimatePresence>
</div>
{/* 网络节点 - Agent */}
<div className="absolute inset-0">
{Array.from({ length: 12 }, (_, i) => (
<NetworkNode
key={i}
id={i}
onConnect={handleNodeConnect}
connections={[]}
/>
))}
</div>
{/* 数据粒子层 */}
<div className="absolute inset-0">
<AnimatePresence>
{dataParticles.map(particle => (
<DataParticle
key={particle.id}
path={particle.path}
/>
))}
</AnimatePresence>
</div>
{/* 顶部渐变遮罩 - 确保文字可读性 */}
<div
className="absolute inset-0 pointer-events-none"
style={{
background: `
linear-gradient(180deg,
rgba(15, 23, 42, 0.3) 0%,
transparent 20%,
transparent 80%,
rgba(15, 23, 42, 0.2) 100%
)
`
}}
/>
{/* 性能优化 */}
<style>{`
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
`}</style>
</div>
);
};
export default AgentNetworkBackground;

View File

@@ -0,0 +1,64 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { ArrowLeft, ArrowRight } from './Icons';
import { getChapterNavigation } from '../utils/courseNavigation';
interface CourseNavigationProps {
className?: string;
}
const CourseNavigation: React.FC<CourseNavigationProps> = ({ className = '' }) => {
const location = useLocation();
const { prev, next } = getChapterNavigation(location.pathname);
return (
<div className={`flex justify-between items-center mt-12 ${className}`}>
{prev ? (
<Link
to={prev.path}
className="cyber-button flex items-center group"
>
<ArrowLeft className="w-5 h-5 mr-2 group-hover:-translate-x-1 transition-transform" />
<div className="text-left">
<div className="text-sm opacity-70"></div>
<div className="font-medium">{prev.title}</div>
</div>
</Link>
) : (
<Link
to="/"
className="cyber-button flex items-center group"
>
<ArrowLeft className="w-5 h-5 mr-2 group-hover:-translate-x-1 transition-transform" />
</Link>
)}
{next ? (
<Link
to={next.path}
className="cyber-button flex items-center group"
>
<div className="text-right">
<div className="text-sm opacity-70"></div>
<div className="font-medium">{next.title}</div>
</div>
<ArrowRight className="w-5 h-5 ml-2 group-hover:translate-x-1 transition-transform" />
</Link>
) : (
<Link
to="/course-summary"
className="cyber-button flex items-center group"
>
<div className="text-right">
<div className="text-sm opacity-70"></div>
<div className="font-medium"></div>
</div>
<ArrowRight className="w-5 h-5 ml-2 group-hover:translate-x-1 transition-transform" />
</Link>
)}
</div>
);
};
export default CourseNavigation;

View File

@@ -0,0 +1,294 @@
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
// 霓虹网格线
const NeonGrid: React.FC = () => {
return (
<div className="absolute inset-0 overflow-hidden">
<div
className="absolute inset-0"
style={{
backgroundImage: `
linear-gradient(rgba(244, 63, 94, 0.3) 1px, transparent 1px),
linear-gradient(90deg, rgba(6, 182, 212, 0.3) 1px, transparent 1px)
`,
backgroundSize: '50px 50px',
animation: 'grid-move 20s linear infinite',
transform: 'perspective(500px) rotateX(60deg) translateZ(0)',
transformOrigin: 'center center',
filter: 'brightness(1.5)',
mixBlendMode: 'screen',
}}
/>
</div>
);
};
// 日文字符数据雨效果
const DataRain: React.FC = () => {
const columns = 15; // 减少列数从30到15
const [charColumns, setCharColumns] = useState<Array<{ chars: string[]; delay: number; duration: number; x: number }>>([]);
// 日文字符集合(片假名、平假名和汉字)
const japaneseChars = [
'ア', 'イ', 'ウ', 'エ', 'オ', 'カ', 'キ', 'ク', 'ケ', 'コ',
'サ', 'シ', 'ス', 'セ', 'ソ', 'タ', 'チ', 'ツ', 'テ', 'ト',
'ナ', 'ニ', 'ヌ', 'ネ', '', 'ハ', 'ヒ', 'フ', 'ヘ', 'ホ',
'マ', 'ミ', 'ム', 'メ', 'モ', 'ヤ', 'ユ', 'ヨ', 'ラ', 'リ',
'ル', 'レ', 'ロ', 'ワ', 'ヲ', 'ン', '日', '本', '語', '愛',
'雨', '桜', '心', '風', '光', '影', '夢', '星', '月', '雲',
'龍', '侍', '忍', '者', '武', '士', '道', '禅', '気', '力',
'火', '水', '土', '空', '時', '無', '有', '生', '死', '闇',
];
useEffect(() => {
// 初始化列
const drops = Array.from({ length: columns }, (_, i) => ({
chars: Array.from({ length: 15 }, () => // 改为15个字符
japaneseChars[Math.floor(Math.random() * japaneseChars.length)]
),
delay: Math.random() * 5,
duration: 12 + Math.random() * 6,
x: (i / columns) * 100,
}));
setCharColumns(drops);
// 定期更新字符 - 加快更新频率
const interval = setInterval(() => {
setCharColumns(prev => prev.map(column => ({
...column,
chars: column.chars.map(char =>
Math.random() < 0.1 ? japaneseChars[Math.floor(Math.random() * japaneseChars.length)] : char // 从0.02增加到0.1
)
})));
}, 50); // 从100ms减少到50ms
return () => clearInterval(interval);
}, []);
return (
<div className="absolute inset-0 overflow-hidden opacity-60">
{charColumns.map((column, i) => (
<motion.div
key={i}
className="absolute flex flex-col text-green-400"
style={{
left: `${column.x}%`,
fontSize: '12px', // 从18px减小到12px
fontFamily: "'Courier New', monospace",
fontWeight: 'normal', // 从bold改为normal
lineHeight: '1',
letterSpacing: '0px',
}}
initial={{ y: -50 }} // 从更接近顶部的位置开始
animate={{ y: window.innerHeight + 100 }}
transition={{
duration: column.duration,
repeat: Infinity,
delay: column.delay,
ease: "linear",
}}
>
{column.chars.map((char, idx) => (
<div
key={idx}
style={{
opacity: idx === 0 ? 1 : Math.max(0.05, 1 - (idx / column.chars.length) * 0.95),
color: idx === 0 ? '#ffffff' : idx < 2 ? '#66ff66' : '#00ff00',
textShadow: idx === 0
? '0 0 8px #ffffff, 0 0 15px #00ff00'
: idx < 2
? '0 0 3px rgba(102, 255, 102, 0.8)'
: '0 0 2px rgba(0, 255, 0, 0.3)',
height: '14px', // 从20px减小到14px
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{char}
</div>
))}
</motion.div>
))}
</div>
);
};
// 霓虹光束
const NeonBeams: React.FC = () => {
return (
<div className="absolute inset-0 overflow-hidden">
{[...Array(5)].map((_, i) => (
<motion.div
key={i}
className="absolute h-px"
style={{
background: `linear-gradient(90deg,
transparent,
${i % 2 === 0 ? '#f43f5e' : '#06b6d4'},
transparent
)`,
width: '200%',
top: `${20 + i * 15}%`,
filter: `blur(${i === 0 ? 2 : 1}px)`,
boxShadow: `0 0 ${10 + i * 5}px ${i % 2 === 0 ? '#f43f5e' : '#06b6d4'}`,
}}
animate={{
x: ['-100%', '0%'],
}}
transition={{
duration: 10 + i * 2,
repeat: Infinity,
ease: "linear",
}}
/>
))}
</div>
);
};
// 故障效果
const GlitchOverlay: React.FC = () => {
const [isGlitching, setIsGlitching] = useState(false);
useEffect(() => {
const interval = setInterval(() => {
setIsGlitching(true);
setTimeout(() => setIsGlitching(false), 200);
}, 5000);
return () => clearInterval(interval);
}, []);
if (!isGlitching) return null;
return (
<motion.div
className="absolute inset-0 pointer-events-none"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
style={{
background: `repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(244, 63, 94, 0.03) 2px,
rgba(244, 63, 94, 0.03) 4px
)`,
animation: 'glitch 0.3s infinite',
}}
/>
);
};
// 粒子效果
const ParticleField: React.FC = () => {
const [particles, setParticles] = useState<Array<{ x: number; y: number; size: number; delay: number }>>([]);
useEffect(() => {
const newParticles = Array.from({ length: 50 }, () => ({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 3 + 1,
delay: Math.random() * 5,
}));
setParticles(newParticles);
}, []);
return (
<div className="absolute inset-0 overflow-hidden">
{particles.map((particle, i) => (
<motion.div
key={i}
className="absolute rounded-full"
style={{
left: `${particle.x}%`,
top: `${particle.y}%`,
width: particle.size,
height: particle.size,
background: i % 3 === 0 ? '#f43f5e' : i % 3 === 1 ? '#a855f7' : '#06b6d4',
boxShadow: `0 0 ${particle.size * 2}px currentColor`,
}}
animate={{
y: [0, -30, 0],
opacity: [0.2, 1, 0.2],
}}
transition={{
duration: 3 + particle.size,
repeat: Infinity,
delay: particle.delay,
}}
/>
))}
</div>
);
};
// 主背景组件 - 原始版本
const CyberpunkBackground: React.FC = () => {
return (
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
{/* 基础渐变背景 */}
<div
className="absolute inset-0"
style={{
background: `
radial-gradient(circle at 20% 50%, rgba(244, 63, 94, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 50%, rgba(168, 85, 247, 0.1) 0%, transparent 50%),
radial-gradient(circle at 50% 100%, rgba(6, 182, 212, 0.1) 0%, transparent 50%),
linear-gradient(180deg, #0a0a0a 0%, #030712 100%)
`,
}}
/>
{/* 动态元素 */}
<NeonGrid />
<NeonBeams />
<DataRain />
<ParticleField />
<GlitchOverlay />
{/* 光晕效果 */}
<div
className="absolute inset-0"
style={{
background: `
radial-gradient(ellipse at center,
transparent 20%,
rgba(0, 0, 0, 0.3) 40%,
rgba(0, 0, 0, 0.6) 70%,
rgba(0, 0, 0, 0.9) 100%
)
`,
}}
/>
{/* 边缘暗角 */}
<div
className="absolute inset-0"
style={{
boxShadow: 'inset 0 0 200px 50px rgba(0, 0, 0, 0.9)',
}}
/>
{/* CRT扫描线效果 */}
<div
className="absolute inset-0 opacity-30"
style={{
backgroundImage: `repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(255, 255, 255, 0.03) 2px,
rgba(255, 255, 255, 0.03) 4px
)`,
animation: 'scan 8s linear infinite',
}}
/>
</div>
);
};
export default CyberpunkBackground;

View File

@@ -0,0 +1,151 @@
import React, { useState, useEffect, useMemo } from 'react';
// 优化后的霓虹网格线组件 - 增强颜色对比度
const NeonGrid: React.FC = () => {
return (
<div className="absolute inset-0 overflow-hidden">
<div
className="absolute inset-0 cyberpunk-grid"
style={{
backgroundImage: `
linear-gradient(rgba(244, 63, 94, 0.4) 1px, transparent 1px),
linear-gradient(90deg, rgba(6, 182, 212, 0.4) 1px, transparent 1px)
`,
backgroundSize: '50px 50px',
transform: 'perspective(500px) rotateX(60deg) scale(1.5)',
transformOrigin: 'center center',
filter: 'brightness(1.2)',
mixBlendMode: 'screen',
}}
/>
</div>
);
};
// 优化的霓虹光束 - 减少数量使用CSS动画
const NeonBeams: React.FC = () => {
return (
<div className="absolute inset-0 overflow-hidden opacity-50">
<div className="neon-beam neon-beam-1" />
<div className="neon-beam neon-beam-2" />
<div className="neon-beam neon-beam-3" />
</div>
);
};
// 增强的数据雨效果 - 更多列,更好的可见性
const DataRainSimplified: React.FC = () => {
return (
<div className="absolute inset-0 overflow-hidden opacity-50">
<div className="data-rain-container">
{Array.from({ length: 20 }, (_, i) => (
<div
key={i}
className="data-rain-column"
style={{
left: `${i * 5}%`,
animationDelay: `${i * 0.3}s`,
opacity: 0.3 + Math.random() * 0.4,
animationDuration: `${3 + Math.random() * 2}s`,
}}
/>
))}
</div>
</div>
);
};
// 优化的故障效果 - 减少频率
const GlitchOverlayOptimized: React.FC = () => {
const [glitchActive, setGlitchActive] = useState(false);
useEffect(() => {
const interval = setInterval(() => {
setGlitchActive(true);
setTimeout(() => setGlitchActive(false), 100);
}, 15000); // 降低频率
return () => clearInterval(interval);
}, []);
if (!glitchActive) return null;
return (
<div className="absolute inset-0 pointer-events-none glitch-overlay" />
);
};
// 优化后的主背景组件
const CyberpunkBackgroundOptimized: React.FC = () => {
// 使用useMemo缓存静态样式
const backgroundStyle = useMemo(() => ({
background: `
radial-gradient(circle at 50% 50%,
rgba(244, 63, 94, 0.05) 0%,
transparent 50%
),
radial-gradient(circle at 80% 20%,
rgba(168, 85, 247, 0.03) 0%,
transparent 50%
),
radial-gradient(circle at 20% 80%,
rgba(6, 182, 212, 0.03) 0%,
transparent 50%
),
linear-gradient(180deg, #0a0a0a 0%, #030712 100%)
`,
}), []);
return (
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
{/* 静态渐变背景 */}
<div
className="absolute inset-0"
style={backgroundStyle}
/>
{/* 简化的网格 */}
<NeonGrid />
{/* CSS动画光束 */}
<NeonBeams />
{/* 简化的数据雨 */}
<DataRainSimplified />
{/* 降频的故障效果 */}
<GlitchOverlayOptimized />
{/* 增强的静态光晕效果 */}
<div
className="absolute inset-0 pointer-events-none"
style={{
background: `
radial-gradient(ellipse at center,
transparent 20%,
rgba(0, 0, 0, 0.3) 40%,
rgba(0, 0, 0, 0.6) 70%,
rgba(0, 0, 0, 0.9) 100%
)
`,
mixBlendMode: 'multiply',
}}
/>
{/* 边缘光晕 */}
<div
className="absolute inset-0 pointer-events-none"
style={{
boxShadow: 'inset 0 0 150px 50px rgba(0, 0, 0, 0.8)',
}}
/>
{/* 简化的CRT效果 */}
<div
className="absolute inset-0 crt-effect"
/>
</div>
);
};
export default CyberpunkBackgroundOptimized;

View File

@@ -0,0 +1,293 @@
import React from 'react';
// 赛博朋克风格的图标组件
interface IconProps {
className?: string;
size?: number;
}
// CPU图标 - 带霓虹效果
export const CyberCpu: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<rect x="7" y="7" width="10" height="10" stroke="currentColor" strokeWidth="2" fill="none" />
<rect x="9" y="9" width="6" height="6" fill="currentColor" opacity="0.3" />
<path d="M10 2v5M14 2v5M10 17v5M14 17v5M2 10h5M17 10h5M2 14h5M17 14h5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 网络图标 - 带连接动画
export const CyberNetwork: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<circle cx="12" cy="5" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="5" cy="19" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="19" cy="19" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 7v6M12 13l-5.5 4M12 13l5.5 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="animate-pulse" />
<circle cx="12" cy="13" r="2" fill="currentColor" />
</svg>
);
// 代码图标 - 终端风格
export const CyberCode: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="2" rx="2" fill="none" />
<path d="M8 8l-2 4l2 4M16 8l2 4l-2 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M12 16.5v.5" stroke="currentColor" strokeWidth="3" strokeLinecap="round" className="animate-pulse" />
</svg>
);
// 目标图标 - 瞄准镜风格
export const CyberTarget: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2" fill="none" />
<circle cx="12" cy="12" r="6" stroke="currentColor" strokeWidth="1.5" fill="none" opacity="0.6" />
<circle cx="12" cy="12" r="3" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.3" />
<path d="M12 3v3M12 18v3M3 12h3M18 12h3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 火箭图标 - 发射风格
export const CyberRocket: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M12 2l3 7h7l-5.5 4 2 7L12 15l-6.5 5 2-7L2 9h7z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 2v13" stroke="currentColor" strokeWidth="1" strokeDasharray="2 2" className="animate-pulse" />
</svg>
);
// 数据库图标 - 层级风格
export const CyberDatabase: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<ellipse cx="12" cy="6" rx="7" ry="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M5 6v6c0 1.66 3.13 3 7 3s7-1.34 7-3V6" stroke="currentColor" strokeWidth="2" />
<path d="M5 12v6c0 1.66 3.13 3 7 3s7-1.34 7-3v-6" stroke="currentColor" strokeWidth="2" />
<path d="M12 9v.01M12 15v.01" stroke="currentColor" strokeWidth="3" strokeLinecap="round" className="animate-pulse" />
</svg>
);
// 闪电图标 - 能量风格
export const CyberZap: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M13 2L3 14h9l-1 8 10-12h-9z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" strokeLinejoin="round" />
<path d="M13 2L3 14h9l-1 8 10-12h-9z" stroke="currentColor" strokeWidth="1" strokeLinejoin="round" className="animate-pulse" opacity="0.8" />
</svg>
);
// 盾牌图标 - 安全风格
export const CyberShield: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M12 2l8 3v7c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10V5z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 设置图标 - 齿轮风格
export const CyberSettings: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M12 15a3 3 0 100-6 3 3 0 000 6z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z" stroke="currentColor" strokeWidth="2" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-spin" style={{ animationDuration: '3s' }} />
</svg>
);
// 层级图标 - 架构风格
export const CyberLayers: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M12 2l10 5v10l-10 5-10-5V7z" stroke="currentColor" strokeWidth="2" fill="none" />
<path d="M12 7l10 5-10 5-10-5z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M2 12v5l10 5v-5M22 12v5l-10 5v-5" stroke="currentColor" strokeWidth="1" strokeDasharray="2 2" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 共享图标 - 连接风格
export const CyberShare: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<circle cx="6" cy="12" r="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="18" cy="6" r="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="18" cy="18" r="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98" stroke="currentColor" strokeWidth="2" className="animate-pulse" />
<circle cx="12" cy="12" r="1" fill="currentColor" />
</svg>
);
// 用户图标 - 头像风格
export const CyberUser: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="12" cy="10" r="3" stroke="currentColor" strokeWidth="2" fill="none" />
<path d="M12 13c-4 0-6 2-6 4v2h12v-2c0-2-2-4-6-4z" fill="currentColor" opacity="0.6" />
<circle cx="9" cy="10" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="15" cy="10" r="0.5" fill="currentColor" className="animate-pulse" />
</svg>
);
// 勾选图标 - 确认风格
export const CyberCheck: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="2" rx="2" fill="currentColor" opacity="0.3" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="animate-pulse" opacity="0.8" />
</svg>
);
// 箭头图标 - 方向风格
export const CyberArrow: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M5 12h14" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
<circle cx="19" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 图表图标 - 数据风格
export const CyberChart: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="2" rx="2" fill="none" />
<path d="M8 16v-5M12 16v-8M16 16v-3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<path d="M8 16v-5M12 16v-8M16 16v-3" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
<circle cx="12" cy="8" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 书籍图标 - 学习风格
export const CyberBook: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<path d="M4 19.5A2.5 2.5 0 016.5 17H20" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M8 7h8M8 11h8M8 15h4" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
</svg>
);
// 时钟图标 - 时间风格
export const CyberClock: React.FC<IconProps> = ({ className = "", size = 24 }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
className={className}
>
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 6v6l4 2" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 3v1M12 20v1M3 12h1M20 12h1" stroke="currentColor" strokeWidth="1" strokeLinecap="round" opacity="0.6" />
</svg>
);
export default {
CyberCpu,
CyberNetwork,
CyberCode,
CyberTarget,
CyberRocket,
CyberDatabase,
CyberZap,
CyberShield,
CyberSettings,
CyberLayers,
CyberShare,
CyberUser,
CyberCheck,
CyberArrow,
CyberChart,
CyberBook,
CyberClock
};

View File

@@ -0,0 +1,104 @@
import React from 'react';
import { motion } from 'framer-motion';
interface CyberpunkVignetteProps {
intensity?: 'light' | 'medium' | 'strong';
variant?: 'default' | 'neon' | 'glitch' | 'minimal';
}
const CyberpunkVignette: React.FC<CyberpunkVignetteProps> = ({
intensity = 'medium',
variant = 'neon'
}) => {
const intensityMap = {
light: { opacity: 0.3, blur: 0.5 },
medium: { opacity: 0.5, blur: 1 },
strong: { opacity: 0.7, blur: 2 }
};
const config = intensityMap[intensity];
const getBackground = () => {
switch (variant) {
case 'minimal':
// 极简变体 - 性能优化版本
return `
linear-gradient(180deg,
rgba(0, 0, 0, ${config.opacity * 0.2}) 0%,
transparent 15%,
transparent 85%,
rgba(0, 0, 0, ${config.opacity * 0.2}) 100%
)
`;
case 'glitch':
return `
radial-gradient(ellipse at center,
transparent 30%,
rgba(244, 63, 94, ${config.opacity * 0.3}) 60%,
rgba(168, 85, 247, ${config.opacity * 0.5}) 80%,
rgba(0, 0, 0, ${config.opacity}) 100%
),
conic-gradient(
from 0deg at 50% 50%,
rgba(244, 63, 94, ${config.opacity * 0.1}),
rgba(168, 85, 247, ${config.opacity * 0.1}),
rgba(6, 182, 212, ${config.opacity * 0.1}),
rgba(244, 63, 94, ${config.opacity * 0.1})
)
`;
case 'neon':
return `
radial-gradient(ellipse at center,
transparent 40%,
rgba(244, 63, 94, ${config.opacity * 0.2}) 70%,
rgba(168, 85, 247, ${config.opacity * 0.3}) 85%,
rgba(0, 0, 0, ${config.opacity * 0.8}) 100%
),
linear-gradient(180deg,
rgba(0, 0, 0, ${config.opacity * 0.3}) 0%,
transparent 10%,
transparent 90%,
rgba(0, 0, 0, ${config.opacity * 0.3}) 100%
),
linear-gradient(90deg,
rgba(0, 0, 0, ${config.opacity * 0.3}) 0%,
transparent 10%,
transparent 90%,
rgba(0, 0, 0, ${config.opacity * 0.3}) 100%
)
`;
default:
return `
radial-gradient(ellipse at center,
transparent 50%,
rgba(0, 0, 0, ${config.opacity * 0.5}) 100%
),
linear-gradient(180deg,
rgba(0, 0, 0, ${config.opacity * 0.4}) 0%,
transparent 20%,
transparent 80%,
rgba(0, 0, 0, ${config.opacity * 0.4}) 100%
)
`;
}
};
return (
<>
<motion.div
className="fixed inset-0 pointer-events-none z-20"
style={{
background: getBackground(),
filter: `blur(${config.blur}px)`,
}}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, ease: "easeOut" }}
/>
{/* 霓虹边框效果已移除 */}
</>
);
};
export default CyberpunkVignette;

View File

@@ -0,0 +1,196 @@
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
// 星点组件 - 实现消失后随机重生
const Star: React.FC<{ index: number }> = ({ index }) => {
const [position, setPosition] = useState({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 4 + 2, // 增大尺寸范围 2-6px
});
const [isVisible, setIsVisible] = useState(true);
// 生成新的随机位置
const regenerate = () => {
setIsVisible(false);
setTimeout(() => {
setPosition({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 4 + 2, // 增大尺寸范围 2-6px
});
setIsVisible(true);
}, 500);
};
useEffect(() => {
// 随机生命周期5-15秒
const lifetime = (Math.random() * 10 + 5) * 1000;
const interval = setInterval(regenerate, lifetime);
return () => clearInterval(interval);
}, []);
return (
<AnimatePresence>
{isVisible && (
<motion.div
className="absolute bg-[#E5DFD7]"
style={{
width: `${position.size}px`,
height: `${position.size}px`,
borderRadius: '50%',
left: `${position.x}%`,
top: `${position.y}%`,
boxShadow: `0 0 ${position.size * 3}px rgba(229, 223, 215, 0.9), 0 0 ${position.size * 6}px rgba(229, 223, 215, 0.4)`,
}}
initial={{ opacity: 0, scale: 0 }}
animate={{
opacity: [0, 1, 1, 0],
scale: [0, 1, 1.2, 0]
}}
transition={{
duration: Math.random() * 3 + 2,
times: [0, 0.2, 0.8, 1],
ease: "easeInOut"
}}
/>
)}
</AnimatePresence>
);
};
const GlobalBackground: React.FC = () => {
return (
<div className="fixed inset-0 pointer-events-none overflow-hidden">
{/* 基础渐变层 - 调暗以突出效果 */}
<div
className="absolute inset-0"
style={{
background: 'linear-gradient(180deg, color-mix(in oklab, #7A9E9F 85%, #000 15%) 0%, color-mix(in oklab, #8A9B8F 75%, #000 25%) 65%, color-mix(in oklab, #8A9B8F 65%, #000 35%) 100%)'
}}
/>
{/* 液态流动层 - 增强金色光斑 */}
<motion.div
className="absolute inset-[-20%]"
style={{
background: `
radial-gradient(45% 30% at 70% 20%, rgba(212, 180, 131, 0.20), transparent 60%),
radial-gradient(40% 28% at 30% 80%, rgba(212, 180, 131, 0.15), transparent 60%)
`,
filter: 'blur(30px)'
}}
animate={{
x: ['-4%', '6%'],
y: ['-2%', '3%'],
rotate: [0.6, -0.6]
}}
transition={{
duration: 25,
ease: "easeInOut",
repeat: Infinity,
repeatType: "reverse"
}}
/>
{/* 极光效果层1 - 增强可见度 */}
<motion.div
className="absolute w-full h-[200%] -top-1/2"
style={{
background: `linear-gradient(45deg,
transparent 20%,
rgba(212, 180, 131, 0.25) 30%,
rgba(122, 158, 159, 0.20) 40%,
rgba(212, 180, 131, 0.18) 50%,
transparent 60%
)`,
filter: 'blur(60px)',
transform: 'skewY(-15deg)',
opacity: 0.6
}}
animate={{
x: ['-100%', '100%'],
opacity: [0.4, 0.7, 0.4]
}}
transition={{
duration: 30,
ease: "easeInOut",
repeat: Infinity,
repeatType: "reverse"
}}
/>
{/* 极光效果层2 */}
<motion.div
className="absolute w-full h-[200%] -top-1/2 opacity-20"
style={{
background: `linear-gradient(-30deg,
transparent 10%,
rgba(138, 155, 143, 0.15) 25%,
rgba(212, 180, 131, 0.10) 35%,
rgba(229, 223, 215, 0.08) 45%,
transparent 60%
)`,
filter: 'blur(80px)',
transform: 'skewY(10deg)'
}}
animate={{
x: ['100%', '-100%'],
opacity: [0.15, 0.3, 0.15]
}}
transition={{
duration: 35,
ease: "easeInOut",
repeat: Infinity,
repeatType: "reverse",
delay: 10
}}
/>
{/* 额外的流动层 - 增强金色效果 */}
<motion.div
className="absolute inset-[-30%]"
style={{
background: `
radial-gradient(50% 35% at 20% 50%, rgba(212, 180, 131, 0.12), transparent 70%),
radial-gradient(35% 25% at 80% 70%, rgba(212, 180, 131, 0.10), transparent 60%)
`,
filter: 'blur(40px)',
opacity: 0.7
}}
animate={{
x: ['5%', '-5%'],
y: ['3%', '-4%'],
rotate: [-1, 1]
}}
transition={{
duration: 40,
ease: "easeInOut",
repeat: Infinity,
repeatType: "reverse"
}}
/>
{/* 星点效果 - 圆形,灭掉后随机重生 */}
<div className="absolute inset-0">
{Array.from({ length: 60 }, (_, i) => (
<Star key={i} index={i} />
))}
</div>
{/* 减少动效样式 */}
<style>{`
@media (prefers-reduced-motion: reduce) {
.motion-div {
animation: none !important;
transition: none !important;
}
}
`}</style>
</div>
);
};
export default GlobalBackground;

575
src/components/Icons.tsx Normal file
View File

@@ -0,0 +1,575 @@
import React from 'react';
interface IconProps {
className?: string;
size?: number;
}
// 书本图标 - 赛博朋克风格
export const BookOpen: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<defs>
<filter id="neon-glow">
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<path d="M4 19.5A2.5 2.5 0 016.5 17H20" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" filter="url(#neon-glow)" />
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M8 7h8M8 11h8M8 15h4" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.8" />
<circle cx="12" cy="11" r="0.5" fill="currentColor" className="animate-pulse" />
</svg>
);
// 设置图标 - 赛博朋克风格
export const Settings: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M12 15a3 3 0 100-6 3 3 0 000 6z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z" stroke="currentColor" strokeWidth="2" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-spin" style={{ animationDuration: '3s' }} />
</svg>
);
// 闪电图标 - 赛博朋克风格
export const Zap: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M13 2L3 14h9l-1 8 10-12h-9z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" strokeLinejoin="round" />
<path d="M13 2L3 14h9l-1 8 10-12h-9z" stroke="currentColor" strokeWidth="1" strokeLinejoin="round" className="animate-pulse" opacity="0.8" />
<circle cx="12" cy="10" r="0.5" fill="currentColor" className="animate-pulse" />
</svg>
);
// CPU图标 - 赛博朋克风格
export const Cpu: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<rect x="7" y="7" width="10" height="10" stroke="currentColor" strokeWidth="2" fill="none" />
<rect x="9" y="9" width="6" height="6" fill="currentColor" opacity="0.3" />
<path d="M10 2v5M14 2v5M10 17v5M14 17v5M2 10h5M17 10h5M2 14h5M17 14h5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M10 2v5M14 2v5M10 17v5M14 17v5" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 箭头右图标 - 赛博朋克风格
export const ChevronRight: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M9 18l6-6-6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9 18l6-6-6-6" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 箭头下图标 - 赛博朋克风格
export const ChevronDown: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M6 9l6 6 6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M6 9l6 6 6-6" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 播放图标 - 赛博朋克风格
export const PlayCircle: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<polygon points="10,8 16,12 10,16 10,8" fill="currentColor" />
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="1" className="animate-pulse" opacity="0.5" />
<polygon points="10,8 16,12 10,16 10,8" fill="currentColor" className="animate-pulse" opacity="0.3" />
</svg>
);
// 时钟图标 - 赛博朋克风格
export const Clock: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 6v6l4 2" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 3v1M12 20v1M3 12h1M20 12h1" stroke="currentColor" strokeWidth="1" strokeLinecap="round" opacity="0.6" className="animate-pulse" />
</svg>
);
// 用户图标 - 赛博朋克风格
export const Users: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="9" cy="7" r="4" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75" stroke="currentColor" strokeWidth="2" />
<circle cx="9" cy="7" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="20" cy="7" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.5s' }} />
</svg>
);
// 目标图标 - 赛博朋克风格
export const Target: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2" fill="none" />
<circle cx="12" cy="12" r="6" stroke="currentColor" strokeWidth="1.5" fill="none" opacity="0.6" className="animate-pulse" />
<circle cx="12" cy="12" r="3" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.3" />
<path d="M12 3v3M12 18v3M3 12h3M18 12h3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 奖杯图标 - 赛博朋克风格
export const Award: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<circle cx="12" cy="8" r="7" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<polyline points="8.21,13.89 7,23 12,20 17,23 15.79,13.88" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="12" cy="8" r="3" fill="currentColor" opacity="0.5" />
<circle cx="12" cy="8" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 1v2M7 3l1 1M17 3l-1 1" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
</svg>
);
// 菜单图标 - 赛博朋克风格
export const Menu: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<line x1="3" y1="6" x2="21" y2="6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="3" y1="18" x2="21" y2="18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="3" cy="6" r="1" fill="currentColor" className="animate-pulse" />
<circle cx="3" cy="12" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.2s' }} />
<circle cx="3" cy="18" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.4s' }} />
</svg>
);
// 关闭图标 - 赛博朋克风格
export const X: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="8" stroke="currentColor" strokeWidth="1" fill="none" className="animate-pulse" opacity="0.3" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 勾选图标 - 赛博朋克风格
export const CheckCircle: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="animate-pulse" opacity="0.8" />
</svg>
);
// 箭头右图标 - 赛博朋克风格
export const ArrowRight: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M5 12h14" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
<circle cx="19" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 显示器图标 - 赛博朋克风格
export const Monitor: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<rect x="2" y="3" width="20" height="14" rx="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<line x1="8" y1="21" x2="16" y2="21" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="12" y1="17" x2="12" y2="21" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<rect x="4" y="5" width="16" height="10" fill="currentColor" opacity="0.2" />
<circle cx="12" cy="10" r="1" fill="currentColor" className="animate-pulse" />
<path d="M6 7h3M6 9h5" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 网络图标 - 赛博朋克风格
export const Network: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<circle cx="12" cy="5" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="5" cy="19" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="19" cy="19" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 7v6M12 13l-5.5 4M12 13l5.5 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="animate-pulse" />
<circle cx="12" cy="13" r="2" fill="currentColor" />
<circle cx="12" cy="5" r="0.5" fill="currentColor" className="animate-pulse" />
</svg>
);
// 眼睛图标 - 赛博朋克风格
export const Eye: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="12" cy="12" r="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.5" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 5v2M12 17v2" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.4" />
</svg>
);
// 层级图标 - 赛博朋克风格
export const Layers: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M12 2l10 5v10l-10 5-10-5V7z" stroke="currentColor" strokeWidth="2" fill="none" />
<path d="M12 7l10 5-10 5-10-5z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M2 12v5l10 5v-5M22 12v5l-10 5v-5" stroke="currentColor" strokeWidth="1" strokeDasharray="2 2" className="animate-pulse" opacity="0.6" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 箭头左图标 - 赛博朋克风格
export const ArrowLeft: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<path d="M19 12H5M12 19l-7-7 7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M19 12H5" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
<circle cx="5" cy="12" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 刷新图标 - 赛博朋克风格
export const RefreshCw: React.FC<IconProps> = ({ className = '', size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" className={className}>
<polyline points="23,4 23,10 17,10" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<polyline points="1,20 1,14 7,14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M20.49 9A9 9 0 005.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 013.51 15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-spin" style={{ animationDuration: '2s' }} />
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1" fill="none" className="animate-pulse" opacity="0.3" />
</svg>
);
// Hash图标 - 赛博朋克风格
export const Hash = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<line x1="4" y1="9" x2="20" y2="9" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="4" y1="15" x2="20" y2="15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="10" y1="3" x2="8" y2="21" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="16" y1="3" x2="14" y2="21" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<rect x="8" y="9" width="8" height="6" fill="currentColor" opacity="0.2" />
</svg>
);
// 计算器图标 - 赛博朋克风格
export const Calculator = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="4" y="2" width="16" height="20" rx="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<rect x="7" y="5" width="10" height="3" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.5" />
<circle cx="8" cy="12" r="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.6" />
<circle cx="12" cy="12" r="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.6" />
<circle cx="16" cy="12" r="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.6" />
<circle cx="8" cy="16" r="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.6" />
<circle cx="12" cy="16" r="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.6" />
<circle cx="16" cy="16" r="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.6" />
<circle cx="12" cy="6.5" r="0.5" fill="currentColor" className="animate-pulse" />
</svg>
);
// 电源图标 - 赛博朋克风格
export const Power = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M18.36 6.64a9 9 0 11-12.73 0" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="12" y1="2" x2="12" y2="12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.2" />
<circle cx="12" cy="2" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 2v10" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 代码图标 - 赛博朋克风格
export const Code = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="2" rx="2" fill="none" />
<path d="M8 8l-2 4 2 4M16 8l2 4-2 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M12 16.5v.5" stroke="currentColor" strokeWidth="3" strokeLinecap="round" className="animate-pulse" />
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="1" rx="2" fill="none" className="animate-pulse" opacity="0.3" />
</svg>
);
// 盾牌图标 - 赛博朋克风格
export const Shield = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2l8 3v7c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10V5z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 2l8 3v7c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10V5z" stroke="currentColor" strokeWidth="1" fill="none" className="animate-pulse" opacity="0.4" />
</svg>
);
// 箭头下图标 - 赛博朋克风格
export const ArrowDown = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 5v14M19 12l-7 7-7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M12 5v14" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
<circle cx="12" cy="19" r="1" fill="currentColor" className="animate-pulse" />
</svg>
);
// 文件夹图标 - 赛博朋克风格
export const Folder = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z" stroke="currentColor" strokeWidth="1" fill="none" className="animate-pulse" opacity="0.5" />
<circle cx="12" cy="13" r="0.5" fill="currentColor" className="animate-pulse" />
</svg>
);
// 服务器图标 - 赛博朋克风格
export const Server = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="2" y="2" width="20" height="8" rx="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<rect x="2" y="14" width="20" height="8" rx="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="6" cy="6" r="1" fill="currentColor" className="animate-pulse" />
<circle cx="6" cy="18" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.5s' }} />
<line x1="10" y1="6" x2="18" y2="6" stroke="currentColor" strokeWidth="1" strokeLinecap="round" opacity="0.5" />
<line x1="10" y1="18" x2="18" y2="18" stroke="currentColor" strokeWidth="1" strokeLinecap="round" opacity="0.5" />
</svg>
);
// 数据库图标 - 赛博朋克风格
export const Database = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<ellipse cx="12" cy="5" rx="9" ry="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3M21 5v14c0 1.66-4 3-9 3s-9-1.34-9-3V5" stroke="currentColor" strokeWidth="2" />
<path d="M21 12v7c0 1.66-4 3-9 3s-9-1.34-9-3v-7" stroke="currentColor" strokeWidth="1" strokeDasharray="2 2" className="animate-pulse" opacity="0.5" />
<circle cx="12" cy="5" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="12" cy="12" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.3s' }} />
<circle cx="12" cy="19" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.6s' }} />
</svg>
);
// 图表图标 - 赛博朋克风格
export const BarChart = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="2" rx="2" fill="none" />
<rect x="7" y="8" width="3" height="13" fill="currentColor" opacity="0.6" />
<rect x="14" y="5" width="3" height="16" fill="currentColor" opacity="0.6" />
<rect x="7" y="8" width="3" height="13" fill="none" stroke="currentColor" strokeWidth="1" className="animate-pulse" opacity="0.8" />
<rect x="14" y="5" width="3" height="16" fill="none" stroke="currentColor" strokeWidth="1" className="animate-pulse" opacity="0.8" />
<circle cx="8.5" cy="8" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="15.5" cy="5" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.3s' }} />
</svg>
);
// 灯泡图标 (💡) - 赛博朋克风格
export const Lightbulb = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2C8.13 2 5 5.13 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.87-3.13-7-7-7z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<line x1="9" y1="21" x2="15" y2="21" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<line x1="12" y1="18" x2="12" y2="21" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="9" r="2" fill="currentColor" className="animate-pulse" />
<path d="M12 2v3M18 9h3M6 9H3M17 14l2 2M7 14l-2 2" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 火箭图标 (🚀) - 赛博朋克风格
export const Rocket = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2L8 8l-3 1v6l3 1 4 6 4-6 3-1V9l-3-1z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="12" cy="11" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.5" />
<path d="M7 17l-2 4M17 17l2 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="11" r="0.5" fill="currentColor" className="animate-pulse" />
<path d="M12 22v-2" stroke="currentColor" strokeWidth="3" strokeLinecap="round" className="animate-pulse" opacity="0.8" />
</svg>
);
// 工具图标 (🔧) - 赛博朋克风格
export const Tool = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94l-6.91 6.91a2.12 2.12 0 01-3-3l6.91-6.91a6 6 0 017.94-7.94l-3.76 3.76z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="18" cy="6" r="1" fill="currentColor" className="animate-pulse" />
<circle cx="6" cy="18" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.5s' }} />
<path d="M15 9l-6 6" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 书籍图标 (📚) - 赛博朋克风格
export const Books = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M4 5h5v14H4zM9 5h5v14H9zM14 5h6v14h-6z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M4 5h5v14H4z" stroke="currentColor" strokeWidth="2" />
<path d="M9 5h5v14H9z" stroke="currentColor" strokeWidth="2" />
<path d="M14 5h6v14h-6z" stroke="currentColor" strokeWidth="2" />
<circle cx="6.5" cy="8" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="11.5" cy="8" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.2s' }} />
<circle cx="17" cy="8" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.4s' }} />
</svg>
);
// 趋势图标 (📈) - 赛博朋克风格
export const TrendingUp = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="3" y="3" width="18" height="18" stroke="currentColor" strokeWidth="2" rx="2" fill="currentColor" opacity="0.2" />
<polyline points="7,17 12,12 15,15 20,10" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<polyline points="15,10 20,10 20,15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<polyline points="7,17 12,12 15,15 20,10" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 包裹图标 (📦) - 赛博朋克风格
export const Package = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2l10 5v10l-10 5-10-5V7z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 22V12M2 7l10 5 10-5M7 4.5L17 9.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M12 2v5" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 闪光图标 (⚡) - 已存在 Zap创建别名
export const Lightning = Zap;
// 目标靶心图标 (🎯) - 已存在 Target创建别名
export const Bullseye = Target;
// 信号图标 (📡) - 赛博朋克风格
export const Signal = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<circle cx="12" cy="18" r="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.5" />
<path d="M16.24 13.76a6 6 0 00-8.48 0" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<path d="M19.07 10.93a10 10 0 00-14.14 0" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<path d="M22 8a14 14 0 00-20 0" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="18" r="0.5" fill="currentColor" className="animate-pulse" />
<path d="M16.24 13.76a6 6 0 00-8.48 0" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 消息图标 (💬) - 赛博朋克风格
export const Message = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="8" cy="11" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="12" cy="11" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.2s' }} />
<circle cx="16" cy="11" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.4s' }} />
</svg>
);
// 标签图标 (🏷️) - 赛博朋克风格
export const Tag = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="7" cy="7" r="1" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.6" />
<circle cx="7" cy="7" r="0.5" fill="currentColor" className="animate-pulse" />
<path d="M2 2l10 10" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 握手图标 (🤝) - 赛博朋克风格
export const Handshake = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M11 6l-3-3-6 6v8h7l3-3m10-8l-6-6-3 3m14 14v-8l-6-6m-5 5l5 5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none" />
<path d="M8 12h8" stroke="currentColor" strokeWidth="2" strokeLinecap="round" fill="none" />
<circle cx="12" cy="12" r="2" fill="currentColor" opacity="0.5" />
<circle cx="12" cy="12" r="0.5" fill="currentColor" className="animate-pulse" />
<path d="M7 12h10" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 拼图图标 (🧩) - 赛博朋克风格
export const Puzzle = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M4 4h4c0-2 1-3 2-3s2 1 2 3h4v4c2 0 3 1 3 2s-1 2-3 2v4h-4c0 2-1 3-2 3s-2-1-2-3H4v-4c-2 0-3-1-3-2s1-2 3-2V4z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M8 12h8M12 8v8" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.5" />
</svg>
);
// 刷新循环图标 (🔄) - 已有 RefreshCw创建别名
export const Refresh = RefreshCw;
// 图表图标 (📊) - 已有 BarChart创建别名
export const Chart = BarChart;
// 机器人图标 (🤖) - 赛博朋克风格
export const Robot = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="4" y="4" width="16" height="16" rx="4" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<rect x="6" y="2" width="12" height="2" rx="1" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.5" />
<circle cx="9" cy="9" r="1" fill="currentColor" className="animate-pulse" />
<circle cx="15" cy="9" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.2s' }} />
<path d="M8 14h8" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<rect x="4" y="20" width="4" height="2" rx="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.5" />
<rect x="16" y="20" width="4" height="2" rx="1" stroke="currentColor" strokeWidth="1" fill="currentColor" opacity="0.5" />
<circle cx="12" cy="12" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.4s' }} />
</svg>
);
// 大脑图标 (🧠) - 赛博朋克风格
export const Brain = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2C8 2 5 5 5 9c0 1.5.5 3 1.5 4C5.5 14 5 15.5 5 17c0 2.5 2 4.5 4.5 4.5h5c2.5 0 4.5-2 4.5-4.5 0-1.5-.5-3-1.5-4 1-.5 1.5-2.5 1.5-4 0-4-3-7-7-7z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M8 10c0-1 .5-2 1.5-2S11 9 11 10M13 10c0-1 .5-2 1.5-2S16 9 16 10" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="12" cy="12" r="1" fill="currentColor" className="animate-pulse" />
<path d="M9 14c1 1 2 1 3 1s2 0 3-1" stroke="currentColor" strokeWidth="1" strokeLinecap="round" className="animate-pulse" opacity="0.6" />
</svg>
);
// 天平图标 (⚖️) - 赛博朋克风格
export const Scale = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2v20" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<path d="M6 6l6 0 6 0" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
<circle cx="6" cy="6" r="4" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="18" cy="6" r="4" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<rect x="8" y="20" width="8" height="2" rx="1" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.5" />
<circle cx="6" cy="6" r="0.5" fill="currentColor" className="animate-pulse" />
<circle cx="18" cy="6" r="0.5" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.5s' }} />
</svg>
);
// 天平图标别名
export const Balance = Scale;
// 添加更多赛博朋克风格图标
export const Warning = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M12 2L2 20h20L12 2z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 9v4m0 4h.01" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="animate-pulse" />
</svg>
);
export const Cog = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<circle cx="12" cy="12" r="3" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 1v6m0 6v6m6.36-15.36l-4.24 4.24m-4.24 4.24l-4.24 4.24M23 12h-6m-6 0H1m16.36 6.36l-4.24-4.24m-4.24-4.24L4.64 5.64" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="animate-spin-slow" />
</svg>
);
export const ClipboardCheck = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="3" y="4" width="18" height="18" rx="2" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M9 12l2 2 4-4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="animate-pulse" />
<rect x="8" y="2" width="8" height="4" rx="1" stroke="currentColor" strokeWidth="2" />
</svg>
);
export const Globe = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z" stroke="currentColor" strokeWidth="2" className="animate-pulse" />
</svg>
);
export const Timer = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<circle cx="12" cy="13" r="9" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M12 7v6l4 2" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="animate-pulse" />
<path d="M9 2h6m-3 0v3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
</svg>
);
export const Map = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M1 6v16l7-4 8 4 7-4V2l-7 4-8-4-7 4z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<path d="M8 2v16m8-12v16" stroke="currentColor" strokeWidth="2" className="animate-pulse" />
</svg>
);
export const Building = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<rect x="4" y="2" width="16" height="20" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<rect x="8" y="6" width="3" height="3" stroke="currentColor" strokeWidth="1" className="animate-pulse" />
<rect x="13" y="6" width="3" height="3" stroke="currentColor" strokeWidth="1" className="animate-pulse" />
<rect x="8" y="12" width="3" height="3" stroke="currentColor" strokeWidth="1" className="animate-pulse" />
<rect x="13" y="12" width="3" height="3" stroke="currentColor" strokeWidth="1" className="animate-pulse" />
<rect x="10" y="18" width="4" height="4" stroke="currentColor" strokeWidth="2" />
</svg>
);
export const MessageSquare = (props: IconProps) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z" stroke="currentColor" strokeWidth="2" fill="currentColor" opacity="0.3" />
<circle cx="9" cy="10" r="1" fill="currentColor" className="animate-pulse" />
<circle cx="12" cy="10" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.2s' }} />
<circle cx="15" cy="10" r="1" fill="currentColor" className="animate-pulse" style={{ animationDelay: '0.4s' }} />
</svg>
);

View File

@@ -0,0 +1,102 @@
import React, { ReactNode, useRef, useEffect, useState } from 'react';
interface LiquidGlassProps {
children: ReactNode;
className?: string;
style?: React.CSSProperties;
onClick?: () => void;
displacementScale?: number;
blurAmount?: number;
saturation?: number;
elasticity?: number;
cornerRadius?: number;
mouseContainer?: React.RefObject<HTMLElement | null> | null;
}
const LiquidGlass: React.FC<LiquidGlassProps> = ({
children,
className = '',
style = {},
onClick,
displacementScale = 50,
blurAmount = 0.08,
saturation = 130,
elasticity = 0.15,
cornerRadius = 16,
mouseContainer
}) => {
const glassRef = useRef<HTMLDivElement>(null);
const [mousePosition, setMousePosition] = useState({ x: 0.5, y: 0.5 });
const [isHovered, setIsHovered] = useState(false);
useEffect(() => {
const handleMouseMove = (e: Event) => {
const mouseEvent = e as MouseEvent;
const container = mouseContainer?.current || glassRef.current;
if (!container) return;
const rect = container.getBoundingClientRect();
const x = (mouseEvent.clientX - rect.left) / rect.width;
const y = (mouseEvent.clientY - rect.top) / rect.height;
setMousePosition({ x: Math.max(0, Math.min(1, x)), y: Math.max(0, Math.min(1, y)) });
};
const container = mouseContainer?.current || document;
container.addEventListener('mousemove', handleMouseMove);
return () => {
container.removeEventListener('mousemove', handleMouseMove);
};
}, [mouseContainer]);
const glassStyle: React.CSSProperties = {
position: 'relative',
overflow: 'hidden',
backdropFilter: `blur(${blurAmount * 100}px) saturate(${saturation}%)`,
background: 'rgba(255, 255, 255, 0.1)',
border: '1px solid rgba(255, 255, 255, 0.2)',
borderRadius: `${cornerRadius}px`,
boxShadow: `
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.2)
`,
transition: `all ${elasticity}s cubic-bezier(0.4, 0, 0.2, 1)`,
transform: isHovered
? `perspective(1000px) rotateX(${(mousePosition.y - 0.5) * 10}deg) rotateY(${(mousePosition.x - 0.5) * 10}deg) scale(1.02)`
: 'perspective(1000px) rotateX(0deg) rotateY(0deg) scale(1)',
cursor: onClick ? 'pointer' : 'default',
...style
};
const overlayStyle: React.CSSProperties = {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: `radial-gradient(circle at ${mousePosition.x * 100}% ${mousePosition.y * 100}%, rgba(255, 255, 255, 0.1) 0%, transparent 50%)`,
borderRadius: `${cornerRadius}px`,
opacity: isHovered ? 1 : 0,
transition: `opacity ${elasticity}s ease-out`,
pointerEvents: 'none'
};
return (
<div
ref={glassRef}
className={className}
style={glassStyle}
onClick={onClick}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<div style={overlayStyle} />
<div style={{ position: 'relative', zIndex: 1 }}>
{children}
</div>
</div>
);
};
export default LiquidGlass;

View File

@@ -0,0 +1,138 @@
import React, { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Cpu, PlayCircle, X } from './Icons';
const Navigation: React.FC = () => {
const location = useLocation();
const [isTrialModalOpen, setIsTrialModalOpen] = useState(false);
const navLinks = [
{ path: '/', label: '课程首页' },
{ path: '/course', label: '课程' }
];
return (
<>
<nav className="fixed top-0 left-0 right-0 z-50 bg-cyber-dark-900/95 backdrop-blur-xl border-b border-cyber-pink-500/30">
{/* Trial Button - Absolutely Positioned at Left */}
<button
onClick={() => setIsTrialModalOpen(true)}
className="absolute left-4 top-1/2 -translate-y-1/2 flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white rounded-xl font-medium text-sm transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-purple-500/30 z-10"
>
<PlayCircle className="w-4 h-4" />
<span></span>
</button>
<div className="max-w-7xl mx-auto px-6">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<div className="flex items-center space-x-4 ml-32">
<Link to="/" className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-r from-cyber-pink-500 to-neon-purple-500 rounded-lg flex items-center justify-center shadow-neon-pink neon-glow-pink">
<Cpu className="w-6 h-6 text-white" />
</div>
<span className="gradient-text font-bold text-lg uppercase tracking-wider">Agent协作系统</span>
</Link>
</div>
{/* Desktop Navigation */}
<div className="hidden md:flex items-center space-x-8">
{navLinks.map((link) => (
<Link
key={link.path}
to={link.path}
className={`relative px-4 py-2 font-semibold transition-all duration-300 ${
location.pathname === link.path
? 'text-neon-cyan-400 neon-text-cyan'
: 'text-cyber-dark-200 hover:text-neon-cyan-400'
}`}
>
{link.label}
{location.pathname === link.path && (
<span className="absolute bottom-0 left-0 right-0 h-0.5 bg-gradient-to-r from-neon-cyan-500 to-cyber-pink-500 shadow-neon-cyan"></span>
)}
</Link>
))}
</div>
{/* Mobile Navigation */}
<div className="md:hidden flex items-center space-x-4">
{navLinks.map((link) => (
<Link
key={link.path}
to={link.path}
className={`px-3 py-2 text-sm font-semibold transition-all duration-300 ${
location.pathname === link.path
? 'text-neon-cyan-400 neon-text-cyan'
: 'text-cyber-dark-200 hover:text-neon-cyan-400'
}`}
>
{link.label}
</Link>
))}
</div>
</div>
</div>
</nav>
{/* Trial Video Modal */}
{isTrialModalOpen && (
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4">
{/* Backdrop */}
<div
className="absolute inset-0 bg-black/80 backdrop-blur-sm"
onClick={() => setIsTrialModalOpen(false)}
/>
{/* Modal Content */}
<div className="relative w-full max-w-5xl bg-gradient-to-br from-gray-900 to-black rounded-2xl shadow-2xl border border-purple-500/30 overflow-hidden">
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-purple-500/20">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-gradient-to-r from-purple-500 to-pink-500 rounded-lg flex items-center justify-center">
<PlayCircle className="w-6 h-6 text-white" />
</div>
<h2 className="text-2xl font-bold text-white"></h2>
</div>
<button
onClick={() => setIsTrialModalOpen(false)}
className="w-10 h-10 rounded-lg bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors"
>
<X className="w-5 h-5 text-white" />
</button>
</div>
{/* Video Container */}
<div className="relative bg-black" style={{ paddingBottom: '56.25%' }}>
<video
className="absolute inset-0 w-full h-full"
controls
autoPlay
src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/web_teach/AIclass_playback.mov"
>
</video>
</div>
{/* Footer */}
<div className="p-6 bg-gradient-to-r from-purple-900/20 to-pink-900/20 border-t border-purple-500/20">
<div className="flex items-center justify-between">
<p className="text-white/80">
Agent协作系统课程的完整直播回放AI协作技术
</p>
<button
onClick={() => setIsTrialModalOpen(false)}
className="px-6 py-2 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white rounded-lg font-medium transition-all hover:scale-105"
>
</button>
</div>
</div>
</div>
</div>
)}
</>
);
};
export default Navigation;

View File

@@ -0,0 +1,27 @@
import React from 'react';
interface PageVignetteProps {
intensity?: 'light' | 'medium' | 'strong';
}
const PageVignette: React.FC<PageVignetteProps> = ({ intensity = 'medium' }) => {
const opacityMap = {
light: 0.1,
medium: 0.15,
strong: 0.25
};
return (
<div
className="fixed inset-0 pointer-events-none z-40"
style={{
background: `
radial-gradient(120% 90% at 50% 40%, transparent 35%, rgba(0,0,0,${opacityMap[intensity]}) 100%),
radial-gradient(80% 60% at 50% 50%, transparent 60%, rgba(0,0,0,${opacityMap[intensity] * 0.5}) 100%)
`
}}
/>
);
};
export default PageVignette;

View File

@@ -0,0 +1,19 @@
import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
const ScrollToTop: React.FC = () => {
const { pathname } = useLocation();
useEffect(() => {
// 页面切换时滚动到顶部
window.scrollTo({
top: 0,
left: 0,
behavior: 'smooth' // 平滑滚动效果
});
}, [pathname]);
return null; // 这个组件不渲染任何内容
};
export default ScrollToTop;

View File

@@ -0,0 +1,55 @@
import React from 'react';
import { motion } from 'framer-motion';
interface TechVignetteProps {
intensity?: 'light' | 'medium' | 'strong';
variant?: 'default' | 'focused' | 'minimal';
}
const TechVignette: React.FC<TechVignetteProps> = ({
intensity = 'medium',
variant = 'default'
}) => {
const intensityMap = {
light: { opacity: 0.05, blur: 0.5 },
medium: { opacity: 0.1, blur: 1 },
strong: { opacity: 0.2, blur: 1.5 }
};
const config = intensityMap[intensity];
const getBackground = () => {
switch (variant) {
case 'focused':
return `
radial-gradient(ellipse 80% 60% at 50% 40%, transparent 30%, rgba(15, 23, 42, ${config.opacity * 1.5}) 100%),
radial-gradient(ellipse 60% 80% at 50% 50%, transparent 50%, rgba(8, 145, 178, ${config.opacity * 0.5}) 100%)
`;
case 'minimal':
return `
linear-gradient(180deg, rgba(15, 23, 42, ${config.opacity * 0.8}) 0%, transparent 30%, transparent 70%, rgba(15, 23, 42, ${config.opacity * 0.6}) 100%)
`;
default:
return `
radial-gradient(120% 90% at 50% 40%, transparent 35%, rgba(15, 23, 42, ${config.opacity}) 100%),
radial-gradient(80% 60% at 50% 50%, transparent 60%, rgba(8, 145, 178, ${config.opacity * 0.3}) 100%),
linear-gradient(180deg, rgba(15, 23, 42, ${config.opacity * 0.5}) 0%, transparent 20%, transparent 80%, rgba(15, 23, 42, ${config.opacity * 0.3}) 100%)
`;
}
};
return (
<motion.div
className="fixed inset-0 pointer-events-none z-20"
style={{
background: getBackground(),
filter: `blur(${config.blur}px)`
}}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, ease: "easeOut" }}
/>
);
};
export default TechVignette;

View File

@@ -0,0 +1,142 @@
import { useEffect, useState, useCallback } from 'react';
interface PerformanceMetrics {
fps: number;
memoryUsage: number | null;
renderTime: number;
isLowPerformance: boolean;
}
export const usePerformanceMonitor = () => {
const [metrics, setMetrics] = useState<PerformanceMetrics>({
fps: 60,
memoryUsage: null,
renderTime: 0,
isLowPerformance: false
});
const [shouldReduceEffects, setShouldReduceEffects] = useState(false);
// FPS 监控
const measureFPS = useCallback(() => {
let lastTime = performance.now();
let frames = 0;
let fps = 60;
const frame = () => {
const currentTime = performance.now();
frames++;
if (currentTime >= lastTime + 1000) {
fps = Math.round((frames * 1000) / (currentTime - lastTime));
frames = 0;
lastTime = currentTime;
// 如果FPS低于30启用性能模式
if (fps < 30) {
setShouldReduceEffects(true);
}
setMetrics(prev => ({
...prev,
fps,
isLowPerformance: fps < 30
}));
}
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
}, []);
// 内存使用监控
const measureMemory = useCallback(() => {
if ('memory' in performance) {
const memory = (performance as any).memory;
const usedMemory = memory.usedJSHeapSize / 1048576; // 转换为MB
setMetrics(prev => ({
...prev,
memoryUsage: Math.round(usedMemory)
}));
}
}, []);
// 渲染时间监控
const measureRenderTime = useCallback(() => {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
if (entry.entryType === 'measure' && entry.name.includes('render')) {
setMetrics(prev => ({
...prev,
renderTime: Math.round(entry.duration)
}));
}
});
});
observer.observe({ entryTypes: ['measure'] });
return () => observer.disconnect();
}, []);
useEffect(() => {
// 启动性能监控
measureFPS();
const memoryInterval = setInterval(measureMemory, 5000);
const cleanupRender = measureRenderTime();
// 检测用户偏好
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
if (mediaQuery.matches) {
setShouldReduceEffects(true);
}
// 检测设备性能
if (navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4) {
setShouldReduceEffects(true);
}
// 检测电池状态
if ('getBattery' in navigator) {
(navigator as any).getBattery().then((battery: any) => {
if (battery.level < 0.2 || !battery.charging) {
setShouldReduceEffects(true);
}
});
}
return () => {
clearInterval(memoryInterval);
cleanupRender();
};
}, [measureFPS, measureMemory, measureRenderTime]);
return {
metrics,
shouldReduceEffects,
enablePerformanceMode: () => setShouldReduceEffects(true),
disablePerformanceMode: () => setShouldReduceEffects(false)
};
};
// 性能优化建议
export const getPerformanceRecommendations = (metrics: PerformanceMetrics): string[] => {
const recommendations: string[] = [];
if (metrics.fps < 30) {
recommendations.push('FPS较低建议减少动画效果');
}
if (metrics.memoryUsage && metrics.memoryUsage > 500) {
recommendations.push('内存使用较高,建议清理缓存');
}
if (metrics.renderTime > 16) {
recommendations.push('渲染时间过长,建议简化组件');
}
return recommendations;
};

View File

@@ -0,0 +1,179 @@
import { useEffect, useRef, useState } from 'react';
interface UseSectionScrollOptions {
duration?: number; // 滚动动画持续时间(毫秒)
easing?: string; // 缓动函数
}
export const useSectionScroll = (options: UseSectionScrollOptions = {}) => {
const {
duration = 1800, // 默认1.8秒
easing = 'cubic-bezier(0.4, 0, 0.2, 1)' // Apple风格缓动
} = options;
const [currentSection, setCurrentSection] = useState(0);
const [isScrolling, setIsScrolling] = useState(false);
const sectionsRef = useRef<HTMLElement[]>([]);
const touchStartY = useRef(0);
// 平滑滚动到指定section
const scrollToSection = (index: number) => {
if (index < 0 || index >= sectionsRef.current.length || isScrolling) {
return;
}
setIsScrolling(true);
const targetSection = sectionsRef.current[index];
if (targetSection) {
// 使用scrollIntoView实现平滑滚动
targetSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
setCurrentSection(index);
// 滚动完成后重置状态
setTimeout(() => {
setIsScrolling(false);
}, duration);
}
};
// 处理滚轮事件
const handleWheel = (e: WheelEvent) => {
if (isScrolling) {
e.preventDefault();
return;
}
const currentSectionElement = sectionsRef.current[currentSection];
if (!currentSectionElement) return;
// 检查滚动事件是否发生在当前section内
const target = e.target as HTMLElement;
if (!currentSectionElement.contains(target)) return;
const { scrollTop, scrollHeight, clientHeight } = currentSectionElement;
const isAtTop = scrollTop === 0;
const isAtBottom = Math.abs(scrollHeight - clientHeight - scrollTop) < 1;
// 向下滚动
if (e.deltaY > 0) {
// 只有在section底部时才阻止默认行为并切换
if (isAtBottom && currentSection < sectionsRef.current.length - 1) {
e.preventDefault();
scrollToSection(currentSection + 1);
}
// 否则允许section内部正常滚动
}
// 向上滚动
else if (e.deltaY < 0) {
// 只有在section顶部时才阻止默认行为并切换
if (isAtTop && currentSection > 0) {
e.preventDefault();
scrollToSection(currentSection - 1);
}
// 否则允许section内部正常滚动
}
};
// 处理触摸事件(移动端)
const handleTouchStart = (e: TouchEvent) => {
touchStartY.current = e.touches[0].clientY;
};
const handleTouchMove = (e: TouchEvent) => {
if (isScrolling) {
e.preventDefault();
return;
}
const currentSectionElement = sectionsRef.current[currentSection];
if (!currentSectionElement) return;
const touchEndY = e.touches[0].clientY;
const deltaY = touchStartY.current - touchEndY;
const { scrollTop, scrollHeight, clientHeight } = currentSectionElement;
const isAtTop = scrollTop === 0;
const isAtBottom = Math.abs(scrollHeight - clientHeight - scrollTop) < 1;
// 向上滑动(手指向上移动)
if (deltaY > 50) {
if (isAtBottom && currentSection < sectionsRef.current.length - 1) {
e.preventDefault();
scrollToSection(currentSection + 1);
touchStartY.current = touchEndY;
}
}
// 向下滑动(手指向下移动)
else if (deltaY < -50) {
if (isAtTop && currentSection > 0) {
e.preventDefault();
scrollToSection(currentSection - 1);
touchStartY.current = touchEndY;
}
}
};
// 处理键盘事件
const handleKeyDown = (e: KeyboardEvent) => {
if (isScrolling) return;
switch (e.key) {
case 'ArrowDown':
case 'PageDown':
if (currentSection < sectionsRef.current.length - 1) {
e.preventDefault();
scrollToSection(currentSection + 1);
}
break;
case 'ArrowUp':
case 'PageUp':
if (currentSection > 0) {
e.preventDefault();
scrollToSection(currentSection - 1);
}
break;
case 'Home':
e.preventDefault();
scrollToSection(0);
break;
case 'End':
e.preventDefault();
scrollToSection(sectionsRef.current.length - 1);
break;
}
};
useEffect(() => {
// 绑定事件监听
window.addEventListener('wheel', handleWheel, { passive: false });
window.addEventListener('touchstart', handleTouchStart, { passive: false });
window.addEventListener('touchmove', handleTouchMove, { passive: false });
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('wheel', handleWheel);
window.removeEventListener('touchstart', handleTouchStart);
window.removeEventListener('touchmove', handleTouchMove);
window.removeEventListener('keydown', handleKeyDown);
};
}, [currentSection, isScrolling]);
// 注册section元素
const registerSection = (element: HTMLElement | null, index: number) => {
if (element) {
sectionsRef.current[index] = element;
}
};
return {
currentSection,
scrollToSection,
registerSection,
isScrolling
};
};

View File

@@ -0,0 +1,624 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=Rajdhani:wght@300;400;500;600;700&display=swap');
body {
@apply bg-cyber-dark-900 text-cyber-dark-100;
font-family: 'Orbitron', 'Rajdhani', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
overflow-x: hidden;
}
/* 全局隐藏滚动条 */
html {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
html::-webkit-scrollbar {
display: none; /* Chrome, Safari and Opera */
}
}
@layer components {
/* 赛博朋克玻璃态效果 */
.glass-effect {
@apply backdrop-blur-xl backdrop-saturate-150;
background: linear-gradient(135deg,
rgba(244, 63, 94, 0.1) 0%,
rgba(168, 85, 247, 0.05) 50%,
rgba(6, 182, 212, 0.1) 100%
);
border: 1px solid rgba(244, 63, 94, 0.3);
box-shadow:
0 8px 32px rgba(244, 63, 94, 0.2),
0 0 80px rgba(168, 85, 247, 0.1),
inset 0 0 20px rgba(244, 63, 94, 0.05);
}
.glass-effect-hover {
@apply transition-all duration-300;
}
.glass-effect-hover:hover {
background: linear-gradient(135deg,
rgba(244, 63, 94, 0.15) 0%,
rgba(168, 85, 247, 0.08) 50%,
rgba(6, 182, 212, 0.15) 100%
);
border-color: rgba(244, 63, 94, 0.5);
box-shadow:
0 12px 48px rgba(244, 63, 94, 0.3),
0 0 120px rgba(168, 85, 247, 0.2),
inset 0 0 30px rgba(244, 63, 94, 0.08);
transform: translateY(-2px);
}
/* 霓虹文字效果 */
.neon-text {
text-shadow:
0 0 10px currentColor,
0 0 20px currentColor,
0 0 40px currentColor,
0 0 80px currentColor;
animation: neon-pulse 2s ease-in-out infinite alternate;
}
.neon-text-pink {
@apply text-cyber-pink-400;
text-shadow:
0 0 10px #f43f5e,
0 0 20px #f43f5e,
0 0 40px #f43f5e,
0 0 80px #f43f5e;
}
.neon-text-purple {
@apply text-neon-purple-400;
text-shadow:
0 0 10px #a855f7,
0 0 20px #a855f7,
0 0 40px #a855f7,
0 0 80px #a855f7;
}
.neon-text-cyan {
@apply text-neon-cyan-400;
text-shadow:
0 0 10px #06b6d4,
0 0 20px #06b6d4,
0 0 40px #06b6d4,
0 0 80px #06b6d4;
}
/* 霓虹边框 */
.neon-border {
position: relative;
border: 2px solid transparent;
background: linear-gradient(#0a0a0a, #0a0a0a) padding-box,
linear-gradient(45deg, #f43f5e, #a855f7, #06b6d4) border-box;
}
.neon-border::before {
content: '';
position: absolute;
inset: -2px;
background: linear-gradient(45deg, #f43f5e, #a855f7, #06b6d4);
border-radius: inherit;
opacity: 0.5;
filter: blur(10px);
z-index: -1;
animation: neon-border-pulse 3s ease-in-out infinite;
}
/* 赛博朋克按钮 */
.cyber-button {
@apply relative px-6 py-3 font-bold text-cyber-dark-100 uppercase tracking-wider;
background: linear-gradient(45deg, rgba(244, 63, 94, 0.2), rgba(168, 85, 247, 0.2));
border: 1px solid rgba(244, 63, 94, 0.5);
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 30%, 100% 100%, 10px 100%, 0 70%);
transition: all 0.3s ease;
}
.cyber-button:hover {
background: linear-gradient(45deg, rgba(244, 63, 94, 0.4), rgba(168, 85, 247, 0.4));
border-color: rgba(244, 63, 94, 0.8);
box-shadow:
0 0 20px rgba(244, 63, 94, 0.5),
0 0 40px rgba(168, 85, 247, 0.3),
inset 0 0 20px rgba(244, 63, 94, 0.2);
transform: translateY(-2px);
}
.cyber-button::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #f43f5e, transparent);
animation: scan 2s linear infinite;
}
/* 故障文字效果 */
.glitch-text {
position: relative;
color: #fff;
font-weight: bold;
}
.glitch-text::before,
.glitch-text::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glitch-text::before {
animation: glitch-1 0.5s infinite;
color: #f43f5e;
z-index: -1;
}
.glitch-text::after {
animation: glitch-2 0.5s infinite;
color: #06b6d4;
z-index: -2;
}
/* 赛博朋克卡片 */
.cyber-card {
@apply relative overflow-hidden;
background: linear-gradient(135deg,
rgba(10, 10, 10, 0.9) 0%,
rgba(23, 23, 23, 0.8) 100%
);
border: 1px solid rgba(244, 63, 94, 0.3);
box-shadow:
0 0 30px rgba(244, 63, 94, 0.2),
inset 0 0 20px rgba(168, 85, 247, 0.05);
}
.cyber-card::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #f43f5e, #a855f7, #06b6d4, #3b82f6);
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
filter: blur(10px);
}
.cyber-card:hover::before {
opacity: 0.5;
}
/* 扫描线效果 */
.scan-lines::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
pointer-events: none;
}
/* 数据流动画 */
.data-stream {
background: linear-gradient(90deg,
transparent,
rgba(244, 63, 94, 0.5),
rgba(168, 85, 247, 0.5),
rgba(6, 182, 212, 0.5),
transparent
);
background-size: 200% 100%;
animation: data-flow 3s linear infinite;
}
}
@layer utilities {
/* 霓虹发光工具类 */
.neon-glow-pink {
filter: drop-shadow(0 0 10px #f43f5e) drop-shadow(0 0 20px #f43f5e);
}
.neon-glow-purple {
filter: drop-shadow(0 0 10px #a855f7) drop-shadow(0 0 20px #a855f7);
}
.neon-glow-cyan {
filter: drop-shadow(0 0 10px #06b6d4) drop-shadow(0 0 20px #06b6d4);
}
.neon-glow-blue {
filter: drop-shadow(0 0 10px #3b82f6) drop-shadow(0 0 20px #3b82f6);
}
/* 文字渐变 */
.gradient-text {
@apply bg-gradient-to-r from-cyber-pink-400 via-neon-purple-400 to-neon-cyan-400 bg-clip-text text-transparent;
}
.gradient-text-reverse {
@apply bg-gradient-to-l from-cyber-pink-400 via-neon-purple-400 to-neon-cyan-400 bg-clip-text text-transparent;
}
}
/* 自定义动画 */
@keyframes neon-pulse {
0%, 100% {
opacity: 1;
filter: brightness(1);
}
50% {
opacity: 0.8;
filter: brightness(1.2);
}
}
@keyframes neon-border-pulse {
0%, 100% {
opacity: 0.5;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.02);
}
}
@keyframes glitch-1 {
0%, 100% {
clip-path: inset(0 0 0 0);
transform: translate(0);
}
20% {
clip-path: inset(20% 0 60% 0);
transform: translate(-2px, 2px);
}
40% {
clip-path: inset(40% 0 40% 0);
transform: translate(2px, -2px);
}
60% {
clip-path: inset(60% 0 20% 0);
transform: translate(-2px, -2px);
}
80% {
clip-path: inset(80% 0 10% 0);
transform: translate(2px, 2px);
}
}
@keyframes glitch-2 {
0%, 100% {
clip-path: inset(0 0 0 0);
transform: translate(0);
}
20% {
clip-path: inset(80% 0 10% 0);
transform: translate(2px, -2px);
}
40% {
clip-path: inset(60% 0 20% 0);
transform: translate(-2px, 2px);
}
60% {
clip-path: inset(40% 0 40% 0);
transform: translate(2px, 2px);
}
80% {
clip-path: inset(20% 0 60% 0);
transform: translate(-2px, -2px);
}
}
@keyframes scan {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes data-flow {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
/* 增强的网格样式 - 更好的可见性 */
.cyberpunk-grid {
will-change: auto;
animation: grid-move 30s linear infinite;
position: relative;
}
.cyberpunk-grid::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(180deg,
transparent 0%,
rgba(6, 182, 212, 0.1) 50%,
transparent 100%
);
pointer-events: none;
}
@keyframes grid-move {
0% {
background-position: 0 0;
}
100% {
background-position: 50px 50px;
}
}
/* 优化的霓虹光束 */
.neon-beam {
position: absolute;
height: 1px;
width: 200%;
left: -50%;
background: linear-gradient(90deg, transparent, #f43f5e, transparent);
box-shadow: 0 0 10px #f43f5e;
transform: translateX(-100%);
animation: beam-move 8s linear infinite;
}
.neon-beam-1 {
top: 20%;
animation-delay: 0s;
}
.neon-beam-2 {
top: 50%;
background: linear-gradient(90deg, transparent, #a855f7, transparent);
box-shadow: 0 0 10px #a855f7;
animation-delay: 2.5s;
animation-duration: 10s;
}
.neon-beam-3 {
top: 80%;
background: linear-gradient(90deg, transparent, #06b6d4, transparent);
box-shadow: 0 0 10px #06b6d4;
animation-delay: 5s;
animation-duration: 12s;
}
@keyframes beam-move {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
/* 优化的数据雨 */
.data-rain-container {
position: absolute;
inset: 0;
}
.data-rain-column {
position: absolute;
width: 2px;
height: 150px;
background: linear-gradient(180deg,
transparent 0%,
rgba(6, 182, 212, 0.4) 20%,
rgba(244, 63, 94, 0.8) 40%,
rgba(168, 85, 247, 1) 50%,
rgba(244, 63, 94, 0.8) 60%,
rgba(6, 182, 212, 0.4) 80%,
transparent 100%
);
filter: blur(0.8px);
box-shadow:
0 0 10px rgba(244, 63, 94, 0.6),
0 0 20px rgba(168, 85, 247, 0.4);
animation: rain-fall 10s linear infinite;
will-change: transform;
}
@keyframes rain-fall {
0% {
transform: translateY(-100px);
}
100% {
transform: translateY(100vh);
}
}
/* 日文字符数据雨样式 - 黑客帝国风格 */
.data-rain-column-text {
position: absolute;
writing-mode: vertical-rl;
text-orientation: upright;
line-height: 1.1;
letter-spacing: 0;
animation: matrix-fall linear infinite;
transform: translateZ(0);
}
.data-rain-column-text span {
color: #00ff41;
text-shadow:
0 0 3px #00ff41,
0 0 8px rgba(0, 255, 65, 0.8);
transition: all 0.5s ease;
}
/* 最亮的字符(头部) */
.data-rain-column-text span:first-child {
color: #ffffff;
text-shadow:
0 0 10px #ffffff,
0 0 20px #00ff41,
0 0 30px #00ff41;
}
/* 渐变效果 */
.data-rain-column-text span:nth-child(2) {
color: #b3ffb3;
text-shadow:
0 0 5px #b3ffb3,
0 0 10px rgba(0, 255, 65, 0.6);
}
.data-rain-column-text span:nth-child(3) {
color: #66ff66;
text-shadow:
0 0 4px #66ff66,
0 0 8px rgba(0, 255, 65, 0.5);
}
.data-rain-column-text span:nth-child(n+10) {
color: #00cc33;
opacity: 0.8;
text-shadow: 0 0 2px rgba(0, 255, 65, 0.4);
}
.data-rain-column-text span:nth-child(n+20) {
color: #009926;
opacity: 0.4;
text-shadow: 0 0 1px rgba(0, 255, 65, 0.2);
}
.data-rain-column-text span:nth-child(n+30) {
color: #006619;
opacity: 0.2;
text-shadow: none;
}
@keyframes matrix-fall {
0% {
transform: translateY(-100%);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(100vh);
opacity: 0;
}
}
/* 优化的故障效果 */
.glitch-overlay {
background: repeating-linear-gradient(
0deg,
rgba(244, 63, 94, 0.03),
rgba(244, 63, 94, 0.03) 2px,
transparent 2px,
transparent 4px
);
animation: glitch-simple 0.1s 2;
}
@keyframes glitch-simple {
0%, 100% {
transform: translate(0);
}
50% {
transform: translate(1px, -1px);
}
}
/* CRT效果优化 */
.crt-effect {
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
opacity: 0.3;
pointer-events: none;
}
/* 性能优化启用GPU加速 */
.gpu-accelerated {
transform: translateZ(0);
will-change: auto;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
/* 减少动画开销 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 优化悬浮效果 */
.optimized-hover {
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: auto;
}
.optimized-hover:hover {
will-change: transform, box-shadow;
}
/*/* 隐藏滚动条 */
::-webkit-scrollbar {
display: none;
}
/* 对于Firefox */
* {
scrollbar-width: none;
}
/* 对于IE和Edge */
body {
-ms-overflow-style: none;
}
/* 选中文本样式 */
::selection {
background: rgba(244, 63, 94, 0.5);
color: #fff;
text-shadow: 0 0 10px rgba(244, 63, 94, 0.8);
}
::-moz-selection {
background: rgba(244, 63, 94, 0.5);
color: #fff;
text-shadow: 0 0 10px rgba(244, 63, 94, 0.8);
}

667
src/index.css Normal file
View File

@@ -0,0 +1,667 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=Rajdhani:wght@300;400;500;600;700&display=swap');
body {
@apply bg-cyber-dark-900 text-cyber-dark-100;
font-family: 'Orbitron', 'Rajdhani', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
overflow-x: hidden;
}
/* 全局隐藏滚动条 */
html {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
html::-webkit-scrollbar {
display: none; /* Chrome, Safari and Opera */
}
}
@layer components {
/* 赛博朋克玻璃态效果 */
.glass-effect {
@apply backdrop-blur-xl backdrop-saturate-150;
background: linear-gradient(135deg,
rgba(244, 63, 94, 0.1) 0%,
rgba(168, 85, 247, 0.05) 50%,
rgba(6, 182, 212, 0.1) 100%
);
border: 1px solid rgba(244, 63, 94, 0.3);
box-shadow:
0 8px 32px rgba(244, 63, 94, 0.2),
0 0 80px rgba(168, 85, 247, 0.1),
inset 0 0 20px rgba(244, 63, 94, 0.05);
}
.glass-effect-hover {
@apply transition-all duration-300;
}
.glass-effect-hover:hover {
background: linear-gradient(135deg,
rgba(244, 63, 94, 0.15) 0%,
rgba(168, 85, 247, 0.08) 50%,
rgba(6, 182, 212, 0.15) 100%
);
border-color: rgba(244, 63, 94, 0.5);
box-shadow:
0 12px 48px rgba(244, 63, 94, 0.3),
0 0 120px rgba(168, 85, 247, 0.2),
inset 0 0 30px rgba(244, 63, 94, 0.08);
transform: translateY(-2px);
}
/* 霓虹文字效果 */
.neon-text {
text-shadow:
0 0 10px currentColor,
0 0 20px currentColor,
0 0 40px currentColor,
0 0 80px currentColor;
animation: neon-pulse 2s ease-in-out infinite alternate;
}
.neon-text-pink {
@apply text-cyber-pink-400;
text-shadow:
0 0 10px #f43f5e,
0 0 20px #f43f5e,
0 0 40px #f43f5e,
0 0 80px #f43f5e;
}
.neon-text-purple {
@apply text-neon-purple-400;
text-shadow:
0 0 10px #a855f7,
0 0 20px #a855f7,
0 0 40px #a855f7,
0 0 80px #a855f7;
}
.neon-text-cyan {
@apply text-neon-cyan-400;
text-shadow:
0 0 10px #06b6d4,
0 0 20px #06b6d4,
0 0 40px #06b6d4,
0 0 80px #06b6d4;
}
/* 霓虹边框 */
.neon-border {
position: relative;
border: 2px solid transparent;
background: linear-gradient(#0a0a0a, #0a0a0a) padding-box,
linear-gradient(45deg, #f43f5e, #a855f7, #06b6d4) border-box;
}
.neon-border::before {
content: '';
position: absolute;
inset: -2px;
background: linear-gradient(45deg, #f43f5e, #a855f7, #06b6d4);
border-radius: inherit;
opacity: 0.5;
filter: blur(10px);
z-index: -1;
animation: neon-border-pulse 3s ease-in-out infinite;
}
/* 赛博朋克按钮 */
.cyber-button {
@apply relative px-6 py-3 font-bold text-cyber-dark-100 uppercase tracking-wider;
background: linear-gradient(45deg, rgba(244, 63, 94, 0.2), rgba(168, 85, 247, 0.2));
border: 1px solid rgba(244, 63, 94, 0.5);
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 30%, 100% 100%, 10px 100%, 0 70%);
transition: all 0.3s ease;
}
.cyber-button:hover {
background: linear-gradient(45deg, rgba(244, 63, 94, 0.4), rgba(168, 85, 247, 0.4));
border-color: rgba(244, 63, 94, 0.8);
box-shadow:
0 0 20px rgba(244, 63, 94, 0.5),
0 0 40px rgba(168, 85, 247, 0.3),
inset 0 0 20px rgba(244, 63, 94, 0.2);
transform: translateY(-2px);
}
.cyber-button::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #f43f5e, transparent);
animation: scan 2s linear infinite;
}
/* 故障文字效果 */
.glitch-text {
position: relative;
color: #fff;
font-weight: bold;
}
.glitch-text::before,
.glitch-text::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glitch-text::before {
animation: glitch-1 0.5s infinite;
color: #f43f5e;
z-index: -1;
}
.glitch-text::after {
animation: glitch-2 0.5s infinite;
color: #06b6d4;
z-index: -2;
}
/* 赛博朋克卡片 */
.cyber-card {
@apply relative overflow-hidden;
background: linear-gradient(135deg,
rgba(10, 10, 10, 0.9) 0%,
rgba(23, 23, 23, 0.8) 100%
);
border: 1px solid rgba(244, 63, 94, 0.3);
box-shadow:
0 0 30px rgba(244, 63, 94, 0.2),
inset 0 0 20px rgba(168, 85, 247, 0.05);
}
.cyber-card::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #f43f5e, #a855f7, #06b6d4, #3b82f6);
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
filter: blur(10px);
}
.cyber-card:hover::before {
opacity: 0.5;
}
/* 扫描线效果 */
.scan-lines::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
pointer-events: none;
}
/* 数据流动画 */
.data-stream {
background: linear-gradient(90deg,
transparent,
rgba(244, 63, 94, 0.5),
rgba(168, 85, 247, 0.5),
rgba(6, 182, 212, 0.5),
transparent
);
background-size: 200% 100%;
animation: data-flow 3s linear infinite;
}
}
@layer utilities {
/* 霓虹发光工具类 */
.neon-glow-pink {
filter: drop-shadow(0 0 10px #f43f5e) drop-shadow(0 0 20px #f43f5e);
}
.neon-glow-purple {
filter: drop-shadow(0 0 10px #a855f7) drop-shadow(0 0 20px #a855f7);
}
.neon-glow-cyan {
filter: drop-shadow(0 0 10px #06b6d4) drop-shadow(0 0 20px #06b6d4);
}
.neon-glow-blue {
filter: drop-shadow(0 0 10px #3b82f6) drop-shadow(0 0 20px #3b82f6);
}
/* 文字渐变 */
.gradient-text {
@apply bg-gradient-to-r from-cyber-pink-400 via-neon-purple-400 to-neon-cyan-400 bg-clip-text text-transparent;
}
.gradient-text-reverse {
@apply bg-gradient-to-l from-cyber-pink-400 via-neon-purple-400 to-neon-cyan-400 bg-clip-text text-transparent;
}
}
/* 自定义动画 */
@keyframes neon-pulse {
0%, 100% {
opacity: 1;
filter: brightness(1);
}
50% {
opacity: 0.8;
filter: brightness(1.2);
}
}
@keyframes neon-border-pulse {
0%, 100% {
opacity: 0.5;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.02);
}
}
@keyframes glitch-1 {
0%, 100% {
clip-path: inset(0 0 0 0);
transform: translate(0);
}
20% {
clip-path: inset(20% 0 60% 0);
transform: translate(-2px, 2px);
}
40% {
clip-path: inset(40% 0 40% 0);
transform: translate(2px, -2px);
}
60% {
clip-path: inset(60% 0 20% 0);
transform: translate(-2px, -2px);
}
80% {
clip-path: inset(80% 0 10% 0);
transform: translate(2px, 2px);
}
}
@keyframes glitch-2 {
0%, 100% {
clip-path: inset(0 0 0 0);
transform: translate(0);
}
20% {
clip-path: inset(80% 0 10% 0);
transform: translate(2px, -2px);
}
40% {
clip-path: inset(60% 0 20% 0);
transform: translate(-2px, 2px);
}
60% {
clip-path: inset(40% 0 40% 0);
transform: translate(2px, 2px);
}
80% {
clip-path: inset(20% 0 60% 0);
transform: translate(-2px, -2px);
}
}
@keyframes scan {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes data-flow {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
/* 增强的网格样式 - 更好的可见性 */
.cyberpunk-grid {
will-change: auto;
animation: grid-move 30s linear infinite;
position: relative;
}
.cyberpunk-grid::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(180deg,
transparent 0%,
rgba(6, 182, 212, 0.1) 50%,
transparent 100%
);
pointer-events: none;
}
@keyframes grid-move {
0% {
background-position: 0 0;
}
100% {
background-position: 50px 50px;
}
}
/* 优化的霓虹光束 */
.neon-beam {
position: absolute;
height: 1px;
width: 200%;
left: -50%;
background: linear-gradient(90deg, transparent, #f43f5e, transparent);
box-shadow: 0 0 10px #f43f5e;
transform: translateX(-100%);
animation: beam-move 8s linear infinite;
}
.neon-beam-1 {
top: 20%;
animation-delay: 0s;
}
.neon-beam-2 {
top: 50%;
background: linear-gradient(90deg, transparent, #a855f7, transparent);
box-shadow: 0 0 10px #a855f7;
animation-delay: 2.5s;
animation-duration: 10s;
}
.neon-beam-3 {
top: 80%;
background: linear-gradient(90deg, transparent, #06b6d4, transparent);
box-shadow: 0 0 10px #06b6d4;
animation-delay: 5s;
animation-duration: 12s;
}
@keyframes beam-move {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
/* 优化的数据雨 */
.data-rain-container {
position: absolute;
inset: 0;
}
.data-rain-column {
position: absolute;
width: 2px;
height: 150px;
background: linear-gradient(180deg,
transparent 0%,
rgba(6, 182, 212, 0.4) 20%,
rgba(244, 63, 94, 0.8) 40%,
rgba(168, 85, 247, 1) 50%,
rgba(244, 63, 94, 0.8) 60%,
rgba(6, 182, 212, 0.4) 80%,
transparent 100%
);
filter: blur(0.8px);
box-shadow:
0 0 10px rgba(244, 63, 94, 0.6),
0 0 20px rgba(168, 85, 247, 0.4);
animation: rain-fall 10s linear infinite;
will-change: transform;
}
@keyframes rain-fall {
0% {
transform: translateY(-100px);
}
100% {
transform: translateY(100vh);
}
}
/* 日文字符数据雨样式 - 黑客帝国风格 */
.data-rain-column-text {
position: absolute;
writing-mode: vertical-rl;
text-orientation: upright;
line-height: 1.1;
letter-spacing: 0;
animation: matrix-fall linear infinite;
transform: translateZ(0);
}
.data-rain-column-text span {
color: #00ff41;
text-shadow:
0 0 3px #00ff41,
0 0 8px rgba(0, 255, 65, 0.8);
transition: all 0.5s ease;
}
/* 最亮的字符(头部) */
.data-rain-column-text span:first-child {
color: #ffffff;
text-shadow:
0 0 10px #ffffff,
0 0 20px #00ff41,
0 0 30px #00ff41;
}
/* 渐变效果 */
.data-rain-column-text span:nth-child(2) {
color: #b3ffb3;
text-shadow:
0 0 5px #b3ffb3,
0 0 10px rgba(0, 255, 65, 0.6);
}
.data-rain-column-text span:nth-child(3) {
color: #66ff66;
text-shadow:
0 0 4px #66ff66,
0 0 8px rgba(0, 255, 65, 0.5);
}
.data-rain-column-text span:nth-child(n+10) {
color: #00cc33;
opacity: 0.8;
text-shadow: 0 0 2px rgba(0, 255, 65, 0.4);
}
.data-rain-column-text span:nth-child(n+20) {
color: #009926;
opacity: 0.4;
text-shadow: 0 0 1px rgba(0, 255, 65, 0.2);
}
.data-rain-column-text span:nth-child(n+30) {
color: #006619;
opacity: 0.2;
text-shadow: none;
}
@keyframes matrix-fall {
0% {
transform: translateY(-100%);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(100vh);
opacity: 0;
}
}
/* 优化的故障效果 */
.glitch-overlay {
background: repeating-linear-gradient(
0deg,
rgba(244, 63, 94, 0.03),
rgba(244, 63, 94, 0.03) 2px,
transparent 2px,
transparent 4px
);
animation: glitch-simple 0.1s 2;
}
@keyframes glitch-simple {
0%, 100% {
transform: translate(0);
}
50% {
transform: translate(1px, -1px);
}
}
/* CRT效果优化 */
.crt-effect {
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
opacity: 0.3;
pointer-events: none;
}
/* 性能优化启用GPU加速 */
.gpu-accelerated {
transform: translateZ(0);
will-change: auto;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
/* 减少动画开销 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 优化悬浮效果 */
.optimized-hover {
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: auto;
}
.optimized-hover:hover {
will-change: transform, box-shadow;
}
/*/* 隐藏滚动条 */
::-webkit-scrollbar {
display: none;
}
/* 对于Firefox */
* {
scrollbar-width: none;
}
/* 对于IE和Edge */
body {
-ms-overflow-style: none;
}
/* 选中文本样式 */
::selection {
background: rgba(244, 63, 94, 0.5);
color: #fff;
text-shadow: 0 0 10px rgba(244, 63, 94, 0.8);
}
::-moz-selection {
background: rgba(244, 63, 94, 0.5);
color: #fff;
text-shadow: 0 0 10px rgba(244, 63, 94, 0.8);
}
/* Section Scroll 平滑全屏滚动效果 */
.section-scroll-container {
height: 100vh;
overflow: hidden;
position: relative;
}
.section-scroll-item {
min-height: 100vh;
max-height: 100vh;
overflow-y: auto;
overflow-x: hidden;
position: relative;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch; /* iOS平滑滚动 */
}
/* 隐藏section内部滚动条 */
.section-scroll-item::-webkit-scrollbar {
display: none; /* Chrome, Safari, Edge */
}
/* Firefox隐藏滚动条 */
.section-scroll-item {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
/* 隐藏横向滚动条 */
.scrollbar-hide {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
.scrollbar-hide::-webkit-scrollbar {
display: none; /* Chrome, Safari, Edge */
}
/* 模糊效果 */
.blur-sm {
filter: blur(2px);
}

13
src/index.tsx Normal file
View File

@@ -0,0 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

1142
src/pages/CoursePage.tsx Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1156
src/pages/HomePage.tsx Normal file

File diff suppressed because it is too large Load Diff

175
src/styles/optimized.css Normal file
View File

@@ -0,0 +1,175 @@
/* 优化后的赛博朋克样式 - 减少性能开销 */
/* 禁用过度的文字阴影效果 */
.neon-text-optimized {
color: #f43f5e;
text-shadow: 0 0 10px rgba(244, 63, 94, 0.5);
}
.neon-text-purple-optimized {
color: #a855f7;
text-shadow: 0 0 10px rgba(168, 85, 247, 0.5);
}
.neon-text-cyan-optimized {
color: #06b6d4;
text-shadow: 0 0 10px rgba(6, 182, 212, 0.5);
}
/* 简化的玻璃效果 */
.glass-effect-optimized {
background: rgba(10, 10, 10, 0.8);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(244, 63, 94, 0.2);
}
/* 优化的卡片悬浮效果 */
.cyber-card-optimized {
background: linear-gradient(135deg,
rgba(10, 10, 10, 0.9) 0%,
rgba(23, 23, 23, 0.8) 100%
);
border: 1px solid rgba(244, 63, 94, 0.2);
transition: transform 0.2s ease, border-color 0.2s ease;
}
.cyber-card-optimized:hover {
transform: translateY(-2px);
border-color: rgba(244, 63, 94, 0.4);
}
/* 简化的按钮样式 */
.cyber-button-optimized {
background: linear-gradient(45deg, rgba(244, 63, 94, 0.8), rgba(168, 85, 247, 0.8));
border: none;
color: white;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: transform 0.2s ease, box-shadow 0.2s ease;
text-transform: uppercase;
letter-spacing: 1px;
}
.cyber-button-optimized:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(244, 63, 94, 0.3);
}
/* 限制动画范围 */
@media screen and (max-width: 768px) {
/* 移动端禁用复杂动画 */
.neon-beam,
.data-rain-column,
.glitch-overlay {
animation: none !important;
display: none;
}
/* 简化背景 */
.cyberpunk-grid {
animation: none;
opacity: 0.2;
}
/* 减少模糊效果 */
.glass-effect-optimized {
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
}
}
/* 性能模式 - 自动检测低端设备 */
@media (prefers-reduced-motion: reduce),
(max-device-memory: 2GB),
(max-device-width: 640px) {
/* 禁用所有动画 */
*,
*::before,
*::after {
animation-play-state: paused !important;
transition: none !important;
}
/* 禁用模糊效果 */
.glass-effect-optimized,
.cyber-card-optimized {
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: rgba(10, 10, 10, 0.95);
}
/* 禁用阴影 */
* {
box-shadow: none !important;
text-shadow: none !important;
}
}
/* 懒加载占位符 */
.lazy-load-placeholder {
background: linear-gradient(90deg,
rgba(244, 63, 94, 0.1) 0%,
rgba(168, 85, 247, 0.1) 50%,
rgba(244, 63, 94, 0.1) 100%
);
animation: lazy-pulse 2s ease-in-out infinite;
}
@keyframes lazy-pulse {
0%, 100% { opacity: 0.5; }
50% { opacity: 0.8; }
}
/* 优化滚动性能 */
.scroll-optimized {
will-change: auto;
contain: layout style paint;
}
.scroll-optimized:hover {
will-change: transform;
}
/* 使用CSS Grid替代复杂布局 */
.grid-optimized {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
contain: layout;
}
/* 图片优化 */
img {
content-visibility: auto;
contain-intrinsic-size: 400px 300px;
}
/* 字体优化 */
@font-face {
font-family: 'Orbitron';
font-display: swap; /* 防止字体加载阻塞 */
src: local('Orbitron'), url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700&display=swap');
}
/* 优化的渐变文字 */
.gradient-text-optimized {
background: linear-gradient(90deg, #f43f5e, #a855f7);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
/* 移除动画避免重绘 */
}
/* 硬件加速优化类 */
.hw-accelerated {
transform: translate3d(0, 0, 0);
will-change: auto;
}
/* 减少重排的布局 */
.layout-optimized {
contain: layout;
content-visibility: auto;
}

View File

@@ -0,0 +1,92 @@
export interface CourseChapter {
id: string;
path: string;
title: string;
description: string;
}
export const courseChapters: CourseChapter[] = [
{
id: 'automation-industry',
path: '/course/automation-industry',
title: '多Agent系统基础理论',
description: '了解多Agent系统的基本概念与发展历程'
},
{
id: 'plc-basics',
path: '/course/plc-basics',
title: '多Agent系统架构模式',
description: '掌握四种主要架构模式的特点与应用'
},
{
id: 'multi-agent-basics',
path: '/course/multi-agent-basics',
title: '多Agent系统基础架构',
description: '深入理解多Agent系统的核心架构'
},
{
id: 'agent-role-design',
path: '/course/agent-role-design',
title: 'Agent角色设计',
description: '学习Agent角色的专业化分工策略'
},
{
id: 'communication-mechanism',
path: '/course/communication-mechanism',
title: 'Agent间通信机制',
description: '掌握Agent间的通信协议与信息交换'
},
{
id: 'collaboration-management',
path: '/course/collaboration-management',
title: '协作管理与任务分配',
description: '学习协作策略和任务分配机制'
},
{
id: 'central-coordination',
path: '/course/central-coordination',
title: '中央协调与管理',
description: '理解中央协调器的设计与实现'
},
{
id: 'application-architecture',
path: '/course/application-architecture',
title: '实际应用架构',
description: '掌握三大典型应用架构设计'
},
{
id: 'a2a-protocol',
path: '/course/a2a-protocol',
title: 'A2A协议与标准化实践',
description: '学习谷歌A2A协议的前沿实践'
},
{
id: 'program-development',
path: '/course/program-development',
title: '关键角色职责图谱',
description: '理解系统中各角色的职责分工'
}
];
export const getChapterNavigation = (currentPath: string) => {
const currentIndex = courseChapters.findIndex(chapter => chapter.path === currentPath);
if (currentIndex === -1) {
return { prev: null, next: null };
}
const prev = currentIndex > 0 ? courseChapters[currentIndex - 1] : null;
const next = currentIndex < courseChapters.length - 1 ? courseChapters[currentIndex + 1] : null;
return { prev, next };
};
export const getNextChapter = (currentPath: string): CourseChapter | null => {
const { next } = getChapterNavigation(currentPath);
return next;
};
export const getPrevChapter = (currentPath: string): CourseChapter | null => {
const { prev } = getChapterNavigation(currentPath);
return prev;
};

View File

@@ -0,0 +1,86 @@
// 性能配置文件
export const performanceConfig = {
// 动画配置
animation: {
// 减少动画持续时间
duration: {
fast: 0.2,
normal: 0.3,
slow: 0.5
},
// 简化的弹簧配置
spring: {
light: {
type: "spring" as const,
stiffness: 300,
damping: 30
},
normal: {
type: "spring" as const,
stiffness: 200,
damping: 25
},
heavy: {
type: "spring" as const,
stiffness: 100,
damping: 20
}
}
},
// 延迟加载配置
lazyLoad: {
threshold: 0.1,
rootMargin: "50px"
},
// 减少复杂效果
effects: {
enableGlitch: false, // 默认关闭故障效果
enableParticles: false, // 关闭粒子效果
enableComplexShadows: false, // 关闭复杂阴影
reducedMotion: false // 减少动效模式
},
// 防抖和节流配置
optimization: {
debounceDelay: 300,
throttleDelay: 100,
maxAnimationElements: 20 // 限制同时动画的元素数量
}
};
// 检测用户偏好
export const detectPerformanceMode = () => {
// 检查是否偏好减少动效
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// 检查设备性能
const isLowEndDevice = navigator.hardwareConcurrency ? navigator.hardwareConcurrency < 4 : false;
// 检查连接速度
const connection = (navigator as any).connection;
const isSlowConnection = connection &&
(connection.effectiveType === 'slow-2g' ||
connection.effectiveType === '2g' ||
connection.saveData);
return {
prefersReducedMotion,
isLowEndDevice,
isSlowConnection,
shouldReduceEffects: prefersReducedMotion || isLowEndDevice || isSlowConnection
};
};
// 动画优化hook
export const useOptimizedAnimation = () => {
const { shouldReduceEffects } = detectPerformanceMode();
return {
transition: shouldReduceEffects
? { duration: 0.1 }
: performanceConfig.animation.spring.normal,
animate: shouldReduceEffects ? false : true
};
};