refactor: P0 - remove testimonial, migrate footer & mobile menu to NAVIGATION_V2
- Remove TestimonialSection from homepage (no customers yet) - Footer: dark theme, NAVIGATION_V2 + MEGA_DROPDOWN_DATA links - Mobile Menu: NAVIGATION_V2 with collapsible dropdown support
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,299 @@
|
||||
# 核心业务与解决方案设计升级 实现计划
|
||||
|
||||
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
||||
|
||||
**目标:** 将产品服务页面的成熟设计模式(组件拆分、动画升级、背景特效、独立布局)应用到核心业务和解决方案页面,实现全站设计一致性。
|
||||
|
||||
**架构:** 参照 `src/components/products/` 的 8 个独立 Section 组件模式,为核心业务创建 6 个独立 Section 组件,为解决方案创建 3 个独立 Section 组件。复用 `@/lib/animations` 动画组件库。核心业务详情页采用独立 Header/Footer 布局。
|
||||
|
||||
**技术栈:** Next.js 16 + React 19 + Framer Motion 12 + Tailwind CSS 4 + 自定义动画组件库
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
### 新建文件
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `src/components/services/service-hero-section.tsx` | 服务详情 Hero(InkBackground + DataParticleFlow + SealStamp + InkReveal) |
|
||||
| `src/components/services/service-challenges-section.tsx` | 挑战板块(StaggerContainer + InkCard) |
|
||||
| `src/components/services/service-features-section.tsx` | 功能/如何帮助板块(ScrollReveal + FadeUp + CheckCircle2) |
|
||||
| `src/components/services/service-process-section.tsx` | 服务流程(SealStamp + StaggerContainer + FadeUp + 渐变连接线) |
|
||||
| `src/components/services/service-outcomes-section.tsx` | 成果板块(CountUp + StaggerContainer + InkCard) |
|
||||
| `src/components/services/service-cases-section.tsx` | 相关案例(StaggerContainer + InkCard) |
|
||||
| `src/components/services/service-cta-section.tsx` | CTA 区域(FloatingElement + RippleButton + 红色渐变背景) |
|
||||
| `src/components/solutions/consulting-section.tsx` | 参谋伙伴模块(InkReveal + StaggerContainer + FadeUp) |
|
||||
| `src/components/solutions/tech-solution-section.tsx` | 技术伙伴模块(InkReveal + StaggerContainer + FadeUp) |
|
||||
| `src/components/solutions/accompany-section.tsx` | 同行伙伴模块(InkReveal + StaggerContainer + FadeUp) |
|
||||
| `src/components/layout/service-header.tsx` | 服务详情独立 Header(参照 product-header) |
|
||||
| `src/components/layout/service-footer.tsx` | 服务详情独立 Footer(参照 product-footer) |
|
||||
|
||||
### 修改文件
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `src/app/(marketing)/services/[id]/client.tsx` | 重构:拆分为 7 个独立 Section 组件 + dynamic 懒加载 |
|
||||
| `src/app/(marketing)/services/[id]/page.tsx` | 添加独立布局支持(isServiceDetailPage 判断) |
|
||||
| `src/app/(marketing)/solutions/page.tsx` | 重构:拆分为 3 个独立 Section 组件 + dynamic 懒加载 |
|
||||
| `src/app/(marketing)/layout.tsx` | 添加 ServiceHeader/ServiceFooter 布局切换逻辑 |
|
||||
| `src/lib/constants/services.ts` | 补充 challenges 和 outcomes 数据结构 |
|
||||
|
||||
---
|
||||
|
||||
## 任务 1:数据结构补全
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/lib/constants/services.ts`
|
||||
|
||||
- [ ] **步骤 1:扩展 Service 类型,补充 challenges 和 outcomes 字段**
|
||||
|
||||
将 `client.tsx` 中硬编码的 `challenges` 和 `outcomes` 对象迁移到 `services.ts`,为每个服务添加:
|
||||
- `challenges: Array<{ title: string; description: string }>` — 4 项挑战
|
||||
- `outcomes: Array<{ value: string; label: string }>` — 3 项成果数据
|
||||
|
||||
- [ ] **步骤 2:验证类型导出**
|
||||
|
||||
确认 `SERVICES` 从 `@/lib/constants` 正确导出,新字段可被消费。
|
||||
|
||||
---
|
||||
|
||||
## 任务 2:核心业务 — Hero Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-hero-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceHeroSection 组件**
|
||||
|
||||
参照 `product-hero-section.tsx`,实现:
|
||||
- Props: `{ service: Service }`
|
||||
- 背景:`InkBackground` + `DataParticleFlow`(particleCount=60, color="#C41E3A", intensity="subtle")
|
||||
- 布局:`min-h-screen flex items-center justify-center` + `bg-gradient-to-b from-white to-[#F8F8F8]`
|
||||
- 动画:`SealStamp` 包裹 Badge(delay=0.1),`InkReveal` 包裹 h1(delay=0.2)、描述(delay=0.4)、CTA 按钮(delay=0.6)
|
||||
- CTA:`RippleButton` 主按钮"了解服务详情" + outline 次按钮"免费咨询"
|
||||
- 滚动指示器:`FloatingElement` + ChevronDown
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:核心业务 — 挑战 Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-challenges-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceChallengesSection 组件**
|
||||
|
||||
- Props: `{ service: Service }`
|
||||
- 背景:`bg-[#F8F8F8]`(灰色交替背景)
|
||||
- 标题区:`ScrollReveal` + `slideInLeftVariants` + 朱砂红装饰线
|
||||
- 卡片网格:`StaggerContainer` + `StaggerItem` 包裹 2x2 网格
|
||||
- 每张卡片:`InkCard`(hoverScale=1.02, hoverShadow 带红色调)
|
||||
- 卡片内容:挑战标题 + 描述
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:核心业务 — 功能 Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-features-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceFeaturesSection 组件**
|
||||
|
||||
- Props: `{ service: Service }`
|
||||
- 背景:`bg-white`
|
||||
- 标题区:`ScrollReveal` + `inkRevealVariants`
|
||||
- 概述文字:`InkReveal`(delay=0.2)
|
||||
- 功能列表:`StaggerContainer` + `StaggerItem`,每项用 `CheckCircle2` 图标 + `FadeUp`
|
||||
|
||||
---
|
||||
|
||||
## 任务 5:核心业务 — 流程 Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-process-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceProcessSection 组件**
|
||||
|
||||
- Props: `{ service: Service }`
|
||||
- 背景:`bg-[#F8F8F8]`
|
||||
- 标题区:`ScrollReveal` + `inkRevealVariants` 居中
|
||||
- 步骤列表:`StaggerContainer`(staggerDelay=0.15)+ `StaggerItem`
|
||||
- 每步:`SealStamp` 编号圆形 + `FadeUp` 标题描述 + 渐变连接线(`w-0.5 h-16 bg-gradient-to-b from-[#C41E3A]/40 to-[#C41E3A]/10`,最后一步无连接线)
|
||||
- 文本解析:中文冒号 `:` 分隔标题和描述
|
||||
|
||||
---
|
||||
|
||||
## 任务 6:核心业务 — 成果 Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-outcomes-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceOutcomesSection 组件**
|
||||
|
||||
- Props: `{ service: Service }`
|
||||
- 背景:`bg-white`
|
||||
- 标题区:`ScrollReveal` + `slideInLeftVariants`
|
||||
- 数据卡片:`StaggerContainer` + `StaggerItem` 包裹 3 列网格
|
||||
- 每张卡片:`InkCard` + `CountUp` 数字动画(从 outcomes.value 提取数字)+ 渐变色文字
|
||||
- Benefits 汇总:底部 `InkReveal` 包裹 benefits 文本
|
||||
|
||||
---
|
||||
|
||||
## 任务 7:核心业务 — 案例 Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-cases-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceCasesSection 组件**
|
||||
|
||||
- Props: 无(内部从 `CASES` 常量获取数据)
|
||||
- 背景:`bg-[#F8F8F8]`
|
||||
- 标题区:`ScrollReveal` + `slideInLeftVariants`
|
||||
- 案例网格:`StaggerContainer` + `StaggerItem` 包裹 2 列网格
|
||||
- 每张卡片:`InkCard` + Badge 行业标签 + 标题 + 描述 + hover 效果
|
||||
|
||||
---
|
||||
|
||||
## 任务 8:核心业务 — CTA Section
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/services/service-cta-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceCTASection 组件**
|
||||
|
||||
- Props: 无
|
||||
- 背景:`bg-gradient-to-r from-[#C41E3A] to-[#E85D75]`(红色渐变)
|
||||
- 装饰:两个 `FloatingElement` 圆形(右上 280px + 左下 220px)
|
||||
- 内容:`InkReveal` 标题 + `FadeUp` 描述 + `FadeUp` 按钮组
|
||||
- 按钮:`RippleButton` 主按钮"开始您的转型之旅" + outline 次按钮"查看其他服务"
|
||||
|
||||
---
|
||||
|
||||
## 任务 9:核心业务 — 独立 Header/Footer
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/layout/service-header.tsx`
|
||||
- 创建:`src/components/layout/service-footer.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ServiceHeader**
|
||||
|
||||
参照 `product-header.tsx`:
|
||||
- Logo + "返回主站"按钮
|
||||
- 滚动时 `bg-white/90 backdrop-blur-xl`
|
||||
- `motion.header` 从顶部滑入动画
|
||||
- 区别:CTA 文案改为"免费咨询"
|
||||
|
||||
- [ ] **步骤 2:创建 ServiceFooter**
|
||||
|
||||
参照 `product-footer.tsx`:
|
||||
- 顶部装饰线 + CTA 区域 + 底部信息
|
||||
- 锚点导航改为服务相关(服务概览/面临挑战/服务流程/预期成果/相关案例)
|
||||
- `RippleButton` + `FloatingElement`
|
||||
|
||||
---
|
||||
|
||||
## 任务 10:核心业务 — 重构详情页
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/app/(marketing)/services/[id]/client.tsx`
|
||||
- 修改:`src/app/(marketing)/services/[id]/page.tsx`
|
||||
- 修改:`src/app/(marketing)/layout.tsx`
|
||||
|
||||
- [ ] **步骤 1:重构 client.tsx**
|
||||
|
||||
将当前的单文件 5 板块替换为 7 个 dynamic 懒加载 Section 组件:
|
||||
```tsx
|
||||
const ServiceHeroSection = dynamic(() => import('@/components/services/service-hero-section'), { ssr: false });
|
||||
const ServiceChallengesSection = dynamic(() => import('@/components/services/service-challenges-section'), { ssr: false });
|
||||
const ServiceFeaturesSection = dynamic(() => import('@/components/services/service-features-section'), { ssr: false });
|
||||
const ServiceProcessSection = dynamic(() => import('@/components/services/service-process-section'), { ssr: false });
|
||||
const ServiceOutcomesSection = dynamic(() => import('@/components/services/service-outcomes-section'), { ssr: false });
|
||||
const ServiceCasesSection = dynamic(() => import('@/components/services/service-cases-section'), { ssr: false });
|
||||
const ServiceCTASection = dynamic(() => import('@/components/services/service-cta-section'), { ssr: false });
|
||||
```
|
||||
渲染顺序:Hero → Challenges → Features → Process → Outcomes → Cases → CTA
|
||||
|
||||
- [ ] **步骤 2:修改 layout.tsx 添加服务详情独立布局**
|
||||
|
||||
在 `isProductDetailPage` 逻辑旁添加 `isServiceDetailPage` 判断:
|
||||
- 路径匹配 `/services/[id]` 时使用 `ServiceHeader` + `ServiceFooter`
|
||||
- 其他页面保持 `Header` + `Footer`
|
||||
|
||||
- [ ] **步骤 3:修改 page.tsx 确保数据传递正确**
|
||||
|
||||
确认 `generateStaticParams` 和 `generateMetadata` 正常工作,新字段(challenges, outcomes)正确序列化传递。
|
||||
|
||||
---
|
||||
|
||||
## 任务 11:解决方案 — 拆分模块组件
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/solutions/consulting-section.tsx`
|
||||
- 创建:`src/components/solutions/tech-solution-section.tsx`
|
||||
- 创建:`src/components/solutions/accompany-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:创建 ConsultingSection(参谋伙伴)**
|
||||
|
||||
- Props: 无(内部硬编码内容,或从常量获取)
|
||||
- 背景:`bg-gradient-to-br from-[#FFFBF5] to-white rounded-2xl p-12 border border-[#C41E3A]/20`
|
||||
- 动画升级:`InkReveal` 包裹标题(delay=0),`FadeUp` 包裹描述段落(delay=0.1/0.2/0.3),`StaggerContainer` + `StaggerItem` 包裹核心价值点网格
|
||||
- 保持现有内容和布局结构不变
|
||||
|
||||
- [ ] **步骤 2:创建 TechSolutionSection(技术伙伴)**
|
||||
|
||||
同上模式,delay 递增 0.2。
|
||||
|
||||
- [ ] **步骤 3:创建 AccompanySection(同行伙伴)**
|
||||
|
||||
同上模式,delay 递增 0.4。
|
||||
|
||||
---
|
||||
|
||||
## 任务 12:解决方案 — 重构页面
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/app/(marketing)/solutions/page.tsx`
|
||||
|
||||
- [ ] **步骤 1:重构 solutions/page.tsx**
|
||||
|
||||
将 3 个内联 `motion.section` 替换为 dynamic 懒加载的独立组件:
|
||||
```tsx
|
||||
const ConsultingSection = dynamic(() => import('@/components/solutions/consulting-section'), { ssr: false });
|
||||
const TechSolutionSection = dynamic(() => import('@/components/solutions/tech-solution-section'), { ssr: false });
|
||||
const AccompanySection = dynamic(() => import('@/components/solutions/accompany-section'), { ssr: false });
|
||||
```
|
||||
保持 `MethodologySection` 和底部 CTA 区域不变。
|
||||
|
||||
---
|
||||
|
||||
## 任务 13:验证
|
||||
|
||||
- [ ] **步骤 1:构建验证**
|
||||
|
||||
运行 `npm run build`,确认无 TypeScript 错误、无导入错误。
|
||||
|
||||
- [ ] **步骤 2:页面验证**
|
||||
|
||||
启动 dev server,逐页检查:
|
||||
- `/services` 列表页正常渲染
|
||||
- `/services/software` 详情页:7 个 Section 全部渲染,动画正常
|
||||
- `/services/data` 详情页:同上
|
||||
- `/services/consulting` 详情页:同上
|
||||
- `/services/solutions` 详情页:同上
|
||||
- `/solutions` 页面:3 个模块全部渲染,动画正常
|
||||
- 独立 Header/Footer 在服务详情页正确显示
|
||||
- 主站 Header/Footer 在其他页面正确显示
|
||||
|
||||
- [ ] **步骤 3:Commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "feat: 升级核心业务和解决方案页面设计,对齐产品服务设计体系
|
||||
|
||||
- 核心业务详情页拆分为 7 个独立 Section 组件
|
||||
- 解决方案页拆分为 3 个独立模块组件
|
||||
- 全面接入动画组件库(InkReveal/SealStamp/InkCard/CountUp 等)
|
||||
- Hero 区域添加 InkBackground + DataParticleFlow 背景特效
|
||||
- 服务详情页采用独立 Header/Footer 布局
|
||||
- 服务数据结构补全 challenges 和 outcomes 字段
|
||||
- 所有组件使用 dynamic 懒加载"
|
||||
```
|
||||
@@ -0,0 +1,428 @@
|
||||
# 移除联系电话和更新 Logo 字体 实现计划
|
||||
|
||||
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
||||
|
||||
**目标:** 移除网站中"电话咨询"按钮,并更新 Logo SVG 使用青柳隶书字体
|
||||
|
||||
**架构:** 移除 3 个组件中的"电话咨询"按钮及相关 import,使用青柳隶书字体重新生成 Logo SVG path
|
||||
|
||||
**技术栈:** React, TypeScript, Next.js, SVG
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
| 文件 | 操作 | 职责 |
|
||||
|------|------|------|
|
||||
| `src/components/services/service-cta-section.tsx` | 修改 | 移除"电话咨询"按钮和 Phone 图标 import |
|
||||
| `src/components/products/product-cta-section.tsx` | 修改 | 移除"电话咨询"按钮和 Phone 图标 import |
|
||||
| `src/app/(marketing)/solutions/[id]/solution-detail-client.tsx` | 修改 | 移除"电话咨询"按钮和 Phone 图标 import |
|
||||
| `public/logo.svg` | 替换 | 使用青柳隶书字体重新生成 SVG path |
|
||||
| `public/logo-white.svg` | 替换 | 使用青柳隶书字体重新生成 SVG path |
|
||||
|
||||
---
|
||||
|
||||
## 任务 1:移除 service-cta-section.tsx 中的"电话咨询"按钮
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/components/services/service-cta-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:读取文件内容**
|
||||
|
||||
运行:读取 `src/components/services/service-cta-section.tsx`
|
||||
|
||||
- [ ] **步骤 2:移除 Phone 图标 import**
|
||||
|
||||
修改文件,将:
|
||||
```tsx
|
||||
import { Phone } from 'lucide-react';
|
||||
```
|
||||
改为:
|
||||
```tsx
|
||||
```
|
||||
(删除整行)
|
||||
|
||||
- [ ] **步骤 3:移除"电话咨询"按钮**
|
||||
|
||||
修改文件,删除以下代码块:
|
||||
```tsx
|
||||
<RippleButton
|
||||
href="tel:+8613800138000"
|
||||
rippleColor="rgba(255, 255, 255, 0.2)"
|
||||
className="bg-transparent border-2 border-white text-white px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center w-full sm:w-auto"
|
||||
>
|
||||
<Phone className="w-4 h-4 mr-2" />
|
||||
电话咨询
|
||||
</RippleButton>
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:验证修改**
|
||||
|
||||
运行:`pnpm build`
|
||||
预期:构建成功,无错误
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add src/components/services/service-cta-section.tsx
|
||||
git commit -m "refactor(services): 移除电话咨询按钮
|
||||
|
||||
- 移除 service-cta-section 中的电话咨询按钮
|
||||
- 移除 Phone 图标 import
|
||||
- 公司暂无对外联系电话"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 2:移除 product-cta-section.tsx 中的"电话咨询"按钮
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/components/products/product-cta-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:读取文件内容**
|
||||
|
||||
运行:读取 `src/components/products/product-cta-section.tsx`
|
||||
|
||||
- [ ] **步骤 2:移除 Phone 图标 import**
|
||||
|
||||
修改文件,将:
|
||||
```tsx
|
||||
import { Phone } from 'lucide-react';
|
||||
```
|
||||
改为:
|
||||
```tsx
|
||||
```
|
||||
(删除整行)
|
||||
|
||||
- [ ] **步骤 3:移除"电话咨询"按钮**
|
||||
|
||||
修改文件,删除以下代码块:
|
||||
```tsx
|
||||
<RippleButton
|
||||
href="tel:+8613800138000"
|
||||
rippleColor="rgba(255, 255, 255, 0.2)"
|
||||
className="bg-transparent border-2 border-white text-white px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center w-full sm:w-auto"
|
||||
>
|
||||
<Phone className="w-4 h-4 mr-2" />
|
||||
电话咨询
|
||||
</RippleButton>
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:验证修改**
|
||||
|
||||
运行:`pnpm build`
|
||||
预期:构建成功,无错误
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add src/components/products/product-cta-section.tsx
|
||||
git commit -m "refactor(products): 移除电话咨询按钮
|
||||
|
||||
- 移除 product-cta-section 中的电话咨询按钮
|
||||
- 移除 Phone 图标 import
|
||||
- 公司暂无对外联系电话"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:移除 solution-detail-client.tsx 中的"电话咨询"按钮
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/app/(marketing)/solutions/[id]/solution-detail-client.tsx`
|
||||
|
||||
- [ ] **步骤 1:读取文件内容**
|
||||
|
||||
运行:读取 `src/app/(marketing)/solutions/[id]/solution-detail-client.tsx`
|
||||
|
||||
- [ ] **步骤 2:查找并移除"电话咨询"按钮**
|
||||
|
||||
找到包含"电话咨询"的按钮代码并删除:
|
||||
```tsx
|
||||
<Button variant="outline" asChild>
|
||||
<a href="tel:+8613800138000">
|
||||
<Phone className="w-4 h-4 mr-2" />
|
||||
电话咨询
|
||||
</a>
|
||||
</Button>
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:检查并移除 Phone 图标 import(如果不再使用)**
|
||||
|
||||
检查文件中是否还有其他地方使用 Phone 图标。如果没有,删除:
|
||||
```tsx
|
||||
import { Phone } from 'lucide-react';
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:验证修改**
|
||||
|
||||
运行:`pnpm build`
|
||||
预期:构建成功,无错误
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add src/app/\(marketing\)/solutions/\[id\]/solution-detail-client.tsx
|
||||
git commit -m "refactor(solutions): 移除电话咨询按钮
|
||||
|
||||
- 移除 solution-detail-client 中的电话咨询按钮
|
||||
- 移除 Phone 图标 import(如果不再使用)
|
||||
- 公司暂无对外联系电话"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:使用青柳隶书字体重新生成 Logo SVG
|
||||
|
||||
**文件:**
|
||||
- 替换:`public/logo.svg`
|
||||
- 替换:`public/logo-white.svg`
|
||||
|
||||
- [ ] **步骤 1:检查青柳隶书字体文件**
|
||||
|
||||
运行:检查 `src/app/fonts/AoyagiReisho.ttf` 是否存在
|
||||
|
||||
- [ ] **步骤 2:使用 Python 脚本生成新的 Logo SVG**
|
||||
|
||||
创建并运行 Python 脚本,使用青柳隶书字体生成"睿新致遠"的 SVG path:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
使用青柳隶书字体生成 Logo SVG path
|
||||
"""
|
||||
import os
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.pens.svgPathPen import SvgPathPen
|
||||
from fontTools.pens.t2CharStringPen import T2CharStringPen
|
||||
|
||||
def get_glyph_path(font_path, text, size=48):
|
||||
"""
|
||||
获取文本的 SVG path
|
||||
"""
|
||||
font = TTFont(font_path)
|
||||
glyf_table = font['glyf']
|
||||
|
||||
paths = []
|
||||
x_offset = 0
|
||||
|
||||
for char in text:
|
||||
glyph_name = font.getBestCmap().get(ord(char))
|
||||
if glyph_name:
|
||||
glyph = glyf_table[glyph_name]
|
||||
if glyph.numberOfContours > 0:
|
||||
pen = SvgPathPen(None)
|
||||
glyph.draw(pen, glyf_table)
|
||||
path = pen.getCommands()
|
||||
paths.append(f'<g transform="translate({x_offset}, 0) scale({size/1000})"><path d="{path}" /></g>')
|
||||
x_offset += size * 1.2
|
||||
|
||||
return '\n'.join(paths)
|
||||
|
||||
def generate_logo_svg():
|
||||
"""
|
||||
生成 Logo SVG
|
||||
"""
|
||||
font_path = 'src/app/fonts/AoyagiReisho.ttf'
|
||||
text = '睿新致遠'
|
||||
|
||||
if not os.path.exists(font_path):
|
||||
print(f"错误:字体文件不存在:{font_path}")
|
||||
return
|
||||
|
||||
# 生成 SVG path
|
||||
paths = get_glyph_path(font_path, text)
|
||||
|
||||
# 创建 SVG
|
||||
svg_template = f'''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 120" width="480" height="120">
|
||||
<defs>
|
||||
<!-- 印章纹理滤镜 -->
|
||||
<filter id="sealTexture" x="0%" y="0%" width="100%" height="100%">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.1" numOctaves="3" result="noise"/>
|
||||
<feDisplacementMap in="SourceGraphic" in2="noise" scale="2" xChannelSelector="R" yChannelSelector="G"/>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- 红色印章 - 手绘不规则风格 -->
|
||||
<g transform="translate(12, 12)">
|
||||
<!-- 印章外框 - 不规则手绘路径 -->
|
||||
<path d="M8,2
|
||||
C25,-2 45,-2 72,3
|
||||
C82,5 85,12 84,25
|
||||
C83,40 85,55 84,70
|
||||
C83,82 78,88 65,89
|
||||
C45,91 25,90 10,88
|
||||
C2,86 -2,78 1,65
|
||||
C3,50 2,35 1,20
|
||||
C0,10 3,4 8,2 Z"
|
||||
fill="#C41E3A"/>
|
||||
<!-- 印章内框 - 手绘风格 -->
|
||||
<path d="M14,10
|
||||
C28,8 55,8 72,12
|
||||
C78,14 79,20 78,30
|
||||
C77,45 78,60 77,72
|
||||
C76,80 72,84 62,85
|
||||
C45,86 28,85 16,83
|
||||
C10,82 8,76 9,65
|
||||
C10,50 9,35 8,22
|
||||
C7,15 10,11 14,10 Z"
|
||||
fill="none" stroke="#fff" stroke-width="1.5" opacity="0.5"/>
|
||||
<!-- 睿新致遠 - 青柳隶书字体路径 -->
|
||||
{paths}
|
||||
</g>
|
||||
|
||||
<!-- 公司名称 -->
|
||||
<g transform="translate(110, 60)">
|
||||
<!-- 睿新致遠 - 青柳隶书字体路径 -->
|
||||
{paths}
|
||||
<!-- NOVALON - 英文字体 -->
|
||||
<text x="24" y="42" font-family="Arial, sans-serif" font-size="14.5" font-weight="500" fill="currentColor" letter-spacing="10.5">NOVALON</text>
|
||||
</g>
|
||||
</svg>'''
|
||||
|
||||
return svg_template
|
||||
|
||||
if __name__ == '__main__':
|
||||
svg_content = generate_logo_svg()
|
||||
if svg_content:
|
||||
with open('public/logo.svg', 'w', encoding='utf-8') as f:
|
||||
f.write(svg_content)
|
||||
print("Logo SVG 已生成:public/logo.svg")
|
||||
```
|
||||
|
||||
运行脚本:
|
||||
```bash
|
||||
python3 scripts/generate-logo-svg.py
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:生成白色版本 Logo**
|
||||
|
||||
复制生成的 Logo SVG 并修改颜色:
|
||||
```bash
|
||||
cp public/logo.svg public/logo-white.svg
|
||||
```
|
||||
|
||||
修改 `public/logo-white.svg`,将 `fill="#C41E3A"` 改为 `fill="white"`
|
||||
|
||||
- [ ] **步骤 4:验证 Logo 显示**
|
||||
|
||||
运行:`pnpm dev`
|
||||
访问:http://localhost:3000
|
||||
预期:Logo 正确显示,使用青柳隶书字体
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add public/logo.svg public/logo-white.svg
|
||||
git commit -m "style(logo): 使用青柳隶书字体更新 Logo
|
||||
|
||||
- 使用青柳隶书字体重新生成 Logo SVG path
|
||||
- 更新 logo.svg 和 logo-white.svg
|
||||
- 确保品牌字体一致性"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 5:运行完整测试并验证
|
||||
|
||||
**文件:**
|
||||
- 无文件修改
|
||||
|
||||
- [ ] **步骤 1:运行构建**
|
||||
|
||||
运行:`pnpm build`
|
||||
预期:构建成功,无错误
|
||||
|
||||
- [ ] **步骤 2:运行 E2E 测试**
|
||||
|
||||
运行:`pnpm test`
|
||||
预期:所有测试通过
|
||||
|
||||
- [ ] **步骤 3:手动验证关键页面**
|
||||
|
||||
访问以下页面验证:
|
||||
- 首页:http://localhost:3000
|
||||
- 服务页面:http://localhost:3000/services
|
||||
- 产品页面:http://localhost:3000/products
|
||||
- 解决方案详情页:http://localhost:3000/solutions/[id]
|
||||
- 联系页面:http://localhost:3000/contact
|
||||
|
||||
验证内容:
|
||||
- ✅ Logo 显示正确
|
||||
- ✅ 无"电话咨询"按钮
|
||||
- ✅ 联系表单电话字段正常显示
|
||||
|
||||
- [ ] **步骤 4:最终 Commit(如有遗漏)**
|
||||
|
||||
如果有遗漏的修改,在此步骤提交。
|
||||
|
||||
---
|
||||
|
||||
## 任务 6:部署到生产环境
|
||||
|
||||
**文件:**
|
||||
- 无文件修改
|
||||
|
||||
- [ ] **步骤 1:推送代码到远程**
|
||||
|
||||
运行:`git push origin main`
|
||||
预期:推送成功
|
||||
|
||||
- [ ] **步骤 2:构建生产版本**
|
||||
|
||||
运行:`pnpm build`
|
||||
预期:构建成功
|
||||
|
||||
- [ ] **步骤 3:部署到生产服务器**
|
||||
|
||||
运行:`./deploy-dist.sh`
|
||||
预期:部署成功
|
||||
|
||||
- [ ] **步骤 4:验证生产环境**
|
||||
|
||||
访问:https://novalon.cn
|
||||
验证内容:
|
||||
- ✅ Logo 显示正确
|
||||
- ✅ 无"电话咨询"按钮
|
||||
- ✅ 联系表单电话字段正常显示
|
||||
|
||||
---
|
||||
|
||||
## 自检清单
|
||||
|
||||
### 1. 规格覆盖度
|
||||
|
||||
| 规格需求 | 对应任务 |
|
||||
|---------|---------|
|
||||
| 移除 service-cta-section.tsx 中的"电话咨询"按钮 | 任务 1 |
|
||||
| 移除 product-cta-section.tsx 中的"电话咨询"按钮 | 任务 2 |
|
||||
| 移除 solution-detail-client.tsx 中的"电话咨询"按钮 | 任务 3 |
|
||||
| 更新 Logo SVG 使用青柳隶书字体 | 任务 4 |
|
||||
| 保留联系表单电话字段 | 无需修改(已确认) |
|
||||
| 测试验证 | 任务 5 |
|
||||
| 部署生产 | 任务 6 |
|
||||
|
||||
### 2. 占位符扫描
|
||||
|
||||
- ✅ 无"待定"、"TODO"、"后续实现"等占位符
|
||||
- ✅ 所有代码步骤包含完整代码
|
||||
- ✅ 所有命令步骤包含完整命令
|
||||
- ✅ 无"类似任务 N"的引用
|
||||
|
||||
### 3. 类型一致性
|
||||
|
||||
- ✅ 所有文件路径使用精确路径
|
||||
- ✅ 所有组件名称一致
|
||||
- ✅ 所有 import 语句正确
|
||||
|
||||
---
|
||||
|
||||
## 执行选项
|
||||
|
||||
**计划已完成并保存到 `docs/superpowers/plans/2026-04-25-remove-phone-and-update-logo-font.md`。两种执行方式:**
|
||||
|
||||
**1. 子代理驱动(推荐)** - 每个任务调度一个新的子代理,任务间进行审查,快速迭代
|
||||
|
||||
**2. 内联执行** - 在当前会话中使用 executing-plans 执行任务,批量执行并设有检查点
|
||||
|
||||
**选哪种方式?**
|
||||
@@ -0,0 +1,671 @@
|
||||
# 前沿技术升级 Phase 1 实现计划:View Transitions + SVG drawSVG + Container Queries
|
||||
|
||||
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
||||
|
||||
**目标:** 在不改变现有静态导出架构的前提下,引入 View Transitions API 实现跨页面流畅过渡、SVG 路径动画实现品牌标题毛笔书写效果、Container Queries 实现组件级响应式布局。
|
||||
|
||||
**架构:** 三项技术均为渐进增强——View Transitions 作为浏览器原生 API 零运行时依赖;SVG drawSVG 基于 GSAP 的 SVG 路径动画插件,仅在品牌标题组件中引入;Container Queries 为纯 CSS 特性,替换现有媒体查询驱动的组件布局。三项改动互不耦合,可独立交付。
|
||||
|
||||
**技术栈:** React 19.2 View Transitions API、GSAP 3 + DrawSVGPlugin、CSS Container Queries、Next.js 16 App Router
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
### 新建文件
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `src/components/ui/view-transition.tsx` | View Transition 封装组件,提供声明式 API |
|
||||
| `src/components/ui/calligraphy-title.tsx` | 品牌标题 SVG 书写动画组件 |
|
||||
| `src/components/ui/calligraphy-title.test.tsx` | 品牌标题组件测试 |
|
||||
| `src/components/ui/view-transition.test.tsx` | View Transition 组件测试 |
|
||||
| `public/brand/ruixin-zhiyuan.svg` | "睿新致遠" SVG 路径数据 |
|
||||
|
||||
### 修改文件
|
||||
| 文件 | 变更内容 |
|
||||
|------|---------|
|
||||
| `src/app/(marketing)/layout.tsx` | 包裹 ViewTransition,实现跨页面过渡 |
|
||||
| `src/components/sections/hero-section.tsx` | 替换 HeroTitle 为 CalligraphyTitle |
|
||||
| `src/components/sections/hero-section-atoms.tsx` | 移除旧 HeroTitle,改用 CalligraphyTitle |
|
||||
| `src/components/ui/animated-card.tsx` | 添加 Container Query 支持 |
|
||||
| `src/components/sections/products-section.tsx` | 产品卡片容器添加 container-type |
|
||||
| `src/components/sections/services-section.tsx` | 服务卡片容器添加 container-type |
|
||||
| `src/app/globals.css` | 添加 View Transition 关键帧、Container Query 样式 |
|
||||
| `package.json` | 添加 gsap 依赖 |
|
||||
|
||||
---
|
||||
|
||||
## 任务 1:View Transitions API 基础封装
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/ui/view-transition.tsx`
|
||||
- 创建:`src/components/ui/view-transition.test.tsx`
|
||||
|
||||
- [ ] **步骤 1:编写失败的测试**
|
||||
|
||||
```tsx
|
||||
// src/components/ui/view-transition.test.tsx
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { ViewTransitionWrapper } from './view-transition';
|
||||
|
||||
describe('ViewTransitionWrapper', () => {
|
||||
it('renders children when View Transitions API is not supported', () => {
|
||||
const originalStartViewTransition = document.startViewTransition;
|
||||
// @ts-expect-error - testing fallback
|
||||
document.startViewTransition = undefined;
|
||||
|
||||
render(
|
||||
<ViewTransitionWrapper name="hero-title">
|
||||
<h1>Test Content</h1>
|
||||
</ViewTransitionWrapper>
|
||||
);
|
||||
|
||||
expect(screen.getByText('Test Content')).toBeInTheDocument();
|
||||
|
||||
// @ts-expect-error - restore
|
||||
document.startViewTransition = originalStartViewTransition;
|
||||
});
|
||||
|
||||
it('applies view-transition-name style when name prop is provided', () => {
|
||||
render(
|
||||
<ViewTransitionWrapper name="hero-title">
|
||||
<h1>Test Content</h1>
|
||||
</ViewTransitionWrapper>
|
||||
);
|
||||
|
||||
const element = screen.getByText('Test Content').parentElement;
|
||||
expect(element?.style.viewTransitionName).toBe('hero-title');
|
||||
});
|
||||
|
||||
it('renders without name prop (no view-transition-name)', () => {
|
||||
render(
|
||||
<ViewTransitionWrapper>
|
||||
<h1>Test Content</h1>
|
||||
</ViewTransitionWrapper>
|
||||
);
|
||||
|
||||
const element = screen.getByText('Test Content').parentElement;
|
||||
expect(element?.style.viewTransitionName).toBe('');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行测试验证失败**
|
||||
|
||||
运行:`npx vitest run src/components/ui/view-transition.test.tsx`
|
||||
预期:FAIL — 模块 `./view-transition` 不存在
|
||||
|
||||
- [ ] **步骤 3:编写最少实现代码**
|
||||
|
||||
```tsx
|
||||
// src/components/ui/view-transition.tsx
|
||||
'use client';
|
||||
|
||||
import { type ReactNode, type CSSProperties } from 'react';
|
||||
|
||||
interface ViewTransitionWrapperProps {
|
||||
children: ReactNode;
|
||||
name?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ViewTransitionWrapper({
|
||||
children,
|
||||
name,
|
||||
className = '',
|
||||
}: ViewTransitionWrapperProps) {
|
||||
const style: CSSProperties = name
|
||||
? { viewTransitionName: name }
|
||||
: {};
|
||||
|
||||
return (
|
||||
<div style={style} className={className}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:运行测试验证通过**
|
||||
|
||||
运行:`npx vitest run src/components/ui/view-transition.test.tsx`
|
||||
预期:PASS
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add src/components/ui/view-transition.tsx src/components/ui/view-transition.test.tsx
|
||||
git commit -m "feat: add ViewTransitionWrapper component with progressive enhancement"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 2:View Transitions 跨页面过渡集成
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/app/(marketing)/layout.tsx`
|
||||
- 修改:`src/app/globals.css`
|
||||
|
||||
- [ ] **步骤 1:在 globals.css 添加 View Transition 关键帧**
|
||||
|
||||
在 `src/app/globals.css` 的 `@layer base` 块末尾添加:
|
||||
|
||||
```css
|
||||
/* View Transitions - 跨页面过渡动画 */
|
||||
@keyframes vt-fade-in {
|
||||
from { opacity: 0; transform: translateY(8px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes vt-fade-out {
|
||||
from { opacity: 1; transform: translateY(0); }
|
||||
to { opacity: 0; transform: translateY(-8px); }
|
||||
}
|
||||
|
||||
@keyframes vt-hero-enter {
|
||||
from { opacity: 0; clip-path: circle(0% at 50% 50%); }
|
||||
to { opacity: 1; clip-path: circle(75% at 50% 50%); }
|
||||
}
|
||||
|
||||
::view-transition-old(root) {
|
||||
animation: vt-fade-out 0.2s cubic-bezier(0.16, 1, 0.3, 1) both;
|
||||
}
|
||||
|
||||
::view-transition-new(root) {
|
||||
animation: vt-fade-in 0.35s cubic-bezier(0.16, 1, 0.3, 1) both;
|
||||
}
|
||||
|
||||
::view-transition-old(hero-title) {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
::view-transition-new(hero-title) {
|
||||
animation: vt-hero-enter 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
::view-transition-old(root),
|
||||
::view-transition-new(root) {
|
||||
animation: none !important;
|
||||
}
|
||||
::view-transition-old(hero-title),
|
||||
::view-transition-new(hero-title) {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:修改 MarketingLayout 集成 View Transitions**
|
||||
|
||||
在 `src/app/(marketing)/layout.tsx` 中,将主内容区域包裹 ViewTransitionWrapper:
|
||||
|
||||
找到 `export default function MarketingLayout` 函数,在 children 外层添加 ViewTransitionWrapper:
|
||||
|
||||
```tsx
|
||||
// 在文件顶部添加导入
|
||||
import { ViewTransitionWrapper } from '@/components/ui/view-transition';
|
||||
|
||||
// 在 return 的 children 包裹处,找到所有渲染 children 的位置
|
||||
// 对主站布局的 children 添加 ViewTransitionWrapper:
|
||||
<ViewTransitionWrapper name="page-content">
|
||||
{children}
|
||||
</ViewTransitionWrapper>
|
||||
|
||||
// 对产品详情页布局的 children 添加:
|
||||
<ViewTransitionWrapper name="product-content">
|
||||
{children}
|
||||
</ViewTransitionWrapper>
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:在 HeroSection 中标记共享元素**
|
||||
|
||||
修改 `src/components/sections/hero-section.tsx`,对品牌标题添加 view-transition-name:
|
||||
|
||||
找到 HeroTitle 的渲染位置,在其外层包裹:
|
||||
|
||||
```tsx
|
||||
<ViewTransitionWrapper name="hero-title">
|
||||
<HeroTitle isVisible={isVisible} />
|
||||
</ViewTransitionWrapper>
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:验证 View Transitions 工作正常**
|
||||
|
||||
运行:`npm run dev`
|
||||
操作:在首页和各子页面之间导航,观察页面过渡动画
|
||||
预期:页面切换时有淡入淡出效果,品牌标题有圆形展开动画
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add src/app/globals.css src/app/\(marketing\)/layout.tsx src/components/sections/hero-section.tsx
|
||||
git commit -m "feat: integrate View Transitions API for cross-page transitions"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:GSAP 安装与 SVG 品牌标题路径准备
|
||||
|
||||
**文件:**
|
||||
- 创建:`public/brand/ruixin-zhiyuan.svg`
|
||||
|
||||
- [ ] **步骤 1:安装 GSAP**
|
||||
|
||||
运行:`npm install gsap`
|
||||
|
||||
- [ ] **步骤 2:创建"睿新致遠"SVG 路径文件**
|
||||
|
||||
将品牌标题转为 SVG path 数据。由于青柳隷書字体已内嵌,需要用字体渲染后提取路径。
|
||||
|
||||
创建 `public/brand/ruixin-zhiyuan.svg`:
|
||||
|
||||
```svg
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 200" fill="none">
|
||||
<!-- 睿 -->
|
||||
<path class="stroke-1" d="M80,40 L80,160 M50,60 L110,60 M50,100 L110,100 M40,140 L120,140 M50,40 L50,160 M110,40 L110,160" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
<!-- 新 -->
|
||||
<path class="stroke-2" d="M200,40 L200,160 M170,60 L230,60 M170,100 L230,100 M160,140 L240,140 M170,40 L170,160 M230,40 L230,160 M200,100 L230,140" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
<!-- 致 -->
|
||||
<path class="stroke-3" d="M320,40 L320,160 M290,60 L350,60 M290,100 L350,100 M280,140 L360,140 M290,40 L290,160 M350,40 L350,160" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
<!-- 遠 -->
|
||||
<path class="stroke-4" d="M440,40 L440,160 M410,60 L470,60 M410,100 L470,100 M400,140 L480,140 M410,40 L410,160 M470,40 L470,160 M440,100 L470,140 M400,80 L440,120" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
</svg>
|
||||
```
|
||||
|
||||
> **注意**:上述 SVG 为占位骨架。实际生产需使用字体转 SVG 工具(如 opentype.js 或在线工具 text-to-svg)从青柳隷書字体提取精确路径。此步骤在实现时需用脚本从 `src/app/fonts/AoyagiReisho.ttf` 提取。
|
||||
|
||||
- [ ] **步骤 3:验证 SVG 可访问**
|
||||
|
||||
运行:`npm run dev`
|
||||
访问:`http://localhost:3000/brand/ruixin-zhiyuan.svg`
|
||||
预期:SVG 文件可正常加载
|
||||
|
||||
- [ ] **步骤 4:Commit**
|
||||
|
||||
```bash
|
||||
git add package.json package-lock.json public/brand/ruixin-zhiyuan.svg
|
||||
git commit -m "feat: add GSAP dependency and brand title SVG path data"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:CalligraphyTitle 组件实现
|
||||
|
||||
**文件:**
|
||||
- 创建:`src/components/ui/calligraphy-title.tsx`
|
||||
- 创建:`src/components/ui/calligraphy-title.test.tsx`
|
||||
|
||||
- [ ] **步骤 1:编写失败的测试**
|
||||
|
||||
```tsx
|
||||
// src/components/ui/calligraphy-title.test.tsx
|
||||
import { render, screen, act } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { CalligraphyTitle } from './calligraphy-title';
|
||||
|
||||
describe('CalligraphyTitle', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
it('renders the title text as fallback', () => {
|
||||
render(<CalligraphyTitle text="睿新致遠" />);
|
||||
expect(screen.getByText('睿新致遠')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('applies brand font family', () => {
|
||||
render(<CalligraphyTitle text="睿新致遠" />);
|
||||
const element = screen.getByText('睿新致遠');
|
||||
expect(element.style.fontFamily).toContain('Aoyagi Reisho');
|
||||
});
|
||||
|
||||
it('respects reduced motion preference', () => {
|
||||
const matchMediaSpy = vi.spyOn(window, 'matchMedia').mockImplementation(
|
||||
(query: string) => ({
|
||||
matches: query === '(prefers-reduced-motion: reduce)',
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: vi.fn(),
|
||||
removeListener: vi.fn(),
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
dispatchEvent: vi.fn(),
|
||||
})
|
||||
);
|
||||
|
||||
render(<CalligraphyTitle text="睿新致遠" />);
|
||||
const element = screen.getByText('睿新致遠');
|
||||
expect(element).toHaveStyle({ opacity: '1' });
|
||||
|
||||
matchMediaSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
render(<CalligraphyTitle text="睿新致遠" className="custom-class" />);
|
||||
const element = screen.getByText('睿新致遠').closest('.custom-class');
|
||||
expect(element).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行测试验证失败**
|
||||
|
||||
运行:`npx vitest run src/components/ui/calligraphy-title.test.tsx`
|
||||
预期:FAIL — 模块 `./calligraphy-title` 不存在
|
||||
|
||||
- [ ] **步骤 3:编写最少实现代码**
|
||||
|
||||
```tsx
|
||||
// src/components/ui/calligraphy-title.tsx
|
||||
'use client';
|
||||
|
||||
import { useRef, useEffect, useState } from 'react';
|
||||
import { gsap } from 'gsap';
|
||||
import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin';
|
||||
|
||||
gsap.registerPlugin(DrawSVGPlugin);
|
||||
|
||||
interface CalligraphyTitleProps {
|
||||
text: string;
|
||||
className?: string;
|
||||
duration?: number;
|
||||
stagger?: number;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export function CalligraphyTitle({
|
||||
text,
|
||||
className = '',
|
||||
duration = 2.5,
|
||||
stagger = 0.4,
|
||||
delay = 0.3,
|
||||
}: CalligraphyTitleProps) {
|
||||
const svgRef = useRef<SVGSVGElement>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
setPrefersReducedMotion(mq.matches);
|
||||
|
||||
const handler = (e: MediaQueryListEvent) => setPrefersReducedMotion(e.matches);
|
||||
mq.addEventListener('change', handler);
|
||||
return () => mq.removeEventListener('change', handler);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (prefersReducedMotion || !svgRef.current) return;
|
||||
|
||||
const paths = svgRef.current.querySelectorAll('path');
|
||||
if (paths.length === 0) return;
|
||||
|
||||
gsap.set(paths, { drawSVG: '0%' });
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
gsap.fromTo(
|
||||
paths,
|
||||
{ drawSVG: '0%' },
|
||||
{
|
||||
drawSVG: '100%',
|
||||
duration,
|
||||
stagger,
|
||||
delay,
|
||||
ease: 'power2.inOut',
|
||||
}
|
||||
);
|
||||
}, svgRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, [prefersReducedMotion, duration, stagger, delay]);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className={`calligraphy-title ${className}`}>
|
||||
<svg
|
||||
ref={svgRef}
|
||||
viewBox="0 0 800 200"
|
||||
className="w-full h-auto"
|
||||
aria-hidden="true"
|
||||
style={{ display: prefersReducedMotion ? 'none' : 'block' }}
|
||||
>
|
||||
<use href="/brand/ruixin-zhiyuan.svg#strokes" />
|
||||
</svg>
|
||||
<span
|
||||
className={prefersReducedMotion ? '' : 'sr-only'}
|
||||
style={{
|
||||
fontFamily: "var(--font-aoyagi-reisho), 'Aoyagi Reisho', 'Ma Shan Zheng', serif",
|
||||
fontWeight: 'normal',
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:运行测试验证通过**
|
||||
|
||||
运行:`npx vitest run src/components/ui/calligraphy-title.test.tsx`
|
||||
预期:PASS
|
||||
|
||||
- [ ] **步骤 5:Commit**
|
||||
|
||||
```bash
|
||||
git add src/components/ui/calligraphy-title.tsx src/components/ui/calligraphy-title.test.tsx
|
||||
git commit -m "feat: add CalligraphyTitle component with GSAP DrawSVG animation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 5:集成 CalligraphyTitle 到 Hero 区域
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/components/sections/hero-section-atoms.tsx`
|
||||
- 修改:`src/components/sections/hero-section.tsx`
|
||||
|
||||
- [ ] **步骤 1:替换 HeroTitle 组件**
|
||||
|
||||
在 `src/components/sections/hero-section-atoms.tsx` 中,修改 `HeroTitle` 函数:
|
||||
|
||||
```tsx
|
||||
// 替换现有 HeroTitle 实现
|
||||
import { CalligraphyTitle } from '@/components/ui/calligraphy-title';
|
||||
|
||||
export function HeroTitle(_props: HeroContentProps) {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
|
||||
if (shouldReduceMotion) {
|
||||
return (
|
||||
<h1
|
||||
id="hero-heading"
|
||||
className="text-5xl sm:text-6xl lg:text-7xl tracking-tight mb-6"
|
||||
style={{
|
||||
fontFamily: "var(--font-aoyagi-reisho), 'Ma Shan Zheng', 'ZCOOL XiaoWei', 'STKaiti', 'KaiTi', serif",
|
||||
fontWeight: 'normal',
|
||||
WebkitFontSmoothing: 'antialiased',
|
||||
MozOsxFontSmoothing: 'grayscale',
|
||||
textRendering: 'optimizeLegibility',
|
||||
}}
|
||||
>
|
||||
{COMPANY_INFO.shortName}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CalligraphyTitle
|
||||
text={COMPANY_INFO.shortName}
|
||||
className="text-5xl sm:text-6xl lg:text-7xl tracking-tight mb-6"
|
||||
duration={2.5}
|
||||
stagger={0.4}
|
||||
delay={0.3}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:移除旧的 InkReveal 包裹**
|
||||
|
||||
在 `src/components/sections/hero-section-atoms.tsx` 中,移除 `HeroTitle` 中的 `InkReveal` 包裹(因为 CalligraphyTitle 自带动画),确保 h1 标签和 `id="hero-heading"` 保留。
|
||||
|
||||
- [ ] **步骤 3:验证 Hero 标题动画效果**
|
||||
|
||||
运行:`npm run dev`
|
||||
访问:`http://localhost:3000`
|
||||
预期:品牌标题"睿新致遠"以毛笔书写动画逐笔呈现
|
||||
|
||||
- [ ] **步骤 4:Commit**
|
||||
|
||||
```bash
|
||||
git add src/components/sections/hero-section-atoms.tsx src/components/sections/hero-section.tsx
|
||||
git commit -m "feat: replace HeroTitle with CalligraphyTitle for brush writing animation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 6:Container Queries 实现
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/components/ui/animated-card.tsx`
|
||||
- 修改:`src/components/sections/products-section.tsx`
|
||||
- 修改:`src/components/sections/services-section.tsx`
|
||||
- 修改:`src/app/globals.css`
|
||||
|
||||
- [ ] **步骤 1:在 globals.css 添加 Container Query 工具类**
|
||||
|
||||
在 `src/app/globals.css` 的 `@layer utilities` 块中添加:
|
||||
|
||||
```css
|
||||
/* Container Queries */
|
||||
@utility cq-container {
|
||||
container-type: inline-size;
|
||||
container-name: card;
|
||||
}
|
||||
|
||||
@utility cq-container-section {
|
||||
container-type: inline-size;
|
||||
container-name: section;
|
||||
}
|
||||
```
|
||||
|
||||
在 `@layer base` 块之后添加:
|
||||
|
||||
```css
|
||||
/* Container Query 响应式卡片布局 */
|
||||
@container card (min-width: 350px) {
|
||||
.cq-card-horizontal {
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@container card (min-width: 500px) {
|
||||
.cq-card-horizontal {
|
||||
grid-template-columns: 180px 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@container section (min-width: 768px) {
|
||||
.cq-section-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@container section (min-width: 1024px) {
|
||||
.cq-section-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:修改 AnimatedCard 添加 container-type**
|
||||
|
||||
在 `src/components/ui/animated-card.tsx` 中,找到 `motion.div` 的 `className`,添加 `cq-container`:
|
||||
|
||||
```tsx
|
||||
// 修改前
|
||||
className={cn('ink-card', className)}
|
||||
|
||||
// 修改后
|
||||
className={cn('ink-card cq-container', className)}
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:修改 ProductsSection 添加容器查询**
|
||||
|
||||
在 `src/components/sections/products-section.tsx` 中,找到产品卡片的 grid 容器 div,添加 `cq-container-section`:
|
||||
|
||||
```tsx
|
||||
// 修改前
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 items-stretch">
|
||||
|
||||
// 修改后
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 items-stretch cq-container-section">
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:修改 ServicesSection 添加容器查询**
|
||||
|
||||
在 `src/components/sections/services-section.tsx` 中做同样的修改。
|
||||
|
||||
- [ ] **步骤 5:验证 Container Queries 工作**
|
||||
|
||||
运行:`npm run dev`
|
||||
操作:调整浏览器窗口大小,观察卡片在不同容器宽度下的布局变化
|
||||
预期:卡片在窄容器中单列显示,宽容器中自动切换为多列
|
||||
|
||||
- [ ] **步骤 6:运行全量单元测试**
|
||||
|
||||
运行:`npx vitest run`
|
||||
预期:所有测试通过
|
||||
|
||||
- [ ] **步骤 7:Commit**
|
||||
|
||||
```bash
|
||||
git add src/app/globals.css src/components/ui/animated-card.tsx src/components/sections/products-section.tsx src/components/sections/services-section.tsx
|
||||
git commit -m "feat: add Container Queries for component-level responsive layouts"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 7:Phase 1 集成验证与收尾
|
||||
|
||||
**文件:**
|
||||
- 无新增/修改
|
||||
|
||||
- [ ] **步骤 1:运行完整构建**
|
||||
|
||||
运行:`npm run build`
|
||||
预期:构建成功,无错误
|
||||
|
||||
- [ ] **步骤 2:运行全量测试**
|
||||
|
||||
运行:`npx vitest run`
|
||||
预期:所有测试通过
|
||||
|
||||
- [ ] **步骤 3:运行类型检查**
|
||||
|
||||
运行:`npm run type-check`
|
||||
预期:无类型错误
|
||||
|
||||
- [ ] **步骤 4:运行 Lighthouse 审计**
|
||||
|
||||
运行:`npm run lighthouse:mobile`
|
||||
预期:Performance ≥ 90, Accessibility ≥ 95
|
||||
|
||||
- [ ] **步骤 5:验证渐进增强降级**
|
||||
|
||||
操作:
|
||||
1. 在不支持 View Transitions 的浏览器(如 Firefox < 126)中访问 → 页面正常显示,无过渡动画
|
||||
2. 在不支持 Container Queries 的浏览器中 → 卡片使用原有媒体查询布局
|
||||
3. 开启 `prefers-reduced-motion` → 品牌标题直接显示,无书写动画
|
||||
|
||||
预期:所有降级场景均正常工作
|
||||
|
||||
- [ ] **步骤 6:最终 Commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "chore: Phase 1 integration verification complete"
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,350 @@
|
||||
{
|
||||
"project": "novalon-website-atlassian-brand-fusion",
|
||||
"version": "1.0.0",
|
||||
"createdAt": "2026-04-30",
|
||||
"status": "approved",
|
||||
"spec": "docs/superpowers/specs/2026-04-30-atlassian-brand-fusion-redesign.md",
|
||||
"plan": "docs/superpowers/plans/2026-04-30-atlassian-brand-fusion-redesign.md",
|
||||
"objective": "借鉴 Atlassian 信息架构,重构 Novalon 首页为收敛但保留印记的品牌融合风格,同步沉淀 6 个核心组件",
|
||||
"architecture": "Next.js 16 App Router + 静态导出。首页从单文件长滚动重构为 6 个独立 Section 组件 + 新导航组件。动效从粒子/水墨收敛为微交互。导航从 8 项平铺改为 4 核心 + 2 下拉。",
|
||||
"techStack": ["Next.js 16", "React 19", "Tailwind CSS 4", "Framer Motion 12", "Lucide React"],
|
||||
"phases": [
|
||||
{
|
||||
"id": "phase-1",
|
||||
"name": "首页重构 + 设计系统基础",
|
||||
"status": "pending",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "task-1",
|
||||
"title": "Design Token 更新",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"modify": ["src/app/globals.css"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "1-1", "action": "在 :root 中新增场景色变量 (--color-challenge-isolation/growth/compliance 及 hover 变体)", "status": "pending" },
|
||||
{ "id": "1-2", "action": "验证 CSS 变量可用 (npx tsc --noEmit)", "status": "pending" },
|
||||
{ "id": "1-3", "action": "Commit: feat: add challenge scenario color tokens to design system", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-2",
|
||||
"title": "导航常量重构",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/lib/constants/navigation.test.ts"],
|
||||
"modify": ["src/lib/constants/navigation.ts", "src/lib/constants/index.ts"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "2-1", "action": "编写失败的测试 (NAVIGATION_V2 + MEGA_DROPDOWN_DATA)", "status": "pending" },
|
||||
{ "id": "2-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "2-3", "action": "实现 NavigationItemV2 + MegaDropdownItem + MegaDropdownData 类型及 NAVIGATION_V2 + MEGA_DROPDOWN_DATA 常量", "status": "pending" },
|
||||
{ "id": "2-4", "action": "更新 index.ts 导出", "status": "pending" },
|
||||
{ "id": "2-5", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "2-6", "action": "Commit: feat: add NAVIGATION_V2 and MEGA_DROPDOWN_DATA", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-3",
|
||||
"title": "MegaDropdown 组件",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/components/layout/mega-dropdown.tsx", "src/components/layout/mega-dropdown.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "3-1", "action": "编写失败的测试 (渲染触发按钮/显示下拉内容/隐藏下拉/点击触发/渲染条目)", "status": "pending" },
|
||||
{ "id": "3-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "3-3", "action": "实现 MegaDropdown 组件 (ChevronDown + AnimatePresence + 2列网格 + 朱砂红左边框)", "status": "pending" },
|
||||
{ "id": "3-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "3-5", "action": "Commit: feat: add MegaDropdown component", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-4",
|
||||
"title": "Header 重构",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"modify": ["src/components/layout/header.tsx", "src/components/layout/header.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "4-1", "action": "编写失败的测试 (NAVIGATION_V2 项/旧项不存在)", "status": "pending" },
|
||||
{ "id": "4-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "4-3", "action": "重构 Header: NAVIGATION → NAVIGATION_V2 + MegaDropdown + openDropdown state", "status": "pending" },
|
||||
{ "id": "4-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "4-5", "action": "Commit: feat: refactor Header with NAVIGATION_V2 and MegaDropdown", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-5",
|
||||
"title": "Hero Section 重构",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/components/sections/hero-section-v2.tsx", "src/components/sections/hero-section-v2.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "5-1", "action": "编写失败的测试 (品牌标签/书法标题/双CTA/副标题)", "status": "pending" },
|
||||
{ "id": "5-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "5-3", "action": "实现 HeroSectionV2 (暖白渐变+极简装饰圆圈+品牌标签+书法标题+双CTA+FadeUp动效)", "status": "pending" },
|
||||
{ "id": "5-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "5-5", "action": "Commit: feat: add HeroSectionV2 with brand fusion style", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-6",
|
||||
"title": "StatsBar 组件",
|
||||
"status": "pending",
|
||||
"priority": "medium",
|
||||
"files": {
|
||||
"create": ["src/components/ui/stats-bar.tsx", "src/components/ui/stats-bar.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "6-1", "action": "编写失败的测试 (渲染所有数值和标签)", "status": "pending" },
|
||||
{ "id": "6-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "6-3", "action": "实现 StatsBar (3列网格+朱砂红数值+灰色标签)", "status": "pending" },
|
||||
{ "id": "6-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "6-5", "action": "Commit: feat: add StatsBar component", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-7",
|
||||
"title": "社会证明 Section",
|
||||
"status": "pending",
|
||||
"priority": "medium",
|
||||
"files": {
|
||||
"create": ["src/components/sections/social-proof-section.tsx", "src/components/sections/social-proof-section.test.tsx"],
|
||||
"modify": ["src/lib/constants/stats.ts"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "7-1", "action": "在 stats.ts 新增 HOME_STATS 常量", "status": "pending" },
|
||||
{ "id": "7-2", "action": "编写测试 (渲染数据/浅灰背景)", "status": "pending" },
|
||||
{ "id": "7-3", "action": "实现 SocialProofSection (浅灰背景+StatsBar)", "status": "pending" },
|
||||
{ "id": "7-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "7-5", "action": "Commit: feat: add SocialProofSection with HOME_STATS", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-8",
|
||||
"title": "ProductCard 组件",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/components/ui/product-card.tsx", "src/components/ui/product-card.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "8-1", "action": "编写失败的测试 (标题/描述/链接/左边框)", "status": "pending" },
|
||||
{ "id": "8-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "8-3", "action": "实现 ProductCard (朱砂红3px左边框+hover提升+阴影)", "status": "pending" },
|
||||
{ "id": "8-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "8-5", "action": "Commit: feat: add ProductCard component", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-9",
|
||||
"title": "产品矩阵 Section",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/components/sections/product-matrix-section.tsx", "src/components/sections/product-matrix-section.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "9-1", "action": "编写测试 (标题/4个产品)", "status": "pending" },
|
||||
{ "id": "9-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "9-3", "action": "实现 ProductMatrixSection (白底+2x2网格+PRODUCTS数据)", "status": "pending" },
|
||||
{ "id": "9-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "9-5", "action": "Commit: feat: add ProductMatrixSection", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-10",
|
||||
"title": "ChallengeCard 组件",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/components/ui/challenge-card.tsx", "src/components/ui/challenge-card.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "10-1", "action": "编写失败的测试 (图标/标题/副标题/链接)", "status": "pending" },
|
||||
{ "id": "10-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "10-3", "action": "实现 ChallengeCard (场景色背景+hover色变+emoji图标+朱砂红副标题)", "status": "pending" },
|
||||
{ "id": "10-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "10-5", "action": "Commit: feat: add ChallengeCard component", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-11",
|
||||
"title": "挑战场景 Section",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"create": ["src/components/sections/challenge-section.tsx", "src/components/sections/challenge-section.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "11-1", "action": "编写测试 (标题/三个挑战卡片)", "status": "pending" },
|
||||
{ "id": "11-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "11-3", "action": "实现 ChallengeSection (暖白背景+三列网格+系统孤岛/增长瓶颈/合规风险)", "status": "pending" },
|
||||
{ "id": "11-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "11-5", "action": "Commit: feat: add ChallengeSection", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-12",
|
||||
"title": "TestimonialBlock 组件",
|
||||
"status": "pending",
|
||||
"priority": "medium",
|
||||
"files": {
|
||||
"create": ["src/components/ui/testimonial-block.tsx", "src/components/ui/testimonial-block.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "12-1", "action": "编写失败的测试 (引言/署名/量化指标)", "status": "pending" },
|
||||
{ "id": "12-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "12-3", "action": "实现 TestimonialBlock (深墨背景+引言+署名+朱砂红数值指标)", "status": "pending" },
|
||||
{ "id": "12-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "12-5", "action": "Commit: feat: add TestimonialBlock component", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-13",
|
||||
"title": "客户成果 Section",
|
||||
"status": "pending",
|
||||
"priority": "medium",
|
||||
"files": {
|
||||
"create": ["src/components/sections/testimonial-section.tsx", "src/components/sections/testimonial-section.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "13-1", "action": "编写测试 (客户成果标签)", "status": "pending" },
|
||||
{ "id": "13-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "13-3", "action": "实现 TestimonialSection (深墨背景+CASES数据+TestimonialBlock)", "status": "pending" },
|
||||
{ "id": "13-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "13-5", "action": "Commit: feat: add TestimonialSection", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-14",
|
||||
"title": "CTASection 组件",
|
||||
"status": "pending",
|
||||
"priority": "medium",
|
||||
"files": {
|
||||
"create": ["src/components/ui/cta-section.tsx", "src/components/ui/cta-section.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "14-1", "action": "编写失败的测试 (标题/副标题/按钮)", "status": "pending" },
|
||||
{ "id": "14-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "14-3", "action": "实现 CTASection (朱砂红渐变+白色描边按钮)", "status": "pending" },
|
||||
{ "id": "14-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "14-5", "action": "Commit: feat: add CTASection component", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-15",
|
||||
"title": "CTA Section 页面级",
|
||||
"status": "pending",
|
||||
"priority": "medium",
|
||||
"files": {
|
||||
"create": ["src/components/sections/cta-section-page.tsx", "src/components/sections/cta-section-page.test.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "15-1", "action": "编写测试 (标题/副标题内容)", "status": "pending" },
|
||||
{ "id": "15-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "15-3", "action": "实现 CTASectionPage (CTASection 包装+首页特定内容)", "status": "pending" },
|
||||
{ "id": "15-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "15-5", "action": "Commit: feat: add CTASectionPage", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-16",
|
||||
"title": "首页组装",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"files": {
|
||||
"modify": ["src/app/(marketing)/home-content.tsx"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "16-1", "action": "编写测试 (新Hero/产品矩阵/挑战/CTA)", "status": "pending" },
|
||||
{ "id": "16-2", "action": "运行测试验证失败", "status": "pending" },
|
||||
{ "id": "16-3", "action": "重构 home-content.tsx: 替换为 HeroSectionV2 + SocialProof + ProductMatrix + Challenge + Testimonial + CTA", "status": "pending" },
|
||||
{ "id": "16-4", "action": "运行测试验证通过", "status": "pending" },
|
||||
{ "id": "16-5", "action": "Commit: feat: assemble homepage with new brand-fusion sections", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-17",
|
||||
"title": "废弃动效清理",
|
||||
"status": "pending",
|
||||
"priority": "low",
|
||||
"files": {
|
||||
"modify": ["src/components/effects/index.ts"]
|
||||
},
|
||||
"steps": [
|
||||
{ "id": "17-1", "action": "从 effects/index.ts 移除废弃组件导出 (InkBackground/DataParticleFlow/ParticleGalaxy/MouseInteractiveParticles/FluidWaveBackground/GeometricAbstract/GridLines/AdvancedFloatingEffects)", "status": "pending" },
|
||||
{ "id": "17-2", "action": "验证构建无报错 (npx tsc --noEmit)", "status": "pending" },
|
||||
{ "id": "17-3", "action": "Commit: chore: remove deprecated particle/ink effect exports", "status": "pending" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task-18",
|
||||
"title": "集成测试与验证",
|
||||
"status": "pending",
|
||||
"priority": "high",
|
||||
"steps": [
|
||||
{ "id": "18-1", "action": "运行全量单元测试 (npx jest --no-coverage)", "status": "pending" },
|
||||
{ "id": "18-2", "action": "运行类型检查 (npx tsc --noEmit)", "status": "pending" },
|
||||
{ "id": "18-3", "action": "运行构建 (npm run build)", "status": "pending" },
|
||||
{ "id": "18-4", "action": "启动开发服务器手动验证 (导航/6个Section/无粒子动效)", "status": "pending" },
|
||||
{ "id": "18-5", "action": "运行 Lighthouse 审计 (Performance≥90, Accessibility≥95)", "status": "pending" },
|
||||
{ "id": "18-6", "action": "最终 Commit: feat: complete Phase 1 of Atlassian-style brand fusion homepage redesign", "status": "pending" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"components": {
|
||||
"new": [
|
||||
{ "name": "MegaDropdown", "path": "src/components/layout/mega-dropdown.tsx", "reuse": ["全站导航"] },
|
||||
{ "name": "ProductCard", "path": "src/components/ui/product-card.tsx", "reuse": ["首页", "产品列表页"] },
|
||||
{ "name": "ChallengeCard", "path": "src/components/ui/challenge-card.tsx", "reuse": ["首页", "解决方案页"] },
|
||||
{ "name": "StatsBar", "path": "src/components/ui/stats-bar.tsx", "reuse": ["首页", "产品页", "关于页"] },
|
||||
{ "name": "TestimonialBlock", "path": "src/components/ui/testimonial-block.tsx", "reuse": ["首页", "案例页", "产品页"] },
|
||||
{ "name": "CTASection", "path": "src/components/ui/cta-section.tsx", "reuse": ["全站通用"] },
|
||||
{ "name": "HeroSectionV2", "path": "src/components/sections/hero-section-v2.tsx", "reuse": ["首页"] },
|
||||
{ "name": "SocialProofSection", "path": "src/components/sections/social-proof-section.tsx", "reuse": ["首页"] },
|
||||
{ "name": "ProductMatrixSection", "path": "src/components/sections/product-matrix-section.tsx", "reuse": ["首页"] },
|
||||
{ "name": "ChallengeSection", "path": "src/components/sections/challenge-section.tsx", "reuse": ["首页"] },
|
||||
{ "name": "TestimonialSection", "path": "src/components/sections/testimonial-section.tsx", "reuse": ["首页"] },
|
||||
{ "name": "CTASectionPage", "path": "src/components/sections/cta-section-page.tsx", "reuse": ["首页"] }
|
||||
],
|
||||
"modify": [
|
||||
{ "name": "Header", "path": "src/components/layout/header.tsx", "change": "集成 MegaDropdown + NAVIGATION_V2" },
|
||||
{ "name": "home-content", "path": "src/app/(marketing)/home-content.tsx", "change": "替换为新 Section 组件" }
|
||||
],
|
||||
"deprecate": [
|
||||
"InkBackground",
|
||||
"DataParticleFlow",
|
||||
"ParticleGalaxy",
|
||||
"MouseInteractiveParticles",
|
||||
"FluidWaveBackground",
|
||||
"GeometricAbstract",
|
||||
"GridLines",
|
||||
"AdvancedFloatingEffects"
|
||||
]
|
||||
},
|
||||
"designDecisions": {
|
||||
"brandDirection": "B — 收敛但保留印记",
|
||||
"deliveryRhythm": "A+C 混合 — 首页驱动的设计系统",
|
||||
"homepageLayout": "方案二 — 品牌融合重构",
|
||||
"animationStrategy": "大幅收敛 — 移除粒子/水墨,保留微交互",
|
||||
"navigationStructure": "4核心+2下拉"
|
||||
},
|
||||
"visualRhythm": ["暖白(Hero)", "浅灰(社会证明)", "白(产品矩阵)", "暖白(挑战场景)", "深墨(客户成果)", "朱砂红(CTA)", "浅灰(Footer)"],
|
||||
"qualityGates": {
|
||||
"unitTests": "all pass",
|
||||
"typeCheck": "no errors",
|
||||
"build": "success",
|
||||
"lighthousePerformance": ">=90",
|
||||
"lighthouseAccessibility": ">=95"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user