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

View File

@@ -0,0 +1,45 @@
{
"permissions": {
"allow": [
"mcp__serena__read_file",
"mcp__serena__activate_project",
"mcp__serena__check_onboarding_performed",
"Bash(npm start)",
"mcp__serena__search_for_pattern",
"mcp__serena__replace_regex",
"mcp__serena__list_dir",
"mcp__serena__create_text_file",
"Bash(rm:*)",
"Bash(npm run build:*)",
"mcp__serena__execute_shell_command",
"Bash(pkill:*)",
"Bash(mkdir:*)",
"Bash(cp:*)",
"Bash(git checkout:*)",
"mcp__serena__replace_symbol_body",
"mcp__serena__think_about_task_adherence",
"mcp__serena__onboarding",
"mcp__serena__write_memory",
"Bash(lsof:*)",
"Bash(PORT=3001 npm start)",
"Bash(kill:*)",
"Bash(python3:*)",
"mcp__serena__find_file",
"mcp__serena__think_about_whether_you_are_done",
"mcp__serena__read_memory",
"Bash(npx tsc:*)",
"mcp__serena__get_symbols_overview",
"Bash(grep:*)",
"Bash(find:*)",
"Bash(timeout 10 npm start)",
"Bash(npm run dev:*)",
"Bash(npm install:*)",
"Bash(npm uninstall:*)",
"Bash(git init:*)",
"Bash(git remote add:*)",
"Bash(git add:*)",
"Bash(git commit -m \"$(cat <<''EOF''\nfeat: 初始化多Agent协作系统项目并添加直播回放功能\n\n- 添加导航栏组件及直播回放按钮\n- 实现视频播放模态框\n- 配置赛博朋克风格主题\n- 添加课程首页和课程页面\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nEOF\n)\")"
],
"deny": []
}
}

35
.gitignore vendored Normal file
View File

@@ -0,0 +1,35 @@
# Dependencies
node_modules/
/.pnp
.pnp.js
# Testing
/coverage
# Production
/build
/dist
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Temporary files
*.tmp
.cache/

1
.serena/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/cache

View File

@@ -0,0 +1,60 @@
# 代码风格与约定
## TypeScript风格
- 使用TypeScript严格模式
- 接口和类型定义使用PascalCase
- 变量和函数使用camelCase
- 常量使用UPPER_SNAKE_CASE
## React约定
- 组件使用PascalCase命名
- Props接口以Props结尾 (如: HomePageProps)
- 使用函数式组件和Hooks
- 导出组件使用export default
## 文件命名
- 组件文件: PascalCase.tsx (如: HomePage.tsx)
- 工具文件: camelCase.ts
- 样式文件: kebab-case.css
## CSS/Tailwind约定
- 优先使用Tailwind CSS类
- 自定义CSS使用CSS变量
- 颜色变量遵循命名模式: --bg-*, --surf-*, --accent-*
- 响应式设计: mobile-first
## 项目特定约定
- 课程相关页面放在 pages/course/ 目录
- 图片资源放在 src/assets/images/
- 组件props解构使用
- 动画使用Framer Motion库
## 导入顺序
1. React相关导入
2. 第三方库导入
3. 本地组件导入
4. 类型导入
5. 样式导入
## 组件结构
```tsx
import React from 'react';
import { motion } from 'framer-motion';
interface ComponentProps {
// props定义
}
const Component: React.FC<ComponentProps> = ({ prop1, prop2 }) => {
// hooks
// 事件处理函数
// 渲染逻辑
return (
<motion.div>
{/* JSX */}
</motion.div>
);
};
export default Component;
```

View File

