Files
novalon-website/docs/plans/2026-02-22-novalon-redesign-implementation.md
T
张翔 b7092296cb docs: 添加 Novalon 官网重新设计实施计划
- 16 个可执行任务
- 完整的代码实现
- 明确的测试步骤
- 清晰的提交信息
- 遵循 TDD、DRY、YAGNI 原则
2026-02-22 14:54:45 +08:00

1342 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Novalon 官网重新设计实施计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 将 Novalon 官网从现有设计升级为数字未来风设计,包括配色系统、UI 组件、页面布局、动效和响应式适配的全面升级。
**Architecture:** 采用渐进式升级策略,从核心配色系统开始,逐步更新 UI 组件、页面布局、动效和响应式适配。使用 Tailwind CSS v4 的 CSS 变量系统实现主题切换,使用 Framer Motion 实现动效,使用 AntV 生态实现数据可视化。
**Tech Stack:** Next.js 16, React 19, TypeScript, Tailwind CSS v4, Framer Motion, AntV (G2/G6/L7/S2), Lucide React
---
## Phase 1: 核心配色系统
### Task 1: 更新 CSS 变量 - 深色模式配色
**Files:**
- Modify: `src/app/globals.css:1-200`
**Step 1: 备份当前配色变量**
```bash
cp src/app/globals.css src/app/globals.css.backup
```
**Step 2: 更新深色模式配色变量**
`.dark` 类中更新配色变量:
```css
.dark {
--color-bg-primary: #0A0A0A;
--color-bg-secondary: #141414;
--color-bg-tertiary: #1A1A1A;
--color-bg-hover: #242424;
--color-text-primary: #FAFAFA;
--color-text-secondary: #D4D4D4;
--color-text-tertiary: #A3A3A3;
--color-text-muted: #737373;
--color-border-primary: #262626;
--color-border-secondary: #333333;
--color-border-accent: #404040;
--color-accent: #FAFAFA;
--color-accent-hover: #E5E5E5;
--color-accent-light: #D4D4D4;
--color-link: #D4D4D4;
--color-link-hover: #FAFAFA;
--color-brand-primary: #C41E3A;
--color-brand-primary-hover: #A01830;
--color-brand-primary-light: #E04A68;
--color-brand-primary-lighter: #F08C9F;
--color-brand-primary-bg: #1A0F11;
--color-tech-blue: #00D9FF;
--color-tech-blue-hover: #00B8D9;
--color-tech-blue-light: #33E1FF;
--color-tech-purple: #A855F7;
--color-tech-purple-hover: #9333EA;
--color-tech-purple-light: #C084FC;
--color-tech-cyan: #06B6D4;
--color-success: #22C55E;
--color-success-bg: #052E16;
--color-warning: #F59E0B;
--color-warning-bg: #1C1917;
--color-info: #0EA5E9;
--color-info-bg: #0C2D48;
--color-error: #EF4444;
--color-error-bg: #1C1917;
}
```
**Step 3: 更新浅色模式配色变量**
`:root` 中更新配色变量:
```css
:root {
--color-bg-primary: #FFFFFF;
--color-bg-secondary: #FAFAFA;
--color-bg-tertiary: #F5F5F5;
--color-bg-hover: #F0F0F0;
--color-text-primary: #171717;
--color-text-secondary: #525252;
--color-text-tertiary: #737373;
--color-text-muted: #A3A3A3;
--color-border-primary: #E5E5E5;
--color-border-secondary: #F0F0F0;
--color-border-accent: #D4D4D4;
--color-accent: #171717;
--color-accent-hover: #262626;
--color-accent-light: #404040;
--color-link: #525252;
--color-link-hover: #171717;
--color-brand-primary: #C41E3A;
--color-brand-primary-hover: #A01830;
--color-brand-primary-light: #D4244A;
--color-brand-primary-lighter: #E04A68;
--color-brand-primary-bg: #FEF2F4;
--color-tech-blue: #00D9FF;
--color-tech-blue-hover: #00B8D9;
--color-tech-blue-light: #33E1FF;
--color-tech-purple: #A855F7;
--color-tech-purple-hover: #9333EA;
--color-tech-purple-light: #C084FC;
--color-tech-cyan: #06B6D4;
--color-success: #16A34A;
--color-success-bg: #F0FDF4;
--color-warning: #D97706;
--color-warning-bg: #FFFBEB;
--color-info: #0284C7;
--color-info-bg: #F0F9FF;
--color-error: #DC2626;
--color-error-bg: #FEF2F2;
}
```
**Step 4: 验证配色变量**
在浏览器中打开网站,切换深色/浅色模式,检查配色是否正确应用。
**Step 5: 提交更改**
```bash
git add src/app/globals.css
git commit -m "feat: 更新核心配色系统 - 深色/浅色模式
- 更新深色模式配色变量(科技蓝、紫色、印章红)
- 更新浅色模式配色变量
- 添加新的科技色彩变量
- 保持品牌色一致性"
```
---
### Task 2: 更新 colors.ts 文件
**Files:**
- Modify: `src/lib/colors.ts:1-69`
**Step 1: 更新品牌色彩定义**
```typescript
export const brandColors = {
primary: {
600: '#C41E3A',
700: '#A01830',
500: '#D4244A',
400: '#E04A68',
100: '#FEF2F4',
},
tech: {
blue: {
600: '#00D9FF',
700: '#00B8D9',
500: '#33E1FF',
},
purple: {
600: '#A855F7',
700: '#9333EA',
500: '#C084FC',
},
cyan: {
600: '#06B6D4',
},
},
neutral: {
900: '#0A0A0A',
800: '#141414',
700: '#1A1A1A',
600: '#242424',
500: '#333333',
400: '#404040',
300: '#737373',
200: '#A3A3A3',
100: '#D4D4D4',
50: '#FAFAFA',
0: '#FFFFFF',
},
success: {
600: '#16A34A',
100: '#F0FDF4',
},
warning: {
600: '#D97706',
100: '#FFFBEB',
},
info: {
600: '#0284C7',
100: '#F0F9FF',
},
error: {
600: '#DC2626',
100: '#FEF2F2',
},
} as const;
export const colorValues = {
primary: '#C41E3A',
primaryHover: '#A01830',
primaryLight: '#D4244A',
primaryBg: '#FEF2F4',
techBlue: '#00D9FF',
techBlueHover: '#00B8D9',
techBlueLight: '#33E1FF',
techPurple: '#A855F7',
techPurpleHover: '#9333EA',
techPurpleLight: '#C084FC',
techCyan: '#06B6D4',
textPrimary: '#FAFAFA',
textSecondary: '#D4D4D4',
textTertiary: '#A3A3A3',
textMuted: '#737373',
bgPrimary: '#0A0A0A',
bgSecondary: '#141414',
bgTertiary: '#1A1A1A',
bgHover: '#242424',
border: '#262626',
borderHover: '#333333',
success: '#16A34A',
successBg: '#F0FDF4',
warning: '#D97706',
warningBg: '#FFFBEB',
info: '#0284C7',
infoBg: '#F0F9FF',
error: '#DC2626',
errorBg: '#FEF2F2',
} as const;
export const gradients = {
primary: 'linear-gradient(135deg, #00D9FF 0%, #A855F7 100%)',
reverse: 'linear-gradient(135deg, #A855F7 0%, #00D9FF 100%)',
glow: 'radial-gradient(circle, rgba(0, 217, 255, 0.15) 0%, transparent 70%)',
glowPurple: 'radial-gradient(circle, rgba(168, 85, 247, 0.15) 0%, transparent 70%)',
} as const;
export type BrandColor = typeof brandColors;
export type ColorValue = typeof colorValues;
export type Gradient = typeof gradients;
```
**Step 2: 验证类型定义**
运行 TypeScript 编译检查:
```bash
npm run build
```
Expected: 无类型错误
**Step 3: 提交更改**
```bash
git add src/lib/colors.ts
git commit -m "feat: 更新色彩系统定义
- 添加科技蓝、紫色、青色色彩系列
- 更新中性色系列
- 添加渐变色定义
- 完善类型定义"
```
---
### Task 3: 创建渐变色工具函数
**Files:**
- Create: `src/lib/gradients.ts`
**Step 1: 创建渐变色工具函数**
```typescript
import { gradients } from './colors';
export const getGradientStyle = (type: keyof typeof gradients) => {
return {
background: gradients[type],
};
};
export const getGlowStyle = (color: 'blue' | 'purple', opacity: number = 0.15) => {
const colorValue = color === 'blue' ? '0, 217, 255' : '168, 85, 247';
return {
background: `radial-gradient(circle, rgba(${colorValue}, ${opacity}) 0%, transparent 70%)`,
};
};
export const getBorderGradientStyle = () => {
return {
borderImage: `${gradients.primary} 1`,
};
};
export const getTextGradientStyle = () => {
return {
background: gradients.primary,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text',
};
};
```
**Step 2: 创建测试文件**
```typescript
import { getGradientStyle, getGlowStyle, getTextGradientStyle } from '../gradients';
describe('gradients utilities', () => {
test('getGradientStyle returns correct gradient', () => {
const style = getGradientStyle('primary');
expect(style.background).toContain('linear-gradient');
});
test('getGlowStyle returns correct glow for blue', () => {
const style = getGlowStyle('blue', 0.2);
expect(style.background).toContain('rgba(0, 217, 255, 0.2)');
});
test('getGlowStyle returns correct glow for purple', () => {
const style = getGlowStyle('purple', 0.1);
expect(style.background).toContain('rgba(168, 85, 247, 0.1)');
});
test('getTextGradientStyle returns correct text gradient', () => {
const style = getTextGradientStyle();
expect(style.WebkitBackgroundClip).toBe('text');
expect(style.WebkitTextFillColor).toBe('transparent');
});
});
```
**Step 3: 运行测试**
```bash
npm test -- src/lib/gradients.test.ts
```
Expected: 所有测试通过
**Step 4: 提交更改**
```bash
git add src/lib/gradients.ts src/lib/gradients.test.ts
git commit -m "feat: 添加渐变色工具函数
- 创建渐变色样式生成函数
- 创建光晕效果生成函数
- 创建文字渐变效果函数
- 添加单元测试"
```
---
## Phase 2: UI 组件更新
### Task 4: 更新按钮组件
**Files:**
- Modify: `src/components/ui/button.tsx`
**Step 1: 更新按钮样式变体**
```typescript
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-tech-blue)] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-[var(--color-brand-primary)] text-white hover:bg-[var(--color-brand-primary-hover)] hover:shadow-[0_0_20px_rgba(196,30,58,0.4)] hover:-translate-y-0.5 active:scale-[0.98]",
secondary:
"bg-gradient-to-br from-[var(--color-tech-blue)] to-[var(--color-tech-purple)] text-white hover:shadow-[0_0_20px_rgba(0,217,255,0.3)] hover:-translate-y-0.5 active:scale-[0.98]",
outline:
"border border-[var(--color-tech-blue)] bg-transparent text-[var(--color-tech-blue)] hover:bg-[rgba(0,217,255,0.1)] hover:shadow-[0_0_20px_rgba(0,217,255,0.2)]",
ghost:
"text-[var(--color-text-secondary)] hover:bg-[rgba(255,255,255,0.05)] hover:text-[var(--color-text-primary)]",
link:
"text-[var(--color-tech-blue)] underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-12 rounded-lg px-6 text-base",
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, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }
```
**Step 2: 测试按钮组件**
在浏览器中打开网站,检查按钮样式是否正确应用。
**Step 3: 提交更改**
```bash
git add src/components/ui/button.tsx
git commit -m "feat: 更新按钮组件样式
- 更新默认按钮为印章红色
- 添加科技蓝渐变次要按钮
- 更新轮廓按钮样式
- 添加悬停发光效果
- 添加点击缩放反馈"
```
---
### Task 5: 更新卡片组件
**Files:**
- Modify: `src/components/ui/card.tsx`
**Step 1: 更新卡片样式**
```typescript
import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-xl border border-[var(--color-border-primary)] bg-[var(--color-bg-tertiary)] text-[var(--color-text-primary)] transition-all duration-300 hover:border-[var(--color-tech-blue)] hover:shadow-[0_0_30px_rgba(0,217,255,0.15)] hover:-translate-y-1",
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-semibold leading-none tracking-tight text-[var(--color-text-primary)]",
className
)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-[var(--color-text-secondary)]", 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 2: 测试卡片组件**
在浏览器中打开网站,检查卡片样式是否正确应用。
**Step 3: 提交更改**
```bash
git add src/components/ui/card.tsx
git commit -m "feat: 更新卡片组件样式
- 更新卡片背景色为深灰
- 添加悬停边框发光效果
- 添加悬停上移动画
- 更新文字颜色变量"
```
---
### Task 6: 更新导航栏组件
**Files:**
- Modify: `src/components/layout/header.tsx`
**Step 1: 更新导航栏样式**
在导航栏组件中添加新的样式类:
```typescript
// 在 header.tsx 中更新导航栏样式
<header className="fixed top-0 left-0 right-0 z-50 h-16 bg-[rgba(10,10,10,0.8)] backdrop-blur-xl border-b border-[var(--color-border-primary)]">
{/* 导航内容 */}
</header>
```
**Step 2: 更新导航链接样式**
```typescript
// 更新导航链接样式
<a className="text-[var(--color-text-secondary)] hover:text-[var(--color-tech-blue)] transition-colors duration-200 relative group">
{link.name}
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[var(--color-tech-blue)] transition-all duration-200 group-hover:w-full" />
</a>
```
**Step 3: 测试导航栏**
在浏览器中打开网站,检查导航栏样式是否正确应用。
**Step 4: 提交更改**
```bash
git add src/components/layout/header.tsx
git commit -m "feat: 更新导航栏样式
- 更新导航栏背景为半透明深色
- 添加模糊效果
- 更新导航链接悬停效果
- 添加下划线动画"
```
---
## Phase 3: 页面布局优化
### Task 7: 更新 Hero 区域
**Files:**
- Modify: `src/components/sections/hero-section.tsx`
**Step 1: 更新 Hero 区域背景**
```typescript
<section className="relative min-h-screen flex items-center justify-center bg-[var(--color-bg-primary)] overflow-hidden">
{/* 网格背景 */}
<div className="absolute inset-0 opacity-[0.03]" style={{
backgroundImage: 'linear-gradient(var(--color-tech-blue) 1px, transparent 1px), linear-gradient(90deg, var(--color-tech-blue) 1px, transparent 1px)',
backgroundSize: '50px 50px'
}} />
{/* 光晕效果 */}
<div className="absolute top-1/4 left-1/4 w-96 h-96 rounded-full opacity-10" style={{
background: 'radial-gradient(circle, rgba(0, 217, 255, 0.15) 0%, transparent 70%)'
}} />
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 rounded-full opacity-10" style={{
background: 'radial-gradient(circle, rgba(168, 85, 247, 0.15) 0%, transparent 70%)'
}} />
{/* 内容 */}
<div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Hero 内容 */}
</div>
</section>
```
**Step 2: 更新 Hero 文案样式**
```typescript
<h1 className="text-5xl md:text-6xl lg:text-7xl font-bold text-[var(--color-text-primary)] mb-6">
</h1>
<p className="text-xl md:text-2xl text-[var(--color-text-secondary)] mb-8 max-w-2xl">
</p>
```
**Step 3: 测试 Hero 区域**
在浏览器中打开网站,检查 Hero 区域样式是否正确应用。
**Step 4: 提交更改**
```bash
git add src/components/sections/hero-section.tsx
git commit -m "feat: 更新 Hero 区域设计
- 添加网格背景
- 添加科技蓝和紫色光晕效果
- 更新文案样式
- 优化布局结构"
```
---
### Task 8: 创建粒子效果组件
**Files:**
- Create: `src/components/effects/particles.tsx`
**Step 1: 创建粒子效果组件**
```typescript
'use client';
import { useEffect, useRef } from 'react';
import { motion } from 'framer-motion';
interface Particle {
x: number;
y: number;
size: number;
speedX: number;
speedY: number;
color: string;
}
export function Particles() {
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);
// 初始化粒子
const particleCount = 50;
const colors = ['#00D9FF', '#A855F7', '#06B6D4'];
for (let i = 0; i < particleCount; i++) {
particlesRef.current.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
size: Math.random() * 3 + 1,
speedX: (Math.random() - 0.5) * 0.5,
speedY: (Math.random() - 0.5) * 0.5,
color: colors[Math.floor(Math.random() * colors.length)],
});
}
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particlesRef.current.forEach((particle) => {
particle.x += particle.speedX;
particle.y += particle.speedY;
if (particle.x < 0 || particle.x > canvas.width) particle.speedX *= -1;
if (particle.y < 0 || particle.y > canvas.height) particle.speedY *= -1;
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
ctx.fillStyle = particle.color;
ctx.fill();
});
animationRef.current = requestAnimationFrame(animate);
};
animate();
return () => {
window.removeEventListener('resize', resizeCanvas);
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
};
}, []);
return (
<canvas
ref={canvasRef}
className="absolute inset-0 pointer-events-none"
style={{ opacity: 0.6 }}
/>
);
}
```
**Step 2: 在 Hero 区域中使用粒子效果**
```typescript
import { Particles } from '@/components/effects/particles';
export function HeroSection() {
return (
<section className="relative min-h-screen">
<Particles />
{/* 其他内容 */}
</section>
);
}
```
**Step 3: 测试粒子效果**
在浏览器中打开网站,检查粒子效果是否正常运行。
**Step 4: 提交更改**
```bash
git add src/components/effects/particles.tsx src/components/sections/hero-section.tsx
git commit -m "feat: 添加粒子效果组件
- 创建 Canvas 粒子动画
- 使用科技蓝、紫色、青色粒子
- 添加粒子漂浮动画
- 在 Hero 区域中集成"
```
---
### Task 9: 创建数字计数动画组件
**Files:**
- Create: `src/components/effects/count-up.tsx`
**Step 1: 创建数字计数动画组件**
```typescript
'use client';
import { useEffect, useRef, useState } from 'react';
import { useInView } from 'framer-motion';
interface CountUpProps {
end: number;
duration?: number;
prefix?: string;
suffix?: string;
className?: string;
}
export function CountUp({ end, duration = 2000, prefix = '', suffix = '', className }: CountUpProps) {
const ref = useRef<HTMLSpanElement>(null);
const isInView = useInView(ref, { once: true });
const [count, setCount] = useState(0);
useEffect(() => {
if (!isInView) return;
let startTime: number;
let animationFrame: number;
const animate = (currentTime: number) => {
if (!startTime) startTime = currentTime;
const progress = Math.min((currentTime - startTime) / duration, 1);
setCount(Math.floor(progress * end));
if (progress < 1) {
animationFrame = requestAnimationFrame(animate);
}
};
animationFrame = requestAnimationFrame(animate);
return () => {
if (animationFrame) {
cancelAnimationFrame(animationFrame);
}
};
}, [isInView, end, duration]);
return (
<span ref={ref} className={className}>
{prefix}{count.toLocaleString()}{suffix}
</span>
);
}
```
**Step 2: 在数据卡片中使用计数动画**
```typescript
import { CountUp } from '@/components/effects/count-up';
export function DataCard() {
return (
<div className="p-6 rounded-xl border border-[var(--color-border-primary)] bg-[var(--color-bg-tertiary)]">
<CountUp end={1000} suffix="+" className="text-4xl font-bold text-[var(--color-tech-blue)]" />
<p className="text-[var(--color-text-secondary)] mt-2"></p>
</div>
);
}
```
**Step 3: 测试计数动画**
在浏览器中打开网站,检查计数动画是否正常运行。
**Step 4: 提交更改**
```bash
git add src/components/effects/count-up.tsx
git commit -m "feat: 添加数字计数动画组件
- 创建 CountUp 组件
- 支持前缀、后缀
- 支持自定义持续时间
- 使用 Intersection Observer 触发"
```
---
## Phase 4: 动效与交互
### Task 10: 创建滚动揭示 Hook
**Files:**
- Create: `src/hooks/use-scroll-reveal.ts`
**Step 1: 创建滚动揭示 Hook**
```typescript
import { useEffect, useRef, useState } from 'react';
export function useScrollReveal<T extends HTMLElement>(threshold = 0.1) {
const ref = useRef<T>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const element = ref.current;
if (!element) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.unobserve(element);
}
},
{ threshold }
);
observer.observe(element);
return () => {
observer.unobserve(element);
};
}, [threshold]);
return { ref, isVisible };
}
```
**Step 2: 创建滚动揭示组件**
```typescript
'use client';
import { motion } from 'framer-motion';
import { useScrollReveal } from '@/hooks/use-scroll-reveal';
interface ScrollRevealProps {
children: React.ReactNode;
className?: string;
delay?: number;
}
export function ScrollReveal({ children, className, delay = 0 }: ScrollRevealProps) {
const { ref, isVisible } = useScrollReveal<HTMLDivElement>();
return (
<motion.div
ref={ref}
initial={{ opacity: 0, y: 30 }}
animate={isVisible ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.6, delay, ease: [0.16, 1, 0.3, 1] }}
className={className}
>
{children}
</motion.div>
);
}
```
**Step 3: 在页面中使用滚动揭示**
```typescript
import { ScrollReveal } from '@/components/effects/scroll-reveal';
export function ProductsSection() {
return (
<section>
<ScrollReveal>
<h2></h2>
</ScrollReveal>
<div className="grid grid-cols-3 gap-6">
{products.map((product, index) => (
<ScrollReveal key={product.id} delay={index * 0.1}>
<ProductCard product={product} />
</ScrollReveal>
))}
</div>
</section>
);
}
```
**Step 4: 提交更改**
```bash
git add src/hooks/use-scroll-reveal.ts src/components/effects/scroll-reveal.tsx
git commit -m "feat: 添加滚动揭示动效
- 创建 useScrollReveal Hook
- 创建 ScrollReveal 组件
- 支持延迟动画
- 使用 Intersection Observer"
```
---
### Task 11: 创建光晕脉动组件
**Files:**
- Create: `src/components/effects/glow-pulse.tsx`
**Step 1: 创建光晕脉动组件**
```typescript
'use client';
import { motion } from 'framer-motion';
interface GlowPulseProps {
color: 'blue' | 'purple';
size?: number;
className?: string;
}
export function GlowPulse({ color, size = 400, className }: GlowPulseProps) {
const colorValue = color === 'blue' ? '0, 217, 255' : '168, 85, 247';
return (
<motion.div
className={`rounded-full pointer-events-none ${className}`}
style={{
width: size,
height: size,
background: `radial-gradient(circle, rgba(${colorValue}, 0.15) 0%, transparent 70%)`,
}}
animate={{
scale: [1, 1.15, 1],
opacity: [0.1, 0.15, 0.1],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: 'easeInOut',
}}
/>
);
}
```
**Step 2: 在 Hero 区域中使用光晕脉动**
```typescript
import { GlowPulse } from '@/components/effects/glow-pulse';
export function HeroSection() {
return (
<section className="relative">
<GlowPulse color="blue" size={400} className="absolute top-1/4 left-1/4" />
<GlowPulse color="purple" size={400} className="absolute bottom-1/4 right-1/4" />
{/* 其他内容 */}
</section>
);
}
```
**Step 3: 提交更改**
```bash
git add src/components/effects/glow-pulse.tsx
git commit -m "feat: 添加光晕脉动组件
- 创建 GlowPulse 组件
- 支持蓝色和紫色光晕
- 添加脉动动画
- 可自定义大小"
```
---
## Phase 5: 响应式适配
### Task 12: 优化移动端导航
**Files:**
- Modify: `src/components/layout/mobile-menu.tsx`
**Step 1: 更新移动端菜单样式**
```typescript
import { motion } from 'framer-motion';
export function MobileMenu() {
return (
<motion.div
initial={{ opacity: 0, x: '100%' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '100%' }}
transition={{ duration: 0.2 }}
className="fixed inset-0 z-50 bg-[var(--color-bg-primary)]"
>
<div className="flex flex-col h-full">
{/* 菜单项 */}
<nav className="flex-1 px-6 py-8">
{links.map((link) => (
<a
key={link.href}
href={link.href}
className="block py-4 text-lg text-[var(--color-text-primary)] hover:text-[var(--color-tech-blue)] transition-colors"
>
{link.name}
</a>
))}
</nav>
</div>
</motion.div>
);
}
```
**Step 2: 测试移动端导航**
在移动设备或浏览器开发者工具中测试移动端导航。
**Step 3: 提交更改**
```bash
git add src/components/layout/mobile-menu.tsx
git commit -m "feat: 优化移动端导航
- 更新移动端菜单背景色
- 添加滑入动画
- 优化菜单项样式
- 改善触摸体验"
```
---
### Task 13: 优化响应式布局
**Files:**
- Modify: `src/app/(marketing)/page.tsx`
**Step 1: 更新首页响应式布局**
```typescript
export default function HomePage() {
return (
<main>
{/* Hero */}
<section className="min-h-screen flex items-center">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
{/* 内容 */}
</div>
</section>
{/* 产品矩阵 */}
<section className="py-20 md:py-24 lg:py-32">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
{/* 产品卡片 */}
</div>
</div>
</section>
</main>
);
}
```
**Step 2: 测试响应式布局**
在不同设备尺寸下测试页面布局。
**Step 3: 提交更改**
```bash
git add src/app/\(marketing\)/page.tsx
git commit -m "feat: 优化响应式布局
- 更新 Section 间距
- 优化网格布局断点
- 改善移动端体验
- 统一内边距规范"
```
---
## Phase 6: 性能优化与测试
### Task 14: 添加性能监控
**Files:**
- Create: `src/components/analytics/performance-monitor.tsx`
**Step 1: 创建性能监控组件**
```typescript
'use client';
import { useEffect } from 'react';
export function PerformanceMonitor() {
useEffect(() => {
if (typeof window === 'undefined') return;
// 监控 Web Vitals
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log('[Performance]', entry.name, entry.duration);
});
});
observer.observe({ entryTypes: ['measure', 'navigation'] });
return () => observer.disconnect();
}, []);
return null;
}
```
**Step 2: 在布局中添加性能监控**
```typescript
import { PerformanceMonitor } from '@/components/analytics/performance-monitor';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<PerformanceMonitor />
{children}
</body>
</html>
);
}
```
**Step 3: 提交更改**
```bash
git add src/components/analytics/performance-monitor.tsx src/app/layout.tsx
git commit -m "feat: 添加性能监控
- 创建性能监控组件
- 监控 Web Vitals 指标
- 输出性能日志"
```
---
### Task 15: 运行性能测试
**Files:**
- Test: `e2e-tests/tests/test_performance.py`
**Step 1: 运行 Lighthouse 测试**
```bash
npx lighthouse http://localhost:3000 --output=json --output-path=./lighthouse-report.json
```
Expected: 性能分数 ≥ 90
**Step 2: 运行 E2E 性能测试**
```bash
pytest e2e-tests/tests/test_performance.py -v
```
Expected: 所有测试通过
**Step 3: 提交测试报告**
```bash
git add lighthouse-report.json
git commit -m "test: 添加性能测试报告
- 运行 Lighthouse 测试
- 验证性能指标
- 确保性能分数达标"
```
---
## 最终验收
### Task 16: 全面测试与验收
**Step 1: 运行所有测试**
```bash
npm run build
npm run lint
pytest e2e-tests/ -v
```
Expected: 所有测试通过,无错误
**Step 2: 视觉验收**
在浏览器中检查:
- 配色方案是否符合设计
- 组件样式是否正确
- 动效是否流畅
- 响应式布局是否正常
**Step 3: 性能验收**
检查 Lighthouse 报告:
- Performance ≥ 90
- Accessibility ≥ 95
- Best Practices ≥ 90
- SEO ≥ 90
**Step 4: 提交最终版本**
```bash
git add .
git commit -m "feat: 完成 Novalon 官网重新设计
✅ 核心配色系统升级
✅ UI 组件更新
✅ 页面布局优化
✅ 动效与交互增强
✅ 响应式适配完善
✅ 性能优化完成
通过所有测试和验收标准"
```
---
## 总结
本实施计划将 Novalon 官网重新设计方案分解为 **16 个可执行任务**,每个任务都包含:
- 明确的文件路径
- 完整的代码实现
- 具体的测试步骤
- 清晰的提交信息
遵循 **TDD、DRY、YAGNI** 原则,确保高质量交付。
**预计完成时间:** 2-3 个工作日
**下一步:** 选择执行方式