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

31 KiB

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: 备份当前配色变量

cp src/app/globals.css src/app/globals.css.backup

Step 2: 更新深色模式配色变量

.dark 类中更新配色变量:

.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 中更新配色变量:

: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: 提交更改

git add src/app/globals.css
git commit -m "feat: 更新核心配色系统 - 深色/浅色模式

- 更新深色模式配色变量(科技蓝、紫色、印章红)
- 更新浅色模式配色变量
- 添加新的科技色彩变量
- 保持品牌色一致性"

Task 2: 更新 colors.ts 文件

Files:

  • Modify: src/lib/colors.ts:1-69

Step 1: 更新品牌色彩定义

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 编译检查:

npm run build

Expected: 无类型错误

Step 3: 提交更改

git add src/lib/colors.ts
git commit -m "feat: 更新色彩系统定义

- 添加科技蓝、紫色、青色色彩系列
- 更新中性色系列
- 添加渐变色定义
- 完善类型定义"

Task 3: 创建渐变色工具函数

Files:

  • Create: src/lib/gradients.ts

Step 1: 创建渐变色工具函数

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: 创建测试文件

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: 运行测试

npm test -- src/lib/gradients.test.ts

Expected: 所有测试通过

Step 4: 提交更改

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: 更新按钮样式变体

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: 提交更改

git add src/components/ui/button.tsx
git commit -m "feat: 更新按钮组件样式

- 更新默认按钮为印章红色
- 添加科技蓝渐变次要按钮
- 更新轮廓按钮样式
- 添加悬停发光效果
- 添加点击缩放反馈"

Task 5: 更新卡片组件

Files:

  • Modify: src/components/ui/card.tsx

Step 1: 更新卡片样式

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: 提交更改

git add src/components/ui/card.tsx
git commit -m "feat: 更新卡片组件样式

- 更新卡片背景色为深灰
- 添加悬停边框发光效果
- 添加悬停上移动画
- 更新文字颜色变量"

Task 6: 更新导航栏组件

Files:

  • Modify: src/components/layout/header.tsx

Step 1: 更新导航栏样式

在导航栏组件中添加新的样式类:

// 在 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: 更新导航链接样式

// 更新导航链接样式
<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: 提交更改

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 区域背景

<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 文案样式

<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: 提交更改

git add src/components/sections/hero-section.tsx
git commit -m "feat: 更新 Hero 区域设计

- 添加网格背景
- 添加科技蓝和紫色光晕效果
- 更新文案样式
- 优化布局结构"

Task 8: 创建粒子效果组件

Files:

  • Create: src/components/effects/particles.tsx

Step 1: 创建粒子效果组件

'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 区域中使用粒子效果

import { Particles } from '@/components/effects/particles';

export function HeroSection() {
  return (
    <section className="relative min-h-screen">
      <Particles />
      {/* 其他内容 */}
    </section>
  );
}

Step 3: 测试粒子效果

在浏览器中打开网站,检查粒子效果是否正常运行。

Step 4: 提交更改

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: 创建数字计数动画组件

'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: 在数据卡片中使用计数动画

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: 提交更改

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

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: 创建滚动揭示组件

'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: 在页面中使用滚动揭示

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: 提交更改

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: 创建光晕脉动组件

'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 区域中使用光晕脉动

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: 提交更改

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: 更新移动端菜单样式

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: 提交更改

git add src/components/layout/mobile-menu.tsx
git commit -m "feat: 优化移动端导航

- 更新移动端菜单背景色
- 添加滑入动画
- 优化菜单项样式
- 改善触摸体验"

Task 13: 优化响应式布局

Files:

  • Modify: src/app/(marketing)/page.tsx

Step 1: 更新首页响应式布局

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: 提交更改

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: 创建性能监控组件

'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: 在布局中添加性能监控

import { PerformanceMonitor } from '@/components/analytics/performance-monitor';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <PerformanceMonitor />
        {children}
      </body>
    </html>
  );
}

Step 3: 提交更改

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 测试

npx lighthouse http://localhost:3000 --output=json --output-path=./lighthouse-report.json

Expected: 性能分数 ≥ 90

Step 2: 运行 E2E 性能测试

pytest e2e-tests/tests/test_performance.py -v

Expected: 所有测试通过

Step 3: 提交测试报告

git add lighthouse-report.json
git commit -m "test: 添加性能测试报告

- 运行 Lighthouse 测试
- 验证性能指标
- 确保性能分数达标"

最终验收

Task 16: 全面测试与验收

Step 1: 运行所有测试

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: 提交最终版本

git add .
git commit -m "feat: 完成 Novalon 官网重新设计

✅ 核心配色系统升级
✅ UI 组件更新
✅ 页面布局优化
✅ 动效与交互增强
✅ 响应式适配完善
✅ 性能优化完成

通过所有测试和验收标准"

总结

本实施计划将 Novalon 官网重新设计方案分解为 16 个可执行任务,每个任务都包含:

  • 明确的文件路径
  • 完整的代码实现
  • 具体的测试步骤
  • 清晰的提交信息

遵循 TDD、DRY、YAGNI 原则,确保高质量交付。

预计完成时间: 2-3 个工作日

下一步: 选择执行方式