@@ -0,0 +1,40 @@
# 项目概述
## 项目目的
这是一个多Agent协作系统的教学网站项目原本是PLC教学网站现已转换为专注于IT运维风格的多Agent系统课程教学平台。
## 技术栈
- **前端框架**: React 18.2.0 + TypeScript 4.9.5
- **路由**: React Router DOM 6.20.1
- **动画库**: Framer Motion 12.19.2
- **拖拽库**: @dnd-kit/core 6.3.1, react-beautiful-dnd 13.1.1
- **样式**: Tailwind CSS 3.3.6 + 自定义CSS
- **构建工具**: React Scripts 5.0.1
## 项目结构
- `src/`
- `components/` - 可复用组件
- `pages/` - 页面组件
- `course/` - 课程相关页面
- `assets/` - 静态资源
- `public/` - 公共静态资源
- `tailwind.config.js` - Tailwind配置
- `tsconfig.json` - TypeScript配置
## 课程内容
基于课程讲义.md包含7大模块
1. 多Agent系统基础
2. Agent角色设计
3. Agent间通信机制
4. 协作与任务管理
5. 中央协调与管理
6. 实际应用架构
7. A2A协议案例讲解
## 设计风格
- IT运维风格IT风
- 深蓝主色调 (#0f172a)
- 青色辅助色 (#0891b2)
- 绿色强调色 (#10b981)
- 玻璃拟态效果
- 流畅动画交互

View File

@@ -0,0 +1,57 @@
# 建议命令
## 开发相关命令
### 启动开发服务器
```bash
npm start
```
### 构建生产版本
```bash
npm run build
```
### 运行测试
```bash
npm run test
```
### 安装依赖
```bash
npm install
```
## Git操作
```bash
git status
git add .
git commit -m "提交信息"
git push
```
## 文件查看
```bash
ls -la # 查看目录内容
find . -name "*.tsx" # 查找TypeScript文件
grep -r "搜索内容" src/ # 在src目录搜索内容
```
## 系统工具 (Darwin)
```bash
open . # 在Finder中打开当前目录
which node # 查看node路径
ps aux | grep node # 查看node进程
kill -9 <PID> # 结束进程
```
## 开发工具
- VS Code: 推荐的IDE
- Chrome DevTools: 调试工具
- React DevTools: React调试扩展
## 注意事项
- 系统为Darwin (macOS)
- 使用npm作为包管理器
- TypeScript配置严格模式
- 支持ES6+语法

View File

@@ -0,0 +1,49 @@
# 任务完成检查清单
## 编码任务完成后必须执行
### 1. 代码质量检查
- [ ] 检查TypeScript类型错误
- [ ] 确保所有组件正确导入导出
- [ ] 检查控制台错误和警告
- [ ] 验证响应式设计在不同设备上的表现
### 2. 功能测试
- [ ] 测试新功能的基本操作
- [ ] 验证路由跳转正常
- [ ] 测试动画效果流畅
- [ ] 检查交互元素响应性
### 3. 样式检查
- [ ] 验证IT运维风格主题一致性
- [ ] 检查颜色变量使用正确
- [ ] 确保玻璃拟态效果正常
- [ ] 验证Tailwind类名正确应用
### 4. 性能检查
- [ ] 检查页面加载速度
- [ ] 验证图片资源优化
- [ ] 确保不存在内存泄漏
### 5. 浏览器兼容性
- [ ] Chrome测试
- [ ] Safari测试 (Darwin系统)
- [ ] 移动端Safari测试
## 课程内容任务特定检查
### 课程页面创建
- [ ] 页面结构符合课程讲义.md内容
- [ ] 包含所有必要的学习目标
- [ ] 交互式元素功能正常
- [ ] 导航链接正确配置
### 样式更新任务
- [ ] 色彩搭配符合IT运维风格
- [ ] 动画缓动效果自然
- [ ] 响应式布局适配各设备
## 提交前最终检查
- [ ] 运行 npm start 确保应用启动正常
- [ ] 快速浏览所有页面确保无明显问题
- [ ] 检查git状态确保没有遗漏文件

68
.serena/project.yml Normal file
View File

@@ -0,0 +1,68 @@
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
# * For C, use cpp
# * For JavaScript, use typescript
# Special requirements:
# * csharp: Requires the presence of a .sln file in the project folder.
language: typescript
# whether to use the project's gitignore file to ignore files
# Added on 2025-04-07
ignore_all_files_in_gitignore: true
# list of additional paths to ignore
# same syntax as gitignore, so you can use * and **
# Was previously called `ignored_dirs`, please update your config if you are using that.
# Added (renamed)on 2025-04-07
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file or directory.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
project_name: "education_web_外贸业务的核心流程及关键角色"

Binary file not shown.

1
.yoyo/snapshot Submodule

Submodule .yoyo/snapshot added at 2a7cdd6367

100
README-教学网页.md Normal file
View File

@@ -0,0 +1,100 @@
# 外贸业务核心流程及关键角色教学网页
## 📖 项目简介
这是一个基于React和TypeScript开发的外贸业务基础课程教学网页采用现代化的玻璃风格UI设计为大专院校国际贸易专业学生提供优质的学习体验。
## 🎯 课程内容
### 核心模块
- **外贸业务全景图**:跨境交易定义、目标、发展历程及面临的关键挑战
- **外贸业务框架**:政策支持、产业链协作与服务支撑体系
- **外贸核心流程**:客户开发、风险筛查、合同签订、生产备货、物流通关、货款回收
- **关键角色职责图谱**:出口商、进口商、外贸经理、货代、银行、海关等角色定位
### 学生能力培养目标
- 掌握外贸业务全流程操作能力
- 具备客户开发与商务谈判技能
- 理解国际物流与报关操作
- 掌握外汇管理与风险控制
### 职业发展方向
- **外贸业务主管**:需求量大,发展前景好
- **外贸业务员**:入门岗位,成长空间广阔
- **物流单证员**:专业性强,薪资稳定
- **外贸跟单员**:综合能力要求高
- **国际采购助理**:供应链管理核心岗位
## 🎨 设计特色
- **现代玻璃风格UI**:采用最新的玻璃拟态设计,视觉效果现代时尚
- **响应式布局**:完美适配各种设备尺寸
- **流畅交互动画**使用Framer Motion提供丝滑的用户体验
- **渐变色彩搭配**:精心设计的色彩方案,营造专业学习氛围
## 🚀 技术栈
- **前端框架**: React 18 + TypeScript
- **样式系统**: Tailwind CSS + 自定义玻璃效果
- **动画库**: Framer Motion
- **路由管理**: React Router DOM
- **图标系统**: Lucide React
- **构建工具**: Create React App
## 📱 页面结构
### 主要页面
- **首页**: 课程概览与模块导航
- **学习目标**: 详细的能力培养目标
- **职业发展**: 外贸相关职业路径介绍
- **课程总结**: 知识点梳理与总结
- **课堂测试**: 多种题型的在线测试
### 课程章节
- **外贸业务全景图**: 跨境交易基础认知与模式分类
- **外贸业务框架**: 生态系统、政策支持与产业协作
- **外贸核心流程**: 六大核心环节详细解析
- **关键角色职责图谱**: 各角色定位与协作关系
## 🎯 教学特色
### 实践案例教学
- **智能手表出口案例**: 完整业务流程演示
- **文具出口实操**: 订单执行全流程跟踪
- **茶叶出口案例**: 国际物流与报关实务
### 互动学习体验
- **课堂测试系统**: 选择题、填空题、连线题、排序题
- **作业练习平台**: 拖拽式业务流程构建
- **进度跟踪功能**: 学习进度可视化展示
### 知识点覆盖
- B2B/B2C/C2C贸易模式对比
- 国际贸易术语与结算方式
- 跨境物流与报关实务
- 外汇管理与风险防范
- 客户开发与商务谈判
## 🔧 本地开发
```bash
# 克隆项目
git clone [repository-url]
# 安装依赖
npm install
# 启动开发服务器
npm start
# 构建生产版本
npm run build
```
## 📄 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
## 🙏 致谢
**致谢**:感谢所有为外贸教育事业贡献力量的教育工作者和行业专家!

114
README.md Normal file
View File

@@ -0,0 +1,114 @@
# Liquid Glass React
Apple's Liquid Glass effect for React.
Card Example | Button Example
:-------------------------:|:-------------------------:
![](https://github.com/rdev/liquid-glass-react/raw/master/assets/card.png) | ![](https://github.com/rdev/liquid-glass-react/raw/master/assets/button.png)
## 🎬 Demo
[Click here](https://liquid-glass.maxrovensky.com) to see it in action!
![project liquid gif](./assets/project-liquid.gif)
## ✨ Features
- Proper edgy bending and refraction
- Multiple refraction modes
- Configurable frosty level
- Supports arbitrary child elements
- Configurable paddings
- Correct hover and click effects
- Edges and highlights take on the underlying light like Apple's does
- Configurable chromatic aberration
- Configurable elasticity, to mimic Apple's "liquid" feel
> **⚠️ NOTE:** Safari and Firefox only partially support the effect (displacement will not be visible)
## 🚀 Usage
### Installation
```bash
npm install liquid-glass-react
```
### Basic Usage
```tsx
import LiquidGlass from 'liquid-glass-react'
function App() {
return (
<LiquidGlass>
<div className="p-6">
<h2>Your content here</h2>
<p>This will have the liquid glass effect</p>
</div>
</LiquidGlass>
)
}
```
### Button Example
```tsx
<LiquidGlass
displacementScale={64}
blurAmount={0.1}
saturation={130}
aberrationIntensity={2}
elasticity={0.35}
cornerRadius={100}
padding="8px 16px"
onClick={() => console.log('Button clicked!')}
>
<span className="text-white font-medium">Click Me</span>
</LiquidGlass>
```
### Mouse Container Example
When you want the glass effect to respond to mouse movement over a larger area (like a parent container), use the `mouseContainer` prop:
```tsx
function App() {
const containerRef = useRef<HTMLDivElement>(null)
return (
<div ref={containerRef} className="w-full h-screen bg-image">
<LiquidGlass
mouseContainer={containerRef}
elasticity={0.3}
style={{ position: 'fixed', top: '50%', left: '50%' }}
>
<div className="p-6">
<h2>Glass responds to mouse anywhere in the container</h2>
</div>
</LiquidGlass>
</div>
)
}
```
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode` | - | The content to render inside the glass container |
| `displacementScale` | `number` | `70` | Controls the intensity of the displacement effect |
| `blurAmount` | `number` | `0.0625` | Controls the blur/frosting level |
| `saturation` | `number` | `140` | Controls color saturation of the glass effect |
| `aberrationIntensity` | `number` | `2` | Controls chromatic aberration intensity |
| `elasticity` | `number` | `0.15` | Controls the "liquid" elastic feel (0 = rigid, higher = more elastic) |
| `cornerRadius` | `number` | `999` | Border radius in pixels |
| `className` | `string` | `""` | Additional CSS classes |
| `padding` | `string` | - | CSS padding value |
| `style` | `React.CSSProperties` | - | Additional inline styles |
| `overLight` | `boolean` | `false` | Whether the glass is over a light background |
| `onClick` | `() => void` | - | Click handler |
| `mouseContainer` | `React.RefObject<HTMLElement \| null> \| null` | `null` | Container element to track mouse movement on (defaults to the glass component itself) |
| `mode` | `"standard" \| "polar" \| "prominent" \| "shader"` | `"standard"` | Refraction mode for different visual effects. `shader` is the most accurate but not the most stable. |
| `globalMousePos` | `{ x: number; y: number }` | - | Global mouse position coordinates for manual control |
| `mouseOffset` | `{ x: number; y: number }` | - | Mouse position offset for fine-tuning positioning |

1307
install.sh Normal file

File diff suppressed because it is too large Load Diff

17687
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

52
package.json Normal file
View File

@@ -0,0 +1,52 @@
{
"name": "foreign-trade-education-web",
"version": "0.1.0",
"private": true,
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@types/node": "^16.18.68",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"framer-motion": "^12.19.2",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.1",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/jest": "^27.5.2",
"@types/react-beautiful-dnd": "^13.1.8",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6"
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

32
public/index.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="多Agent协作系统教学网页 - 现代化玻璃风格界面"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>多Agent协作系统</title>
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
</style>
</head>
<body>
<noscript>您需要启用JavaScript来运行此应用程序。</noscript>
<div id="root"></div>
</body>
</html>

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
};
};

174
tailwind.config.js Normal file
View File

@@ -0,0 +1,174 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
colors: {
// 赛博朋克主色调 - 霓虹粉紫
'cyber-pink': {
900: '#831843',
800: '#9f1239',
700: '#be123c',
600: '#e11d48',
500: '#f43f5e',
400: '#fb7185',
300: '#fda4af',
200: '#fecdd3',
100: '#ffe4e6',
50: '#fff1f2',
},
// 赛博朋克霓虹蓝
'neon-blue': {
900: '#1e3a8a',
800: '#1e40af',
700: '#1d4ed8',
600: '#2563eb',
500: '#3b82f6',
400: '#60a5fa',
300: '#93c5fd',
200: '#bfdbfe',
100: '#dbeafe',
50: '#eff6ff',
},
// 赛博朋克霓虹紫
'neon-purple': {
900: '#581c87',
800: '#6b21a8',
700: '#7c3aed',
600: '#9333ea',
500: '#a855f7',
400: '#c084fc',
300: '#d8b4fe',
200: '#e9d5ff',
100: '#f3e8ff',
50: '#faf5ff',
},
// 赛博朋克霓虹青
'neon-cyan': {
900: '#164e63',
800: '#155e75',
700: '#0e7490',
600: '#0891b2',
500: '#06b6d4',
400: '#22d3ee',
300: '#67e8f9',
200: '#a5f3fc',
100: '#cffafe',
50: '#ecfeff',
},
// 赛博朋克暗黑背景
'cyber-dark': {
950: '#030712',
900: '#0a0a0a',
800: '#171717',
700: '#262626',
600: '#404040',
500: '#525252',
400: '#737373',
300: '#a3a3a3',
200: '#d4d4d4',
100: '#f5f5f5',
50: '#fafafa',
},
// 赛博朋克霓虹黄
'neon-yellow': {
900: '#713f12',
800: '#854d0e',
700: '#a16207',
600: '#ca8a04',
500: '#eab308',
400: '#facc15',
300: '#fde047',
200: '#fef08a',
100: '#fef3c7',
50: '#fefce8',
},
// 保留旧色系用于快速迁移
base: {
50: '#E5DFD7',
800: '#8A9B8F',
900: 'color-mix(in oklab, #7A9E9F 86%, #000 14%)'
},
accent: {
500: '#D4B483'
},
'surf-tundra': {
300: '#67e8f9',
400: '#22d3ee',
500: '#06b6d4',
600: '#0891b2',
},
'accent-sand': {
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
}
},
backdropBlur: {
xs: '2px',
sm: '8px',
md: '12px',
lg: '16px',
xl: '24px',
'2xl': '40px',
},
backdropSaturate: {
150: '150%',
175: '175%',
200: '200%',
},
boxShadow: {
'neon-pink': '0 0 20px rgba(244, 63, 94, 0.5), 0 0 40px rgba(244, 63, 94, 0.3), 0 0 60px rgba(244, 63, 94, 0.1)',
'neon-blue': '0 0 20px rgba(59, 130, 246, 0.5), 0 0 40px rgba(59, 130, 246, 0.3), 0 0 60px rgba(59, 130, 246, 0.1)',
'neon-purple': '0 0 20px rgba(168, 85, 247, 0.5), 0 0 40px rgba(168, 85, 247, 0.3), 0 0 60px rgba(168, 85, 247, 0.1)',
'neon-cyan': '0 0 20px rgba(6, 182, 212, 0.5), 0 0 40px rgba(6, 182, 212, 0.3), 0 0 60px rgba(6, 182, 212, 0.1)',
'glass': '0 8px 32px rgba(0, 0, 0, 0.4), 0 0 0 0.5px rgba(255, 255, 255, 0.1) inset',
'glass-hover': '0 12px 48px rgba(0, 0, 0, 0.5), 0 0 0 0.5px rgba(255, 255, 255, 0.2) inset',
'glass-sm': '0 4px 24px rgba(0, 0, 0, 0.3), 0 0 0 0.5px rgba(255, 255, 255, 0.08) inset',
'glass-lg': '0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 0.5px rgba(255, 255, 255, 0.15) inset',
'inner-light': '0 0 0 0.5px rgba(255, 255, 255, 0.1) inset',
},
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.5s ease-out',
'pulse-slow': 'pulse 3s ease-in-out infinite',
'float': 'float 6s ease-in-out infinite',
'neon-flicker': 'neonFlicker 2s infinite alternate',
'glitch': 'glitch 1s infinite',
'scan-line': 'scanLine 8s linear infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(20px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-10px)' },
},
neonFlicker: {
'0%, 100%': { opacity: '1' },
'50%': { opacity: '0.8' },
},
glitch: {
'0%, 100%': { transform: 'translate(0)' },
'20%': { transform: 'translate(-1px, 1px)' },
'40%': { transform: 'translate(-1px, -1px)' },
'60%': { transform: 'translate(1px, 1px)' },
'80%': { transform: 'translate(1px, -1px)' },
},
scanLine: {
'0%': { transform: 'translateY(-100%)' },
'100%': { transform: 'translateY(100%)' },
}
}
},
},
plugins: [],
}

26
tsconfig.json Normal file
View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}

Some files were not shown because too many files have changed in this diff Show More