1801 lines
46 KiB
Markdown
1801 lines
46 KiB
Markdown
# Novalon 官网重新设计实施计划
|
||
|
||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||
|
||
**Goal:** 将 Novalon 官网从现有设计升级为深色科技风格的现代化企业网站
|
||
|
||
**Architecture:** 采用 Next.js 16 App Router + React 19 + TypeScript + Tailwind CSS v4 技术栈,基于组件化设计,实现深色科技风格的视觉系统和流畅的用户体验
|
||
|
||
**Tech Stack:** Next.js 16, React 19, TypeScript 5, Tailwind CSS v4, Framer Motion, AntV G2, shadcn/ui
|
||
|
||
---
|
||
|
||
## 前置准备
|
||
|
||
### Task 0: 创建开发分支
|
||
|
||
**Files:**
|
||
- None
|
||
|
||
**Step 1: 检查当前分支状态**
|
||
|
||
Run: `git status`
|
||
|
||
Expected: 工作目录干净,在 main 或 develop 分支
|
||
|
||
**Step 2: 创建新的功能分支**
|
||
|
||
Run: `git checkout -b feature/website-redesign`
|
||
|
||
Expected: 切换到新分支 feature/website-redesign
|
||
|
||
**Step 3: 推送分支到远程**
|
||
|
||
Run: `git push -u origin feature/website-redesign`
|
||
|
||
Expected: 分支推送到远程仓库
|
||
|
||
---
|
||
|
||
## 阶段一:基础架构搭建
|
||
|
||
### Task 1: 安装必要依赖
|
||
|
||
**Files:**
|
||
- Modify: `package.json`
|
||
|
||
**Step 1: 安装动画库**
|
||
|
||
Run: `npm install framer-motion`
|
||
|
||
Expected: framer-motion 安装成功
|
||
|
||
**Step 2: 安装图表库**
|
||
|
||
Run: `npm install @antv/g2`
|
||
|
||
Expected: @antv/g2 安装成功
|
||
|
||
**Step 3: 安装 CVA(如果尚未安装)**
|
||
|
||
Run: `npm install class-variance-authority`
|
||
|
||
Expected: class-variance-authority 安装成功
|
||
|
||
**Step 4: 验证安装**
|
||
|
||
Run: `npm list framer-motion @antv/g2 class-variance-authority`
|
||
|
||
Expected: 显示已安装的版本信息
|
||
|
||
**Step 5: 提交依赖更新**
|
||
|
||
Run:
|
||
```bash
|
||
git add package.json package-lock.json
|
||
git commit -m "chore: add framer-motion, @antv/g2, and class-variance-authority dependencies"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 2: 扩展 Tailwind 配置
|
||
|
||
**Files:**
|
||
- Modify: `tailwind.config.ts`(如果不存在则创建)
|
||
|
||
**Step 1: 检查 Tailwind 配置文件**
|
||
|
||
Run: `ls -la | grep tailwind`
|
||
|
||
Expected: 显示 tailwind 配置文件
|
||
|
||
**Step 2: 读取现有配置**
|
||
|
||
Read: `tailwind.config.ts`
|
||
|
||
**Step 3: 扩展配置添加深色主题色彩**
|
||
|
||
Modify: `tailwind.config.ts`
|
||
|
||
```typescript
|
||
import type { Config } from "tailwindcss";
|
||
|
||
export default {
|
||
content: [
|
||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||
],
|
||
theme: {
|
||
extend: {
|
||
colors: {
|
||
dark: {
|
||
DEFAULT: "#0A0A0A",
|
||
secondary: "#1A1A1A",
|
||
tertiary: "#2A2A2A",
|
||
},
|
||
tech: {
|
||
blue: "#00D9FF",
|
||
purple: "#A855F7",
|
||
cyan: "#06B6D4",
|
||
},
|
||
},
|
||
fontFamily: {
|
||
sans: ["Inter", "system-ui", "sans-serif"],
|
||
mono: ["JetBrains Mono", "monospace"],
|
||
},
|
||
animation: {
|
||
"fade-in-up": "fadeInUp 0.6s ease-out",
|
||
"fade-in-scale": "fadeInScale 0.6s ease-out",
|
||
glow: "glow 2s ease-in-out infinite",
|
||
float: "float 3s ease-in-out infinite",
|
||
},
|
||
keyframes: {
|
||
fadeInUp: {
|
||
"0%": { opacity: "0", transform: "translateY(20px)" },
|
||
"100%": { opacity: "1", transform: "translateY(0)" },
|
||
},
|
||
fadeInScale: {
|
||
"0%": { opacity: "0", transform: "scale(0.95)" },
|
||
"100%": { opacity: "1", transform: "scale(1)" },
|
||
},
|
||
glow: {
|
||
"0%, 100%": { boxShadow: "0 0 20px rgba(0, 217, 255, 0.3)" },
|
||
"50%": { boxShadow: "0 0 40px rgba(0, 217, 255, 0.6)" },
|
||
},
|
||
float: {
|
||
"0%, 100%": { transform: "translateY(0px)" },
|
||
"50%": { transform: "translateY(-10px)" },
|
||
},
|
||
},
|
||
},
|
||
},
|
||
plugins: [],
|
||
} satisfies Config;
|
||
```
|
||
|
||
**Step 4: 验证配置语法**
|
||
|
||
Run: `npx tsc --noEmit tailwind.config.ts`
|
||
|
||
Expected: 无错误输出
|
||
|
||
**Step 5: 提交配置更新**
|
||
|
||
Run:
|
||
```bash
|
||
git add tailwind.config.ts
|
||
git commit -m "feat: extend Tailwind config with dark theme and tech colors"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 3: 更新全局样式
|
||
|
||
**Files:**
|
||
- Modify: `src/app/globals.css`
|
||
|
||
**Step 1: 读取现有全局样式**
|
||
|
||
Read: `src/app/globals.css`
|
||
|
||
**Step 2: 添加 CSS 变量和基础样式**
|
||
|
||
Modify: `src/app/globals.css`
|
||
|
||
在文件顶部添加:
|
||
|
||
```css
|
||
:root {
|
||
--color-dark: #0A0A0A;
|
||
--color-dark-secondary: #1A1A1A;
|
||
--color-dark-tertiary: #2A2A2A;
|
||
--color-tech-blue: #00D9FF;
|
||
--color-tech-purple: #A855F7;
|
||
--color-tech-cyan: #06B6D4;
|
||
|
||
--gradient-primary: linear-gradient(135deg, #00D9FF 0%, #A855F7 100%);
|
||
--gradient-dark: linear-gradient(180deg, #0A0A0A 0%, #1A1A1A 100%);
|
||
--gradient-glow: radial-gradient(circle, #00D9FF20 0%, transparent 70%);
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
background-color: var(--color-dark);
|
||
color: #FFFFFF;
|
||
font-family: 'Inter', system-ui, sans-serif;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
a {
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
|
||
button {
|
||
font-family: inherit;
|
||
}
|
||
|
||
input, textarea {
|
||
font-family: inherit;
|
||
}
|
||
|
||
::-webkit-scrollbar {
|
||
width: 8px;
|
||
height: 8px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
background: var(--color-dark-secondary);
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
background: var(--color-tech-blue);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background: var(--color-tech-purple);
|
||
}
|
||
```
|
||
|
||
**Step 3: 验证样式文件**
|
||
|
||
Run: `npm run build`
|
||
|
||
Expected: 构建成功,无样式错误
|
||
|
||
**Step 4: 提交样式更新**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/app/globals.css
|
||
git commit -m "feat: add CSS variables and base styles for dark theme"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 4: 创建工具函数
|
||
|
||
**Files:**
|
||
- Modify: `src/lib/utils.ts`
|
||
|
||
**Step 1: 读取现有工具函数**
|
||
|
||
Read: `src/lib/utils.ts`
|
||
|
||
**Step 2: 添加新的工具函数**
|
||
|
||
Modify: `src/lib/utils.ts`
|
||
|
||
```typescript
|
||
import { type ClassValue, clsx } from "clsx";
|
||
import { twMerge } from "tailwind-merge";
|
||
|
||
export function cn(...inputs: ClassValue[]) {
|
||
return twMerge(clsx(inputs));
|
||
}
|
||
|
||
export function formatNumber(num: number): string {
|
||
return new Intl.NumberFormat("zh-CN").format(num);
|
||
}
|
||
|
||
export function formatCurrency(amount: number): string {
|
||
return new Intl.NumberFormat("zh-CN", {
|
||
style: "currency",
|
||
currency: "CNY",
|
||
}).format(amount);
|
||
}
|
||
|
||
export function debounce<T extends (...args: unknown[]) => unknown>(
|
||
func: T,
|
||
wait: number
|
||
): (...args: Parameters<T>) => void {
|
||
let timeout: NodeJS.Timeout | null = null;
|
||
return (...args: Parameters<T>) => {
|
||
if (timeout) clearTimeout(timeout);
|
||
timeout = setTimeout(() => func(...args), wait);
|
||
};
|
||
}
|
||
|
||
export function throttle<T extends (...args: unknown[]) => unknown>(
|
||
func: T,
|
||
limit: number
|
||
): (...args: Parameters<T>) => void {
|
||
let inThrottle: boolean;
|
||
return (...args: Parameters<T>) => {
|
||
if (!inThrottle) {
|
||
func(...args);
|
||
inThrottle = true;
|
||
setTimeout(() => (inThrottle = false), limit);
|
||
}
|
||
};
|
||
}
|
||
|
||
export function randomBetween(min: number, max: number): number {
|
||
return Math.random() * (max - min) + min;
|
||
}
|
||
|
||
export function lerp(start: number, end: number, t: number): number {
|
||
return start + (end - start) * t;
|
||
}
|
||
|
||
export function clamp(value: number, min: number, max: number): number {
|
||
return Math.min(Math.max(value, min), max);
|
||
}
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交工具函数**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/lib/utils.ts
|
||
git commit -m "feat: add utility functions for formatting and animation"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 5: 创建主题常量
|
||
|
||
**Files:**
|
||
- Modify: `src/lib/constants.ts`
|
||
|
||
**Step 1: 读取现有常量**
|
||
|
||
Read: `src/lib/constants.ts`
|
||
|
||
**Step 2: 添加主题相关常量**
|
||
|
||
Modify: `src/lib/constants.ts`
|
||
|
||
在文件末尾添加:
|
||
|
||
```typescript
|
||
export const THEME = {
|
||
colors: {
|
||
dark: {
|
||
DEFAULT: "#0A0A0A",
|
||
secondary: "#1A1A1A",
|
||
tertiary: "#2A2A2A",
|
||
},
|
||
tech: {
|
||
blue: "#00D9FF",
|
||
purple: "#A855F7",
|
||
cyan: "#06B6D4",
|
||
},
|
||
text: {
|
||
primary: "#FFFFFF",
|
||
secondary: "#A0A0A0",
|
||
disabled: "#606060",
|
||
},
|
||
},
|
||
gradients: {
|
||
primary: "linear-gradient(135deg, #00D9FF 0%, #A855F7 100%)",
|
||
dark: "linear-gradient(180deg, #0A0A0A 0%, #1A1A1A 100%)",
|
||
glow: "radial-gradient(circle, #00D9FF20 0%, transparent 70%)",
|
||
},
|
||
spacing: {
|
||
xs: "4px",
|
||
sm: "8px",
|
||
md: "16px",
|
||
lg: "24px",
|
||
xl: "32px",
|
||
"2xl": "48px",
|
||
"3xl": "64px",
|
||
},
|
||
borderRadius: {
|
||
sm: "8px",
|
||
md: "12px",
|
||
lg: "16px",
|
||
full: "9999px",
|
||
},
|
||
animation: {
|
||
fast: "150ms",
|
||
standard: "300ms",
|
||
slow: "500ms",
|
||
verySlow: "1000ms",
|
||
},
|
||
breakpoints: {
|
||
sm: "640px",
|
||
md: "768px",
|
||
lg: "1024px",
|
||
xl: "1280px",
|
||
"2xl": "1536px",
|
||
},
|
||
} as const;
|
||
|
||
export const ANIMATION_VARIANTS = {
|
||
fadeInUp: {
|
||
initial: { opacity: 0, y: 20 },
|
||
animate: { opacity: 1, y: 0 },
|
||
exit: { opacity: 0, y: -20 },
|
||
},
|
||
fadeInScale: {
|
||
initial: { opacity: 0, scale: 0.95 },
|
||
animate: { opacity: 1, scale: 1 },
|
||
exit: { opacity: 0, scale: 0.95 },
|
||
},
|
||
slideInLeft: {
|
||
initial: { opacity: 0, x: -20 },
|
||
animate: { opacity: 1, x: 0 },
|
||
exit: { opacity: 0, x: 20 },
|
||
},
|
||
slideInRight: {
|
||
initial: { opacity: 0, x: 20 },
|
||
animate: { opacity: 1, x: 0 },
|
||
exit: { opacity: 0, x: -20 },
|
||
},
|
||
} as const;
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交常量更新**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/lib/constants.ts
|
||
git commit -m "feat: add theme constants and animation variants"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
## 阶段二:基础UI组件开发
|
||
|
||
### Task 6: 创建增强版按钮组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/ui/button.tsx`
|
||
|
||
**Step 1: 读取现有按钮组件**
|
||
|
||
Read: `src/components/ui/button.tsx`
|
||
|
||
**Step 2: 重写按钮组件以支持深色主题**
|
||
|
||
Modify: `src/components/ui/button.tsx`
|
||
|
||
```typescript
|
||
import * as React from "react";
|
||
import { cva, type VariantProps } from "class-variance-authority";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
const buttonVariants = cva(
|
||
"inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-tech-blue focus-visible:ring-offset-2 focus-visible:ring-offset-dark disabled:pointer-events-none disabled:opacity-50",
|
||
{
|
||
variants: {
|
||
variant: {
|
||
default:
|
||
"bg-gradient-to-r from-tech-blue to-tech-purple text-white hover:shadow-lg hover:shadow-tech-blue/50 hover:scale-105 active:scale-95",
|
||
secondary:
|
||
"bg-dark-tertiary text-white border border-gray-700 hover:border-tech-blue hover:shadow-lg hover:shadow-tech-blue/20 hover:scale-105 active:scale-95",
|
||
outline:
|
||
"border border-tech-blue text-tech-blue hover:bg-tech-blue/10 hover:shadow-lg hover:shadow-tech-blue/20",
|
||
ghost:
|
||
"text-gray-300 hover:text-tech-blue hover:bg-dark-tertiary",
|
||
link: "text-tech-blue underline-offset-4 hover:underline",
|
||
},
|
||
size: {
|
||
default: "h-10 px-6 py-2",
|
||
sm: "h-8 px-4 text-xs",
|
||
lg: "h-12 px-8 text-base",
|
||
xl: "h-14 px-10 text-lg",
|
||
icon: "h-10 w-10",
|
||
},
|
||
},
|
||
defaultVariants: {
|
||
variant: "default",
|
||
size: "default",
|
||
},
|
||
}
|
||
);
|
||
|
||
export interface ButtonProps
|
||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||
VariantProps<typeof buttonVariants> {
|
||
asChild?: boolean;
|
||
}
|
||
|
||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||
({ className, variant, size, ...props }, ref) => {
|
||
return (
|
||
<button
|
||
className={cn(buttonVariants({ variant, size, className }))}
|
||
ref={ref}
|
||
{...props}
|
||
/>
|
||
);
|
||
}
|
||
);
|
||
Button.displayName = "Button";
|
||
|
||
export { Button, buttonVariants };
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交按钮组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/ui/button.tsx
|
||
git commit -m "feat: enhance button component with dark theme variants"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 7: 创建增强版卡片组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/ui/card.tsx`
|
||
|
||
**Step 1: 读取现有卡片组件**
|
||
|
||
Read: `src/components/ui/card.tsx`
|
||
|
||
**Step 2: 重写卡片组件以支持深色主题和悬停效果**
|
||
|
||
Modify: `src/components/ui/card.tsx`
|
||
|
||
```typescript
|
||
import * as React from "react";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
const Card = React.forwardRef<
|
||
HTMLDivElement,
|
||
React.HTMLAttributes<HTMLDivElement> & {
|
||
variant?: "default" | "hover" | "glow";
|
||
}
|
||
>(({ className, variant = "default", ...props }, ref) => (
|
||
<div
|
||
ref={ref}
|
||
className={cn(
|
||
"rounded-xl border border-gray-800 bg-dark-tertiary text-white transition-all duration-300",
|
||
{
|
||
"hover:border-tech-blue hover:shadow-lg hover:shadow-tech-blue/20 hover:-translate-y-2":
|
||
variant === "hover",
|
||
"hover:border-tech-blue hover:shadow-xl hover:shadow-tech-blue/30 hover:-translate-y-2 animate-glow":
|
||
variant === "glow",
|
||
},
|
||
className
|
||
)}
|
||
{...props}
|
||
/>
|
||
));
|
||
Card.displayName = "Card";
|
||
|
||
const CardHeader = React.forwardRef<
|
||
HTMLDivElement,
|
||
React.HTMLAttributes<HTMLDivElement>
|
||
>(({ className, ...props }, ref) => (
|
||
<div
|
||
ref={ref}
|
||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||
{...props}
|
||
/>
|
||
));
|
||
CardHeader.displayName = "CardHeader";
|
||
|
||
const CardTitle = React.forwardRef<
|
||
HTMLParagraphElement,
|
||
React.HTMLAttributes<HTMLHeadingElement>
|
||
>(({ className, ...props }, ref) => (
|
||
<h3
|
||
ref={ref}
|
||
className={cn(
|
||
"text-2xl font-bold leading-none tracking-tight text-white",
|
||
className
|
||
)}
|
||
{...props}
|
||
/>
|
||
));
|
||
CardTitle.displayName = "CardTitle";
|
||
|
||
const CardDescription = React.forwardRef<
|
||
HTMLParagraphElement,
|
||
React.HTMLAttributes<HTMLParagraphElement>
|
||
>(({ className, ...props }, ref) => (
|
||
<p
|
||
ref={ref}
|
||
className={cn("text-sm text-gray-400", className)}
|
||
{...props}
|
||
/>
|
||
));
|
||
CardDescription.displayName = "CardDescription";
|
||
|
||
const CardContent = React.forwardRef<
|
||
HTMLDivElement,
|
||
React.HTMLAttributes<HTMLDivElement>
|
||
>(({ className, ...props }, ref) => (
|
||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||
));
|
||
CardContent.displayName = "CardContent";
|
||
|
||
const CardFooter = React.forwardRef<
|
||
HTMLDivElement,
|
||
React.HTMLAttributes<HTMLDivElement>
|
||
>(({ className, ...props }, ref) => (
|
||
<div
|
||
ref={ref}
|
||
className={cn("flex items-center p-6 pt-0", className)}
|
||
{...props}
|
||
/>
|
||
));
|
||
CardFooter.displayName = "CardFooter";
|
||
|
||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交卡片组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/ui/card.tsx
|
||
git commit -m "feat: enhance card component with dark theme and hover effects"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 8: 创建输入框组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/ui/input.tsx`
|
||
|
||
**Step 1: 读取现有输入框组件**
|
||
|
||
Read: `src/components/ui/input.tsx`
|
||
|
||
**Step 2: 重写输入框组件以支持深色主题**
|
||
|
||
Modify: `src/components/ui/input.tsx`
|
||
|
||
```typescript
|
||
import * as React from "react";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
export interface InputProps
|
||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||
|
||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||
({ className, type, ...props }, ref) => {
|
||
return (
|
||
<input
|
||
type={type}
|
||
className={cn(
|
||
"flex h-10 w-full rounded-lg border border-gray-700 bg-dark-secondary px-4 py-2 text-sm text-white placeholder:text-gray-500 transition-all duration-300",
|
||
"focus:border-tech-blue focus:outline-none focus:ring-2 focus:ring-tech-blue/20 focus:shadow-lg focus:shadow-tech-blue/10",
|
||
"disabled:cursor-not-allowed disabled:opacity-50",
|
||
"hover:border-gray-600",
|
||
className
|
||
)}
|
||
ref={ref}
|
||
{...props}
|
||
/>
|
||
);
|
||
}
|
||
);
|
||
Input.displayName = "Input";
|
||
|
||
export { Input };
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交输入框组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/ui/input.tsx
|
||
git commit -m "feat: enhance input component with dark theme styles"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 9: 创建徽章组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/ui/badge.tsx`
|
||
|
||
**Step 1: 读取现有徽章组件**
|
||
|
||
Read: `src/components/ui/badge.tsx`
|
||
|
||
**Step 2: 重写徽章组件以支持深色主题**
|
||
|
||
Modify: `src/components/ui/badge.tsx`
|
||
|
||
```typescript
|
||
import * as React from "react";
|
||
import { cva, type VariantProps } from "class-variance-authority";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
const badgeVariants = cva(
|
||
"inline-flex items-center rounded-full px-3 py-1 text-xs font-medium transition-colors duration-300",
|
||
{
|
||
variants: {
|
||
variant: {
|
||
default:
|
||
"bg-tech-blue/20 text-tech-blue border border-tech-blue/30",
|
||
secondary:
|
||
"bg-tech-purple/20 text-tech-purple border border-tech-purple/30",
|
||
success:
|
||
"bg-green-500/20 text-green-400 border border-green-500/30",
|
||
warning:
|
||
"bg-yellow-500/20 text-yellow-400 border border-yellow-500/30",
|
||
error:
|
||
"bg-red-500/20 text-red-400 border border-red-500/30",
|
||
outline:
|
||
"bg-transparent text-gray-300 border border-gray-600",
|
||
},
|
||
},
|
||
defaultVariants: {
|
||
variant: "default",
|
||
},
|
||
}
|
||
);
|
||
|
||
export interface BadgeProps
|
||
extends React.HTMLAttributes<HTMLDivElement>,
|
||
VariantProps<typeof badgeVariants> {}
|
||
|
||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||
return (
|
||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||
);
|
||
}
|
||
|
||
export { Badge, badgeVariants };
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交徽章组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/ui/badge.tsx
|
||
git commit -m "feat: enhance badge component with dark theme variants"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
## 阶段三:布局组件重构
|
||
|
||
### Task 10: 重构导航栏组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/layout/header.tsx`
|
||
|
||
**Step 1: 读取现有导航栏组件**
|
||
|
||
Read: `src/components/layout/header.tsx`
|
||
|
||
**Step 2: 重写导航栏组件以支持深色主题和下拉菜单**
|
||
|
||
Modify: `src/components/layout/header.tsx`
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
import { useState, useEffect } from "react";
|
||
import Link from "next/link";
|
||
import { Button } from "@/components/ui/button";
|
||
import { NAVIGATION, COMPANY_INFO } from "@/lib/constants";
|
||
import { cn } from "@/lib/utils";
|
||
import { ChevronDown, Menu, X } from "lucide-react";
|
||
|
||
export function Header() {
|
||
const [isScrolled, setIsScrolled] = useState(false);
|
||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
const handleScroll = () => {
|
||
setIsScrolled(window.scrollY > 10);
|
||
};
|
||
window.addEventListener("scroll", handleScroll);
|
||
return () => window.removeEventListener("scroll", handleScroll);
|
||
}, []);
|
||
|
||
return (
|
||
<header
|
||
className={cn(
|
||
"fixed top-0 left-0 right-0 z-50 transition-all duration-300",
|
||
isScrolled
|
||
? "bg-dark/95 backdrop-blur-md border-b border-gray-800 shadow-lg"
|
||
: "bg-transparent"
|
||
)}
|
||
>
|
||
<nav className="container-wide h-16 flex items-center justify-between">
|
||
<Link href="/" className="flex items-center gap-2 group">
|
||
<div className="relative">
|
||
<img
|
||
src="/logo.svg"
|
||
alt={COMPANY_INFO.shortName}
|
||
className="h-8 w-auto transition-all duration-300 group-hover:drop-shadow-[0_0_10px_rgba(0,217,255,0.5)]"
|
||
/>
|
||
</div>
|
||
<span className="text-lg font-bold text-white hidden sm:block">
|
||
{COMPANY_INFO.shortName}
|
||
</span>
|
||
</Link>
|
||
|
||
<div className="hidden lg:flex items-center gap-8">
|
||
{NAVIGATION.map((item) => (
|
||
<Link
|
||
key={item.id}
|
||
href={item.href}
|
||
className="text-gray-300 hover:text-tech-blue transition-colors duration-300 relative group"
|
||
>
|
||
{item.label}
|
||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-tech-blue transition-all duration-300 group-hover:w-full" />
|
||
</Link>
|
||
))}
|
||
</div>
|
||
|
||
<div className="hidden lg:flex items-center gap-4">
|
||
<Button variant="ghost" size="sm">
|
||
登录
|
||
</Button>
|
||
<Button variant="default" size="sm">
|
||
免费试用
|
||
</Button>
|
||
</div>
|
||
|
||
<button
|
||
className="lg:hidden text-white p-2"
|
||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||
aria-label="Toggle menu"
|
||
>
|
||
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
||
</button>
|
||
</nav>
|
||
|
||
{isMobileMenuOpen && (
|
||
<div className="lg:hidden bg-dark-secondary border-t border-gray-800">
|
||
<div className="container-wide py-4 space-y-4">
|
||
{NAVIGATION.map((item) => (
|
||
<Link
|
||
key={item.id}
|
||
href={item.href}
|
||
className="block text-gray-300 hover:text-tech-blue transition-colors duration-300 py-2"
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
>
|
||
{item.label}
|
||
</Link>
|
||
))}
|
||
<div className="flex flex-col gap-2 pt-4 border-t border-gray-800">
|
||
<Button variant="ghost" className="w-full">
|
||
登录
|
||
</Button>
|
||
<Button variant="default" className="w-full">
|
||
免费试用
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</header>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交导航栏组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/layout/header.tsx
|
||
git commit -m "feat: refactor header with dark theme and mobile menu"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 11: 重构页脚组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/layout/footer.tsx`
|
||
|
||
**Step 1: 读取现有页脚组件**
|
||
|
||
Read: `src/components/layout/footer.tsx`
|
||
|
||
**Step 2: 重写页脚组件以支持深色主题**
|
||
|
||
Modify: `src/components/layout/footer.tsx`
|
||
|
||
```typescript
|
||
import Link from "next/link";
|
||
import { COMPANY_INFO } from "@/lib/constants";
|
||
|
||
export function Footer() {
|
||
const currentYear = new Date().getFullYear();
|
||
|
||
const footerLinks = {
|
||
products: [
|
||
{ label: "ERP系统", href: "/products/erp" },
|
||
{ label: "CRM系统", href: "/products/crm" },
|
||
{ label: "OA平台", href: "/products/oa" },
|
||
{ label: "BI平台", href: "/products/bi" },
|
||
],
|
||
solutions: [
|
||
{ label: "金融行业", href: "/solutions/finance" },
|
||
{ label: "制造业", href: "/solutions/manufacturing" },
|
||
{ label: "零售行业", href: "/solutions/retail" },
|
||
{ label: "教育行业", href: "/solutions/education" },
|
||
],
|
||
company: [
|
||
{ label: "关于我们", href: "/about" },
|
||
{ label: "新闻动态", href: "/news" },
|
||
{ label: "成功案例", href: "/cases" },
|
||
{ label: "联系我们", href: "/contact" },
|
||
],
|
||
};
|
||
|
||
return (
|
||
<footer className="bg-dark-secondary border-t border-gray-800">
|
||
<div className="container-wide py-12">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||
<div className="space-y-4">
|
||
<Link href="/" className="flex items-center gap-2">
|
||
<img
|
||
src="/logo.svg"
|
||
alt={COMPANY_INFO.shortName}
|
||
className="h-8 w-auto"
|
||
/>
|
||
<span className="text-lg font-bold text-white">
|
||
{COMPANY_INFO.shortName}
|
||
</span>
|
||
</Link>
|
||
<p className="text-sm text-gray-400">
|
||
{COMPANY_INFO.slogan}
|
||
</p>
|
||
<div className="flex gap-4">
|
||
<a
|
||
href="#"
|
||
className="text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
aria-label="WeChat"
|
||
>
|
||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||
<path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 01.213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 00.167-.054l1.903-1.114a.864.864 0 01.717-.098 10.16 10.16 0 002.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178A1.17 1.17 0 014.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178 1.17 1.17 0 01-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 01.598.082l1.584.926a.272.272 0 00.14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 01-.023-.156.49.49 0 01.201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-7.062-6.122zm-2.036 2.87c.535 0 .969.44.969.982a.976.976 0 01-.969.983.976.976 0 01-.969-.983c0-.542.434-.982.97-.982zm4.844 0c.535 0 .969.44.969.982a.976.976 0 01-.969.983.976.976 0 01-.969-.983c0-.542.434-.982.97-.982z" />
|
||
</svg>
|
||
</a>
|
||
<a
|
||
href="#"
|
||
className="text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
aria-label="Weibo"
|
||
>
|
||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||
<path d="M10.098 20.323c-3.977.391-7.414-1.406-7.672-4.02-.259-2.609 2.759-5.047 6.74-5.441 3.979-.394 7.413 1.404 7.671 4.018.259 2.6-2.759 5.049-6.737 5.439l-.002.004zM9.05 17.219c-.384.616-1.208.884-1.829.602-.612-.279-.793-.991-.406-1.593.379-.595 1.176-.861 1.793-.601.622.263.82.972.442 1.592zm1.27-1.627c-.141.237-.449.353-.689.253-.236-.09-.313-.361-.177-.586.138-.227.436-.346.672-.24.239.09.315.36.18.573h.014zm.176-2.719c-1.893-.493-4.033.45-4.857 2.118-.836 1.704-.026 3.591 1.886 4.21 1.983.64 4.318-.341 5.132-2.179.8-1.793-.201-3.642-2.161-4.149zm7.563-1.224c-.346-.105-.579-.18-.405-.649.381-1.017.422-1.896-.001-2.521-.792-1.163-2.951-1.102-5.418-.03 0 0-.776.34-.578-.275.381-1.217.324-2.236-.27-2.82-1.349-1.326-4.935.05-8.012 3.073C.417 11.473-.27 14.034-.27 16.218c0 4.179 5.37 6.717 10.624 6.717 6.886 0 11.469-3.997 11.469-7.169 0-1.917-1.618-3.004-3.764-3.617h.002zm2.029-5.47c-.439-.511-1.09-.744-1.741-.653-.651.091-1.178.488-1.434 1.065-.256.577-.197 1.23.157 1.742.354.512.941.812 1.592.812.651 0 1.238-.3 1.592-.812.354-.512.413-1.165.157-1.742-.256-.577-.783-.974-1.434-1.065-.651-.091-1.302.142-1.741.653h-.003v.003z" />
|
||
</svg>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 className="text-white font-semibold mb-4">产品服务</h3>
|
||
<ul className="space-y-2">
|
||
{footerLinks.products.map((link) => (
|
||
<li key={link.href}>
|
||
<Link
|
||
href={link.href}
|
||
className="text-sm text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
>
|
||
{link.label}
|
||
</Link>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 className="text-white font-semibold mb-4">解决方案</h3>
|
||
<ul className="space-y-2">
|
||
{footerLinks.solutions.map((link) => (
|
||
<li key={link.href}>
|
||
<Link
|
||
href={link.href}
|
||
className="text-sm text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
>
|
||
{link.label}
|
||
</Link>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 className="text-white font-semibold mb-4">关于我们</h3>
|
||
<ul className="space-y-2">
|
||
{footerLinks.company.map((link) => (
|
||
<li key={link.href}>
|
||
<Link
|
||
href={link.href}
|
||
className="text-sm text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
>
|
||
{link.label}
|
||
</Link>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-12 pt-8 border-t border-gray-800">
|
||
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
|
||
<p className="text-sm text-gray-400">
|
||
© {currentYear} {COMPANY_INFO.name}. All rights reserved.
|
||
</p>
|
||
<div className="flex gap-6">
|
||
<Link
|
||
href="/privacy"
|
||
className="text-sm text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
>
|
||
隐私政策
|
||
</Link>
|
||
<Link
|
||
href="/terms"
|
||
className="text-sm text-gray-400 hover:text-tech-blue transition-colors duration-300"
|
||
>
|
||
服务条款
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交页脚组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/layout/footer.tsx
|
||
git commit -m "feat: refactor footer with dark theme and improved layout"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
## 阶段四:特效组件开发
|
||
|
||
### Task 12: 创建粒子背景组件
|
||
|
||
**Files:**
|
||
- Create: `src/components/effects/particle-background.tsx`
|
||
|
||
**Step 1: 创建粒子背景组件**
|
||
|
||
Create: `src/components/effects/particle-background.tsx`
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
import { useEffect, useRef } from "react";
|
||
import { randomBetween } from "@/lib/utils";
|
||
|
||
interface Particle {
|
||
x: number;
|
||
y: number;
|
||
vx: number;
|
||
vy: number;
|
||
size: number;
|
||
color: string;
|
||
opacity: number;
|
||
}
|
||
|
||
interface ParticleBackgroundProps {
|
||
particleCount?: number;
|
||
colors?: string[];
|
||
minSize?: number;
|
||
maxSize?: number;
|
||
speed?: number;
|
||
className?: string;
|
||
}
|
||
|
||
export function ParticleBackground({
|
||
particleCount = 50,
|
||
colors = ["#00D9FF", "#A855F7", "#06B6D4"],
|
||
minSize = 1,
|
||
maxSize = 3,
|
||
speed = 0.5,
|
||
className = "",
|
||
}: ParticleBackgroundProps) {
|
||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||
const particlesRef = useRef<Particle[]>([]);
|
||
const animationRef = useRef<number>();
|
||
|
||
useEffect(() => {
|
||
const canvas = canvasRef.current;
|
||
if (!canvas) return;
|
||
|
||
const ctx = canvas.getContext("2d");
|
||
if (!ctx) return;
|
||
|
||
const resizeCanvas = () => {
|
||
canvas.width = window.innerWidth;
|
||
canvas.height = window.innerHeight;
|
||
};
|
||
|
||
resizeCanvas();
|
||
window.addEventListener("resize", resizeCanvas);
|
||
|
||
particlesRef.current = Array.from({ length: particleCount }, () => ({
|
||
x: randomBetween(0, canvas.width),
|
||
y: randomBetween(0, canvas.height),
|
||
vx: randomBetween(-speed, speed),
|
||
vy: randomBetween(-speed, speed),
|
||
size: randomBetween(minSize, maxSize),
|
||
color: colors[Math.floor(Math.random() * colors.length)],
|
||
opacity: randomBetween(0.1, 0.5),
|
||
}));
|
||
|
||
const animate = () => {
|
||
if (!ctx || !canvas) return;
|
||
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
|
||
particlesRef.current.forEach((particle) => {
|
||
particle.x += particle.vx;
|
||
particle.y += particle.vy;
|
||
|
||
if (particle.x < 0 || particle.x > canvas.width) particle.vx *= -1;
|
||
if (particle.y < 0 || particle.y > canvas.height) particle.vy *= -1;
|
||
|
||
ctx.beginPath();
|
||
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
|
||
ctx.fillStyle = particle.color;
|
||
ctx.globalAlpha = particle.opacity;
|
||
ctx.fill();
|
||
});
|
||
|
||
ctx.globalAlpha = 1;
|
||
animationRef.current = requestAnimationFrame(animate);
|
||
};
|
||
|
||
animate();
|
||
|
||
return () => {
|
||
window.removeEventListener("resize", resizeCanvas);
|
||
if (animationRef.current) {
|
||
cancelAnimationFrame(animationRef.current);
|
||
}
|
||
};
|
||
}, [particleCount, colors, minSize, maxSize, speed]);
|
||
|
||
return (
|
||
<canvas
|
||
ref={canvasRef}
|
||
className={`absolute inset-0 pointer-events-none ${className}`}
|
||
style={{ zIndex: 0 }}
|
||
/>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 2: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 3: 提交粒子背景组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/effects/particle-background.tsx
|
||
git commit -m "feat: create particle background component for hero section"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 13: 创建发光效果组件
|
||
|
||
**Files:**
|
||
- Create: `src/components/effects/glow-effect.tsx`
|
||
|
||
**Step 1: 创建发光效果组件**
|
||
|
||
Create: `src/components/effects/glow-effect.tsx`
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
import { cn } from "@/lib/utils";
|
||
|
||
interface GlowEffectProps {
|
||
color?: string;
|
||
size?: "sm" | "md" | "lg" | "xl";
|
||
className?: string;
|
||
children?: React.ReactNode;
|
||
}
|
||
|
||
const sizeMap = {
|
||
sm: "w-32 h-32",
|
||
md: "w-48 h-48",
|
||
lg: "w-64 h-64",
|
||
xl: "w-96 h-96",
|
||
};
|
||
|
||
export function GlowEffect({
|
||
color = "#00D9FF",
|
||
size = "lg",
|
||
className,
|
||
children,
|
||
}: GlowEffectProps) {
|
||
return (
|
||
<div className={cn("relative", className)}>
|
||
<div
|
||
className={cn(
|
||
"absolute rounded-full blur-3xl opacity-20 animate-pulse",
|
||
sizeMap[size]
|
||
)}
|
||
style={{
|
||
background: `radial-gradient(circle, ${color}40 0%, transparent 70%)`,
|
||
}}
|
||
/>
|
||
{children}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
interface GradientOrbProps {
|
||
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
||
color?: string;
|
||
className?: string;
|
||
}
|
||
|
||
const positionMap = {
|
||
"top-left": "top-0 left-0",
|
||
"top-right": "top-0 right-0",
|
||
"bottom-left": "bottom-0 left-0",
|
||
"bottom-right": "bottom-0 right-0",
|
||
};
|
||
|
||
export function GradientOrb({
|
||
position = "top-right",
|
||
color = "#00D9FF",
|
||
className,
|
||
}: GradientOrbProps) {
|
||
return (
|
||
<div
|
||
className={cn(
|
||
"absolute w-96 h-96 rounded-full blur-3xl opacity-5 pointer-events-none",
|
||
positionMap[position],
|
||
className
|
||
)}
|
||
style={{
|
||
background: `radial-gradient(circle, ${color} 0%, transparent 70%)`,
|
||
}}
|
||
/>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 2: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 3: 提交发光效果组件**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/effects/glow-effect.tsx
|
||
git commit -m "feat: create glow effect and gradient orb components"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
## 阶段五:首页重构
|
||
|
||
### Task 14: 重构 Hero Section
|
||
|
||
**Files:**
|
||
- Modify: `src/components/sections/hero-section.tsx`
|
||
|
||
**Step 1: 读取现有 Hero Section**
|
||
|
||
Read: `src/components/sections/hero-section.tsx`
|
||
|
||
**Step 2: 重写 Hero Section 以支持深色主题和动画**
|
||
|
||
Modify: `src/components/sections/hero-section.tsx`
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
import { motion } from "framer-motion";
|
||
import { Button } from "@/components/ui/button";
|
||
import { ParticleBackground } from "@/components/effects/particle-background";
|
||
import { GradientOrb } from "@/components/effects/glow-effect";
|
||
import { COMPANY_INFO } from "@/lib/constants";
|
||
import { ArrowRight, Sparkles } from "lucide-react";
|
||
|
||
export function HeroSection() {
|
||
return (
|
||
<section className="relative min-h-screen flex items-center justify-center overflow-hidden pt-16">
|
||
<ParticleBackground
|
||
particleCount={80}
|
||
colors={["#00D9FF", "#A855F7", "#06B6D4"]}
|
||
minSize={1}
|
||
maxSize={4}
|
||
speed={0.3}
|
||
/>
|
||
|
||
<GradientOrb position="top-right" color="#00D9FF" />
|
||
<GradientOrb position="bottom-left" color="#A855F7" />
|
||
|
||
<div className="container-wide relative z-10 py-24 md:py-32 lg:py-40">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6 }}
|
||
className="mb-6"
|
||
>
|
||
<span className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-tech-blue/10 border border-tech-blue/20 text-tech-blue text-sm font-medium">
|
||
<Sparkles className="w-4 h-4" />
|
||
专注科技创新
|
||
</span>
|
||
</motion.div>
|
||
|
||
<motion.h1
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6, delay: 0.1 }}
|
||
className="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6 leading-tight"
|
||
>
|
||
{COMPANY_INFO.slogan}
|
||
</motion.h1>
|
||
|
||
<motion.p
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6, delay: 0.2 }}
|
||
className="text-lg md:text-xl text-gray-400 mb-8 max-w-2xl mx-auto"
|
||
>
|
||
{COMPANY_INFO.description}
|
||
</motion.p>
|
||
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6, delay: 0.3 }}
|
||
className="flex flex-col sm:flex-row gap-4 justify-center"
|
||
>
|
||
<Button size="lg" className="group">
|
||
立即体验
|
||
<ArrowRight className="ml-2 w-4 h-4 group-hover:translate-x-1 transition-transform" />
|
||
</Button>
|
||
<Button size="lg" variant="secondary">
|
||
了解更多
|
||
</Button>
|
||
</motion.div>
|
||
</div>
|
||
</div>
|
||
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
transition={{ duration: 1, delay: 0.5 }}
|
||
className="absolute bottom-8 left-1/2 -translate-x-1/2"
|
||
>
|
||
<div className="flex flex-col items-center gap-2 text-gray-400">
|
||
<span className="text-sm">向下滚动</span>
|
||
<div className="w-6 h-10 rounded-full border-2 border-gray-600 flex justify-center pt-2">
|
||
<motion.div
|
||
animate={{ y: [0, 12, 0] }}
|
||
transition={{ duration: 1.5, repeat: Infinity }}
|
||
className="w-1.5 h-1.5 bg-tech-blue rounded-full"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
</section>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交 Hero Section**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/sections/hero-section.tsx
|
||
git commit -m "feat: refactor hero section with dark theme and animations"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 15: 创建统计数据 Section
|
||
|
||
**Files:**
|
||
- Create: `src/components/sections/stats-section.tsx`
|
||
|
||
**Step 1: 创建统计数据 Section**
|
||
|
||
Create: `src/components/sections/stats-section.tsx`
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
import { motion } from "framer-motion";
|
||
import { STATS } from "@/lib/constants";
|
||
|
||
export function StatsSection() {
|
||
return (
|
||
<section className="py-20 bg-dark-secondary">
|
||
<div className="container-wide">
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||
{STATS.map((stat, index) => (
|
||
<motion.div
|
||
key={stat.label}
|
||
initial={{ opacity: 0, y: 20 }}
|
||
whileInView={{ opacity: 1, y: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||
className="text-center"
|
||
>
|
||
<div className="text-4xl md:text-5xl font-bold text-tech-blue mb-2">
|
||
{stat.value}
|
||
</div>
|
||
<div className="text-gray-400 text-sm md:text-base">
|
||
{stat.label}
|
||
</div>
|
||
</motion.div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 2: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 3: 提交统计数据 Section**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/sections/stats-section.tsx
|
||
git commit -m "feat: create stats section with animated counters"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
### Task 16: 重构产品展示 Section
|
||
|
||
**Files:**
|
||
- Modify: `src/components/sections/products-section.tsx`
|
||
|
||
**Step 1: 读取现有产品展示 Section**
|
||
|
||
Read: `src/components/sections/products-section.tsx`
|
||
|
||
**Step 2: 重写产品展示 Section 以支持深色主题和卡片效果**
|
||
|
||
Modify: `src/components/sections/products-section.tsx`
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
import { motion } from "framer-motion";
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import { PRODUCTS } from "@/lib/constants";
|
||
import { ArrowRight } from "lucide-react";
|
||
|
||
export function ProductsSection() {
|
||
return (
|
||
<section className="py-20 bg-dark">
|
||
<div className="container-wide">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
whileInView={{ opacity: 1, y: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.6 }}
|
||
className="text-center mb-12"
|
||
>
|
||
<h2 className="text-3xl md:text-4xl font-bold text-white mb-4">
|
||
产品服务
|
||
</h2>
|
||
<p className="text-gray-400 max-w-2xl mx-auto">
|
||
为企业提供全方位的数字化解决方案,助力业务增长
|
||
</p>
|
||
</motion.div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
{PRODUCTS.slice(0, 6).map((product, index) => (
|
||
<motion.div
|
||
key={product.id}
|
||
initial={{ opacity: 0, y: 20 }}
|
||
whileInView={{ opacity: 1, y: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||
>
|
||
<Card variant="hover" className="h-full">
|
||
<CardHeader>
|
||
<div className="flex items-start justify-between mb-2">
|
||
<Badge variant="default">{product.category}</Badge>
|
||
</div>
|
||
<CardTitle className="text-xl">{product.title}</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<CardDescription className="mb-4">
|
||
{product.description}
|
||
</CardDescription>
|
||
<div className="flex flex-wrap gap-2 mb-4">
|
||
{product.features.slice(0, 3).map((feature) => (
|
||
<Badge key={feature} variant="outline" className="text-xs">
|
||
{feature}
|
||
</Badge>
|
||
))}
|
||
</div>
|
||
<a
|
||
href={`/products/${product.id}`}
|
||
className="inline-flex items-center text-tech-blue hover:text-tech-purple transition-colors duration-300 text-sm font-medium group"
|
||
>
|
||
了解更多
|
||
<ArrowRight className="ml-1 w-4 h-4 group-hover:translate-x-1 transition-transform" />
|
||
</a>
|
||
</CardContent>
|
||
</Card>
|
||
</motion.div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Step 3: 验证类型检查**
|
||
|
||
Run: `npx tsc --noEmit`
|
||
|
||
Expected: 无类型错误
|
||
|
||
**Step 4: 提交产品展示 Section**
|
||
|
||
Run:
|
||
```bash
|
||
git add src/components/sections/products-section.tsx
|
||
git commit -m "feat: refactor products section with dark theme and card layout"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
---
|
||
|
||
## 阶段六:测试与验证
|
||
|
||
### Task 17: 运行开发服务器测试
|
||
|
||
**Files:**
|
||
- None
|
||
|
||
**Step 1: 启动开发服务器**
|
||
|
||
Run: `npm run dev`
|
||
|
||
Expected: 开发服务器成功启动在 http://localhost:3000
|
||
|
||
**Step 2: 在浏览器中验证首页**
|
||
|
||
手动测试:
|
||
- 访问 http://localhost:3000
|
||
- 验证深色主题是否正确应用
|
||
- 验证导航栏是否正常工作
|
||
- 验证 Hero Section 动画是否流畅
|
||
- 验证产品卡片悬停效果
|
||
- 验证响应式布局(移动端、平板、桌面)
|
||
|
||
Expected: 所有功能正常工作
|
||
|
||
**Step 3: 停止开发服务器**
|
||
|
||
按 Ctrl+C 停止服务器
|
||
|
||
Expected: 服务器成功停止
|
||
|
||
---
|
||
|
||
### Task 18: 运行构建测试
|
||
|
||
**Files:**
|
||
- None
|
||
|
||
**Step 1: 运行生产构建**
|
||
|
||
Run: `npm run build`
|
||
|
||
Expected: 构建成功,无错误
|
||
|
||
**Step 2: 检查构建输出**
|
||
|
||
验证构建输出中:
|
||
- 页面是否正确生成
|
||
- 是否有优化建议
|
||
- 构建大小是否合理
|
||
|
||
Expected: 构建输出正常
|
||
|
||
**Step 3: 运行代码检查**
|
||
|
||
Run: `npm run lint`
|
||
|
||
Expected: 无 ESLint 错误
|
||
|
||
---
|
||
|
||
### Task 19: 提交所有更改
|
||
|
||
**Files:**
|
||
- None
|
||
|
||
**Step 1: 检查 Git 状态**
|
||
|
||
Run: `git status`
|
||
|
||
Expected: 显示所有修改的文件
|
||
|
||
**Step 2: 添加所有更改**
|
||
|
||
Run: `git add .`
|
||
|
||
Expected: 所有更改已暂存
|
||
|
||
**Step 3: 创建提交**
|
||
|
||
Run:
|
||
```bash
|
||
git commit -m "feat: complete website redesign with dark tech theme
|
||
|
||
- Add dark theme color system and CSS variables
|
||
- Enhance UI components (Button, Card, Input, Badge)
|
||
- Refactor layout components (Header, Footer)
|
||
- Create effect components (ParticleBackground, GlowEffect)
|
||
- Refactor sections (Hero, Stats, Products)
|
||
- Add Framer Motion animations
|
||
- Improve responsive design
|
||
- Update Tailwind configuration"
|
||
```
|
||
|
||
Expected: 提交成功
|
||
|
||
**Step 4: 推送到远程**
|
||
|
||
Run: `git push origin feature/website-redesign`
|
||
|
||
Expected: 推送成功
|
||
|
||
---
|
||
|
||
## 完成清单
|
||
|
||
- [ ] 安装必要依赖(framer-motion, @antv/g2, class-variance-authority)
|
||
- [ ] 扩展 Tailwind 配置
|
||
- [ ] 更新全局样式
|
||
- [ ] 创建工具函数
|
||
- [ ] 创建主题常量
|
||
- [ ] 增强按钮组件
|
||
- [ ] 增强卡片组件
|
||
- [ ] 增强输入框组件
|
||
- [ ] 增强徽章组件
|
||
- [ ] 重构导航栏组件
|
||
- [ ] 重构页脚组件
|
||
- [ ] 创建粒子背景组件
|
||
- [ ] 创建发光效果组件
|
||
- [ ] 重构 Hero Section
|
||
- [ ] 创建统计数据 Section
|
||
- [ ] 重构产品展示 Section
|
||
- [ ] 运行开发服务器测试
|
||
- [ ] 运行构建测试
|
||
- [ ] 提交所有更改
|
||
|
||
---
|
||
|
||
## 注意事项
|
||
|
||
1. **每个任务都应该独立完成并提交**,便于版本控制和回滚
|
||
2. **遇到错误立即停止**,不要继续下一步
|
||
3. **保持代码风格一致**,遵循项目现有的代码规范
|
||
4. **测试每个组件**,确保在移动端和桌面端都能正常工作
|
||
5. **关注性能**,避免过度使用动画和特效
|
||
|
||
---
|
||
|
||
**计划创建者:** AI Assistant
|
||
**创建日期:** 2026-02-21
|
||
**预计工期:** 2-3天(基础架构 + 核心组件 + 首页重构)
|