69a22a750a
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2471 lines
81 KiB
Markdown
2471 lines
81 KiB
Markdown
# DAL Website Redesign Implementation Plan
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** Transform dalcode-website from a single-product Webflow-template site into a product-matrix platform site for DAL Code, DAL CLI, DAL Office, and DeepAILab API Platform.
|
||
|
||
**Architecture:** Replace webflow.css (11K lines) with Tailwind utility classes. Keep GSAP for scroll animations, remove Lottie. Remove next-themes (dark-only). Retain next-intl for zh-CN/en bilingual support. All new content goes through i18n message files.
|
||
|
||
**Tech Stack:** Next.js 16.2.4, React 19, Tailwind CSS 4, GSAP 3, next-intl 4, React Hook Form + Zod
|
||
|
||
**Key constraint:** All copy must be smart, polished, and sophisticated — not generic/cheap-sounding. The user explicitly said "文案一定要智能灵活,不要太 low".
|
||
|
||
**AGENTS.md warning:** Next.js 16 may have breaking API changes. Before writing any code, check `node_modules/next/dist/docs/` for current conventions. Key findings from review: `page.tsx`, `layout.tsx`, `not-found.tsx` conventions unchanged. `middleware` is deprecated in favor of `proxy`.
|
||
|
||
---
|
||
|
||
## File Structure
|
||
|
||
### New files
|
||
|
||
```
|
||
app/
|
||
├── globals.css (REWRITE — pure Tailwind, no webflow refs)
|
||
├── code/page.tsx (DAL Code product page)
|
||
├── cli/page.tsx (DAL CLI product page)
|
||
├── office/page.tsx (DAL Office page)
|
||
├── platform/page.tsx (API Platform page)
|
||
├── pricing/page.tsx (Unified pricing page)
|
||
|
||
components/
|
||
├── Header.tsx (REWRITE — new nav with Products dropdown)
|
||
├── Footer.tsx (REWRITE — 4-column layout)
|
||
├── GsapAnimations.tsx (MODIFY — update selectors for new sections)
|
||
├── ScrollReveal.tsx (NEW — reusable scroll-reveal wrapper)
|
||
├── home/
|
||
│ ├── HeroSection.tsx (REWRITE)
|
||
│ ├── ProductEcosystem.tsx (NEW — 2×2 product cards)
|
||
│ ├── WorkflowSteps.tsx (NEW — 3-step Intent/Build/Ship)
|
||
│ ├── FeatureGrid.tsx (NEW — 8-feature grid)
|
||
│ ├── EcosystemSection.tsx (NEW — DeepAILab platform)
|
||
│ ├── BottomCta.tsx (NEW — bottom CTA)
|
||
│ ├── FaqSection.tsx (NEW — accordion FAQ)
|
||
│ └── index.ts (REWRITE — export new components)
|
||
|
||
lib/
|
||
├── site-content.ts (REWRITE — new data structures)
|
||
```
|
||
|
||
### Files to delete
|
||
|
||
```
|
||
app/webflow.css (11K lines, replaced by Tailwind)
|
||
components/ThemeToggle.tsx (no more theme switching)
|
||
components/LottiePlayer.tsx (removing Lottie)
|
||
components/home/IntegrationsSection.tsx (replaced by ProductEcosystem)
|
||
components/home/PrinciplesSection.tsx (replaced by WorkflowSteps)
|
||
components/home/BlogPreviewSection.tsx (removed from homepage)
|
||
components/home/CtaSection.tsx (replaced by BottomCta)
|
||
```
|
||
|
||
### Message files to rewrite
|
||
|
||
```
|
||
messages/zh-CN.json (full rewrite with new content)
|
||
messages/en.json (full rewrite with new content)
|
||
```
|
||
|
||
---
|
||
|
||
## Task 1: Foundation — Remove webflow.css, set up dark Tailwind base
|
||
|
||
**Files:**
|
||
- Delete: `app/webflow.css`
|
||
- Rewrite: `app/globals.css`
|
||
- Modify: `app/layout.tsx`
|
||
- Delete: `components/ThemeToggle.tsx`
|
||
- Delete: `components/LottiePlayer.tsx`
|
||
|
||
- [ ] **Step 1: Create the new globals.css**
|
||
|
||
Replace the entire `app/globals.css` with a Tailwind-first dark theme foundation:
|
||
|
||
```css
|
||
@import "tailwindcss";
|
||
|
||
@theme {
|
||
--color-bg-primary: #0a0a0a;
|
||
--color-bg-secondary: #111111;
|
||
--color-bg-card: #161616;
|
||
--color-bg-card-hover: #1a1a1a;
|
||
--color-border: #222222;
|
||
--color-border-hover: #333333;
|
||
--color-text-primary: #f0f0f0;
|
||
--color-text-secondary: #a0a0a0;
|
||
--color-text-muted: #666666;
|
||
--color-accent: #6366f1;
|
||
--color-accent-hover: #818cf8;
|
||
--color-accent-glow: rgba(99, 102, 241, 0.15);
|
||
--font-sans: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
|
||
--font-display: var(--font-inter-tight), var(--font-sans);
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
@apply bg-bg-primary text-text-primary antialiased;
|
||
font-family: var(--font-sans);
|
||
}
|
||
|
||
::selection {
|
||
@apply bg-accent/30 text-text-primary;
|
||
}
|
||
|
||
/* Scrollbar */
|
||
::-webkit-scrollbar { width: 6px; }
|
||
::-webkit-scrollbar-track { background: transparent; }
|
||
::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }
|
||
::-webkit-scrollbar-thumb:hover { background: var(--color-border-hover); }
|
||
|
||
/* Shared animation classes used by GSAP */
|
||
.reveal-up {
|
||
opacity: 0;
|
||
transform: translateY(40px);
|
||
}
|
||
|
||
.reveal-visible {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
transition: opacity 0.6s ease, transform 0.6s ease;
|
||
}
|
||
|
||
/* Glow effect for cards */
|
||
.card-glow {
|
||
position: relative;
|
||
}
|
||
.card-glow::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
padding: 1px;
|
||
background: linear-gradient(135deg, transparent, var(--color-accent-glow), transparent);
|
||
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||
mask-composite: exclude;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
.card-glow:hover::before {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Stagger children animation delay */
|
||
.stagger-children > * {
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Update layout.tsx — remove webflow.css, ThemeProvider, Lottie**
|
||
|
||
Replace `app/layout.tsx`:
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { Inter, Inter_Tight } from "next/font/google"
|
||
import { NextIntlClientProvider } from "next-intl"
|
||
import { getLocale, getMessages } from "next-intl/server"
|
||
import Header from "@/components/Header"
|
||
import Footer from "@/components/Footer"
|
||
import GsapAnimations from "@/components/GsapAnimations"
|
||
import { SITE_BRAND, SITE_DESCRIPTION, SITE_NAME } from "@/lib/site-content"
|
||
import "./globals.css"
|
||
|
||
const inter = Inter({
|
||
subsets: ["latin"],
|
||
weight: ["400", "500", "600", "700"],
|
||
variable: "--font-inter",
|
||
display: "swap",
|
||
})
|
||
|
||
const interTight = Inter_Tight({
|
||
subsets: ["latin"],
|
||
weight: ["400", "500", "600", "700"],
|
||
variable: "--font-inter-tight",
|
||
display: "swap",
|
||
})
|
||
|
||
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000"
|
||
|
||
export const metadata: Metadata = {
|
||
metadataBase: new URL(SITE_URL),
|
||
title: {
|
||
default: SITE_BRAND,
|
||
template: `%s | ${SITE_NAME}`,
|
||
},
|
||
description: SITE_DESCRIPTION,
|
||
icons: {
|
||
icon: "/favicon.ico",
|
||
apple: "/assets/dalcode-app-icon-192.png",
|
||
},
|
||
openGraph: {
|
||
type: "website",
|
||
siteName: SITE_BRAND,
|
||
title: SITE_BRAND,
|
||
description: SITE_DESCRIPTION,
|
||
},
|
||
}
|
||
|
||
export default async function RootLayout({
|
||
children,
|
||
}: Readonly<{
|
||
children: React.ReactNode
|
||
}>) {
|
||
const locale = await getLocale()
|
||
const messages = await getMessages()
|
||
|
||
return (
|
||
<NextIntlClientProvider locale={locale} messages={messages}>
|
||
<html
|
||
lang={locale}
|
||
className={`${inter.variable} ${interTight.variable}`}
|
||
>
|
||
<body className={inter.className}>
|
||
<Header />
|
||
<main>{children}</main>
|
||
<Footer />
|
||
<GsapAnimations />
|
||
</body>
|
||
</html>
|
||
</NextIntlClientProvider>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Delete obsolete files**
|
||
|
||
```bash
|
||
rm app/webflow.css
|
||
rm components/ThemeToggle.tsx
|
||
rm components/LottiePlayer.tsx
|
||
rm components/RevealObserver.tsx
|
||
rm components/PageTransition.tsx
|
||
```
|
||
|
||
- [ ] **Step 4: Verify build compiles**
|
||
|
||
```bash
|
||
cd /Users/leon/本地开发项目/claude-code/dalcode-website && npx next build 2>&1 | tail -20
|
||
```
|
||
|
||
Expected: Build may fail due to import references in other files. That's OK — we'll fix them in subsequent tasks. The goal here is that `globals.css` and `layout.tsx` are correct.
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "chore: remove webflow.css and theme toggle, set up dark Tailwind foundation"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 2: i18n Content — Rewrite all message files
|
||
|
||
**Files:**
|
||
- Rewrite: `messages/zh-CN.json`
|
||
- Rewrite: `messages/en.json`
|
||
|
||
The copy below is the heart of the redesign. Every string must be polished — no filler, no "lorem ipsum energy".
|
||
|
||
- [ ] **Step 1: Write zh-CN.json**
|
||
|
||
```json
|
||
{
|
||
"site": {
|
||
"name": "DAL",
|
||
"brand": "DAL by DeepAILab",
|
||
"tagline": "The Open AI Development Platform",
|
||
"description": "从想法到产品的完整 AI 开发平台。自由选模型,全链路覆盖,一个账号搞定一切。"
|
||
},
|
||
"nav": {
|
||
"products": "产品",
|
||
"docs": "文档",
|
||
"pricing": "定价",
|
||
"blog": "博客",
|
||
"community": "社区",
|
||
"downloads": "下载",
|
||
"signIn": "登录",
|
||
"toggleMenu": "切换菜单",
|
||
"productItems": {
|
||
"code": { "name": "DAL Code", "tagline": "AI 原生开发环境" },
|
||
"cli": { "name": "DAL CLI", "tagline": "终端里的 AI 搭档" },
|
||
"office": { "name": "DAL Office", "tagline": "AI 文档工作台" },
|
||
"platform": { "name": "API Platform", "tagline": "统一 AI 开发者平台" }
|
||
}
|
||
},
|
||
"hero": {
|
||
"badge": "by DeepAILab",
|
||
"headline": "开放的 AI 开发平台",
|
||
"subheadline": "从想法到产品,自由选模型,从代码到文档全覆盖。一个账号,完整生态。",
|
||
"ctaPrimary": "下载 DAL Code",
|
||
"ctaSecondary": "安装 CLI",
|
||
"cliCommand": "curl -fsSL https://cli.deepailab.ai/install | bash"
|
||
},
|
||
"ecosystem": {
|
||
"label": "PRODUCT ECOSYSTEM",
|
||
"title": "一个平台,覆盖 AI 开发全场景",
|
||
"products": {
|
||
"code": {
|
||
"name": "DAL Code",
|
||
"tagline": "AI 原生开发环境",
|
||
"description": "不只是写代码的编辑器,而是从需求澄清到工程交付的完整工作台。",
|
||
"features": ["Intent Capture", "Mission Mode", "多模型路由"],
|
||
"cta": "了解 DAL Code"
|
||
},
|
||
"cli": {
|
||
"name": "DAL CLI",
|
||
"tagline": "终端里的 AI 开发搭档",
|
||
"description": "轻量、快速、管道友好。在终端里完成从 Agent 任务到代码交付的全流程。",
|
||
"features": ["Agent 执行", "管道集成", "轻量高速"],
|
||
"cta": "了解 DAL CLI"
|
||
},
|
||
"office": {
|
||
"name": "DAL Office",
|
||
"tagline": "AI 驱动的文档工作台",
|
||
"description": "用 AI 生成和编辑文档、表格、演示文稿——开发者的工作不只有代码。",
|
||
"features": ["Word", "Excel", "PPT"],
|
||
"cta": "了解 DAL Office"
|
||
},
|
||
"platform": {
|
||
"name": "API Platform",
|
||
"tagline": "统一 AI 开发者平台",
|
||
"description": "模型聚合、智能路由、成本优化——所有 DAL 产品背后的基础设施。",
|
||
"features": ["模型聚合", "智能路由", "API 折扣"],
|
||
"cta": "探索平台"
|
||
}
|
||
}
|
||
},
|
||
"workflow": {
|
||
"label": "HOW IT WORKS",
|
||
"title": "不是更好的 prompt,是更好的工作方式",
|
||
"steps": {
|
||
"intent": {
|
||
"number": "01",
|
||
"name": "INTENT",
|
||
"title": "先把需求想清楚",
|
||
"description": "AI 主动采访你,用结构化问题把模糊想法变成可执行的工程需求——不是等你写出完美的 prompt。"
|
||
},
|
||
"build": {
|
||
"number": "02",
|
||
"name": "BUILD",
|
||
"title": "智能拆解,并行执行",
|
||
"description": "Agent 自动分解任务,为每个子任务选择最优模型,多线并行推进——你监督方向,它负责落地。"
|
||
},
|
||
"ship": {
|
||
"number": "03",
|
||
"name": "SHIP",
|
||
"title": "代码、测试、文档一起交付",
|
||
"description": "不只是输出代码片段。测试、文档同步生成,关键操作需要你的审批,结果全程可追溯。"
|
||
}
|
||
}
|
||
},
|
||
"features": {
|
||
"label": "EVERYTHING YOU NEED",
|
||
"title": "为认真做产品的开发者而建",
|
||
"items": {
|
||
"routing": {
|
||
"title": "多模型智能路由",
|
||
"description": "同一工作流里,不同子任务自动匹配最优模型。质量、速度、成本不再是单选题。"
|
||
},
|
||
"skills": {
|
||
"title": "Skills 引擎",
|
||
"description": "把工程经验封装成可复用的引导式工作流。不是 prompt 模板,是方法论的产品化。"
|
||
},
|
||
"mission": {
|
||
"title": "Mission Mode",
|
||
"description": "复杂任务自动拆解,进度实时可见,断点可续跑。长任务终于不再是黑盒。"
|
||
},
|
||
"byok": {
|
||
"title": "自带 API Key",
|
||
"description": "用你自己的 API Key 接入任何模型。不被平台绑定,完全掌控成本和数据流向。"
|
||
},
|
||
"context": {
|
||
"title": "上下文引擎",
|
||
"description": "五层智能压缩,让百万行项目也能保持上下文连贯。大项目不再是 AI 的盲区。"
|
||
},
|
||
"audit": {
|
||
"title": "审批与审计",
|
||
"description": "危险操作需人工确认,每一步操作可追溯可审计。给个人效率,给团队安全感。"
|
||
},
|
||
"rag": {
|
||
"title": "知识库接入",
|
||
"description": "连接你的私有文档和知识库,AI 的回答基于你的真实上下文,而不是通用训练数据。"
|
||
},
|
||
"cost": {
|
||
"title": "成本透明化",
|
||
"description": "每次 AI 交互的成本实时可见。花了多少、省了多少,用数据说话。"
|
||
}
|
||
}
|
||
},
|
||
"platform": {
|
||
"label": "ONE PLATFORM, ONE ACCOUNT",
|
||
"title": "DeepAILab — 连接一切的 AI 开发者平台",
|
||
"advantages": {
|
||
"account": {
|
||
"title": "一个账号",
|
||
"description": "登录一次,Code、CLI、Office、API Platform 全部打通。无缝切换,统一管理。"
|
||
},
|
||
"discount": {
|
||
"title": "API 折扣",
|
||
"description": "通过平台调用主流模型,费率优于直连。用得越多,省得越多。"
|
||
},
|
||
"dashboard": {
|
||
"title": "成本仪表盘",
|
||
"description": "跨产品的用量统计和成本拆解,一目了然。告别月底账单惊喜。"
|
||
}
|
||
},
|
||
"cta": "探索 DeepAILab 平台"
|
||
},
|
||
"bottomCta": {
|
||
"headline": "准备好用新方式开发了吗?",
|
||
"subheadline": "从一次 Intent 采访开始,让 AI 先帮你想清楚要做什么。",
|
||
"ctaPrimary": "下载 DAL Code",
|
||
"ctaSecondary": "安装 CLI"
|
||
},
|
||
"faq": {
|
||
"label": "FAQ",
|
||
"title": "常见问题",
|
||
"items": {
|
||
"vsCursor": {
|
||
"q": "DAL Code 和 Cursor / Windsurf 有什么不同?",
|
||
"a": "Cursor 和 Windsurf 的核心是让你写更好的代码。DAL Code 的起点更早——它先帮你把需求想清楚,再把任务拆解、执行和交付。同时,DAL 不绑定单一模型,支持多模型智能路由和自带 API Key。"
|
||
},
|
||
"vsClaude": {
|
||
"q": "DAL CLI 和 Claude Code CLI 有什么不同?",
|
||
"a": "Claude Code 绑定 Anthropic 模型生态。DAL CLI 支持多模型路由,可以用你自己的 API Key,并且和 DAL Code、DAL Office 共享同一个账号和工作流体系。"
|
||
},
|
||
"byok": {
|
||
"q": "我可以用自己的 API Key 吗?",
|
||
"a": "可以。DAL 支持接入你自己的 API Key,包括 OpenAI、Anthropic、Google 等主流提供商。你也可以使用 DeepAILab 平台提供的 API 折扣。"
|
||
},
|
||
"apiDiscount": {
|
||
"q": "DeepAILab API 折扣怎么计算?",
|
||
"a": "通过 DeepAILab 平台统一调用模型 API,费率低于各厂商直连价格。具体折扣取决于用量层级,详见定价页面。"
|
||
},
|
||
"models": {
|
||
"q": "支持哪些 AI 模型?",
|
||
"a": "支持 Claude (Opus/Sonnet/Haiku)、GPT 系列、Gemini 系列等 20+ 主流模型,并持续接入新模型。Smart Routing 会根据任务类型自动选择最合适的模型。"
|
||
},
|
||
"enterprise": {
|
||
"q": "支持企业私有化部署吗?",
|
||
"a": "私有化部署、SSO、审计日志和自定义安全策略是产品路线的重点方向。如果你的团队有明确需求,欢迎联系我们从一个具体场景开始落地。"
|
||
}
|
||
}
|
||
},
|
||
"footer": {
|
||
"newsletter": {
|
||
"placeholder": "输入邮箱,订阅产品动态",
|
||
"submit": "订阅",
|
||
"success": "已订阅。",
|
||
"error": "订阅失败,请重试。"
|
||
},
|
||
"groups": {
|
||
"products": "产品",
|
||
"resources": "资源",
|
||
"community": "社区",
|
||
"company": "公司"
|
||
},
|
||
"links": {
|
||
"code": "DAL Code",
|
||
"cli": "DAL CLI",
|
||
"office": "DAL Office",
|
||
"apiPlatform": "API Platform",
|
||
"pricing": "定价",
|
||
"docs": "文档",
|
||
"blog": "博客",
|
||
"changelog": "更新日志",
|
||
"faq": "FAQ",
|
||
"discord": "Discord",
|
||
"github": "GitHub",
|
||
"twitter": "X / Twitter",
|
||
"about": "关于",
|
||
"careers": "加入我们",
|
||
"contact": "联系"
|
||
},
|
||
"copyright": "© 2026 DeepAILab. All rights reserved.",
|
||
"privacy": "隐私政策",
|
||
"terms": "服务条款"
|
||
},
|
||
"codePage": {
|
||
"hero": {
|
||
"label": "DAL CODE",
|
||
"headline": "不只是编辑器,是 AI 工程工作台",
|
||
"subheadline": "从需求采访到代码交付,一个工作台覆盖完整开发流程。Intent Capture 让 AI 先帮你想清楚要做什么,Mission Mode 让复杂任务自动拆解执行。",
|
||
"cta": "下载 DAL Code"
|
||
}
|
||
},
|
||
"cliPage": {
|
||
"hero": {
|
||
"label": "DAL CLI",
|
||
"headline": "终端里的 AI 开发搭档",
|
||
"subheadline": "轻量、快速、管道友好。在你熟悉的终端环境里,用 Agent 完成从需求到代码的全流程。",
|
||
"cta": "安装 DAL CLI",
|
||
"cliCommand": "curl -fsSL https://cli.deepailab.ai/install | bash"
|
||
}
|
||
},
|
||
"officePage": {
|
||
"hero": {
|
||
"label": "DAL OFFICE",
|
||
"headline": "AI 驱动的文档工作台",
|
||
"subheadline": "开发者的工作不只有代码。用 AI 生成和编辑 Word 文档、Excel 表格、PPT 演示文稿——和 DAL Code 无缝协作。",
|
||
"cta": "了解 DAL Office"
|
||
}
|
||
},
|
||
"platformPage": {
|
||
"hero": {
|
||
"label": "API PLATFORM",
|
||
"headline": "所有 DAL 产品背后的 AI 基础设施",
|
||
"subheadline": "模型聚合、智能路由、成本优化、用量分析——一个平台,为所有 AI 开发场景提供统一的基础能力。",
|
||
"cta": "探索 API Platform"
|
||
}
|
||
},
|
||
"pricingPage": {
|
||
"hero": {
|
||
"label": "PRICING",
|
||
"headline": "简单透明的定价",
|
||
"subheadline": "从个人开发者到企业团队,选择适合你的方案。"
|
||
}
|
||
},
|
||
"about": {
|
||
"hero": {
|
||
"label": "ABOUT",
|
||
"headline": "我们在构建下一代 AI 开发基础设施",
|
||
"subheadline": "DeepAILab 相信 AI 开发工具应该是开放的、可组合的、为开发者真正服务的。"
|
||
}
|
||
},
|
||
"contact": {
|
||
"hero": {
|
||
"label": "CONTACT",
|
||
"headline": "和我们聊聊你的真实场景",
|
||
"subheadline": "无论是产品试用、企业方案还是生态合作,从一个具体场景开始。"
|
||
}
|
||
},
|
||
"blog": {
|
||
"hero": {
|
||
"label": "BLOG",
|
||
"headline": "产品思考与工程实践",
|
||
"subheadline": "关于 AI 开发工具、多模型路由、工程工作流的深度内容。"
|
||
}
|
||
},
|
||
"common": {
|
||
"learnMore": "了解更多",
|
||
"getStarted": "开始使用",
|
||
"comingSoon": "即将推出",
|
||
"backToHome": "返回首页"
|
||
}
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Write en.json**
|
||
|
||
```json
|
||
{
|
||
"site": {
|
||
"name": "DAL",
|
||
"brand": "DAL by DeepAILab",
|
||
"tagline": "The Open AI Development Platform",
|
||
"description": "The complete AI development platform. Choose your models, cover the full workflow, one account for everything."
|
||
},
|
||
"nav": {
|
||
"products": "Products",
|
||
"docs": "Docs",
|
||
"pricing": "Pricing",
|
||
"blog": "Blog",
|
||
"community": "Community",
|
||
"downloads": "Downloads",
|
||
"signIn": "Sign In",
|
||
"toggleMenu": "Toggle menu",
|
||
"productItems": {
|
||
"code": { "name": "DAL Code", "tagline": "AI-native development environment" },
|
||
"cli": { "name": "DAL CLI", "tagline": "Your AI partner in the terminal" },
|
||
"office": { "name": "DAL Office", "tagline": "AI-powered document workspace" },
|
||
"platform": { "name": "API Platform", "tagline": "Unified AI developer platform" }
|
||
}
|
||
},
|
||
"hero": {
|
||
"badge": "by DeepAILab",
|
||
"headline": "The Open AI Development Platform",
|
||
"subheadline": "From idea to production. Choose your models, cover the full workflow from code to docs. One account, complete ecosystem.",
|
||
"ctaPrimary": "Download DAL Code",
|
||
"ctaSecondary": "Install CLI",
|
||
"cliCommand": "curl -fsSL https://cli.deepailab.ai/install | bash"
|
||
},
|
||
"ecosystem": {
|
||
"label": "PRODUCT ECOSYSTEM",
|
||
"title": "One platform, every AI development scenario",
|
||
"products": {
|
||
"code": {
|
||
"name": "DAL Code",
|
||
"tagline": "AI-native development environment",
|
||
"description": "More than a code editor — a complete workspace from requirements clarification to engineering delivery.",
|
||
"features": ["Intent Capture", "Mission Mode", "Multi-model Routing"],
|
||
"cta": "Explore DAL Code"
|
||
},
|
||
"cli": {
|
||
"name": "DAL CLI",
|
||
"tagline": "Your AI development partner in the terminal",
|
||
"description": "Lightweight, fast, pipeline-friendly. Run agent tasks and ship code from your terminal.",
|
||
"features": ["Agent Execution", "Pipeline Integration", "Lightweight"],
|
||
"cta": "Explore DAL CLI"
|
||
},
|
||
"office": {
|
||
"name": "DAL Office",
|
||
"tagline": "AI-powered document workspace",
|
||
"description": "Generate and edit documents, spreadsheets, and presentations with AI — because developers do more than write code.",
|
||
"features": ["Word", "Excel", "PPT"],
|
||
"cta": "Explore DAL Office"
|
||
},
|
||
"platform": {
|
||
"name": "API Platform",
|
||
"tagline": "Unified AI developer platform",
|
||
"description": "Model aggregation, smart routing, cost optimization — the infrastructure behind every DAL product.",
|
||
"features": ["Model Aggregation", "Smart Routing", "API Discounts"],
|
||
"cta": "Explore Platform"
|
||
}
|
||
}
|
||
},
|
||
"workflow": {
|
||
"label": "HOW IT WORKS",
|
||
"title": "Not a better prompt. A better workflow.",
|
||
"steps": {
|
||
"intent": {
|
||
"number": "01",
|
||
"name": "INTENT",
|
||
"title": "Clarify what you're building",
|
||
"description": "AI interviews you with structured questions, turning vague ideas into actionable engineering requirements — no perfect prompt needed."
|
||
},
|
||
"build": {
|
||
"number": "02",
|
||
"name": "BUILD",
|
||
"title": "Decompose and execute in parallel",
|
||
"description": "Agents break down tasks, select the optimal model for each subtask, and execute in parallel — you steer, they build."
|
||
},
|
||
"ship": {
|
||
"number": "03",
|
||
"name": "SHIP",
|
||
"title": "Code, tests, and docs — delivered together",
|
||
"description": "Not just code snippets. Tests and documentation generated in sync, critical actions require your approval, full audit trail."
|
||
}
|
||
}
|
||
},
|
||
"features": {
|
||
"label": "EVERYTHING YOU NEED",
|
||
"title": "Built for developers who ship",
|
||
"items": {
|
||
"routing": {
|
||
"title": "Multi-model Smart Routing",
|
||
"description": "Each subtask automatically matched to the optimal model. Quality, speed, and cost are no longer trade-offs."
|
||
},
|
||
"skills": {
|
||
"title": "Skills Engine",
|
||
"description": "Engineering experience packaged as reusable guided workflows. Not prompt templates — methodology as a product."
|
||
},
|
||
"mission": {
|
||
"title": "Mission Mode",
|
||
"description": "Complex tasks decomposed automatically, progress visible in real time, resume from any breakpoint."
|
||
},
|
||
"byok": {
|
||
"title": "Bring Your Own Key",
|
||
"description": "Connect your own API keys from any provider. No vendor lock-in, full control over cost and data flow."
|
||
},
|
||
"context": {
|
||
"title": "Context Engine",
|
||
"description": "Five-layer intelligent compression keeps context coherent across million-line projects."
|
||
},
|
||
"audit": {
|
||
"title": "Approval & Audit",
|
||
"description": "Critical actions require human confirmation. Every step traceable, every decision auditable."
|
||
},
|
||
"rag": {
|
||
"title": "Knowledge Integration",
|
||
"description": "Connect your private docs and knowledge bases. AI answers grounded in your real context, not generic training data."
|
||
},
|
||
"cost": {
|
||
"title": "Cost Transparency",
|
||
"description": "Real-time cost visibility for every AI interaction. See what you spend and what you save."
|
||
}
|
||
}
|
||
},
|
||
"platform": {
|
||
"label": "ONE PLATFORM, ONE ACCOUNT",
|
||
"title": "DeepAILab — The AI developer platform that connects everything",
|
||
"advantages": {
|
||
"account": {
|
||
"title": "One Account",
|
||
"description": "Sign in once. Code, CLI, Office, and API Platform — all connected, all managed from one place."
|
||
},
|
||
"discount": {
|
||
"title": "API Discounts",
|
||
"description": "Access leading models through the platform at better rates than direct connections."
|
||
},
|
||
"dashboard": {
|
||
"title": "Cost Dashboard",
|
||
"description": "Cross-product usage analytics and cost breakdown at a glance. No more billing surprises."
|
||
}
|
||
},
|
||
"cta": "Explore DeepAILab Platform"
|
||
},
|
||
"bottomCta": {
|
||
"headline": "Ready to build the new way?",
|
||
"subheadline": "Start with an Intent interview. Let AI help you figure out what to build.",
|
||
"ctaPrimary": "Download DAL Code",
|
||
"ctaSecondary": "Install CLI"
|
||
},
|
||
"faq": {
|
||
"label": "FAQ",
|
||
"title": "Frequently Asked Questions",
|
||
"items": {
|
||
"vsCursor": {
|
||
"q": "How is DAL Code different from Cursor or Windsurf?",
|
||
"a": "Cursor and Windsurf focus on helping you write better code. DAL Code starts earlier — it helps you clarify what to build before decomposing, executing, and delivering the work. It also supports multi-model routing and bring-your-own API keys."
|
||
},
|
||
"vsClaude": {
|
||
"q": "How is DAL CLI different from Claude Code?",
|
||
"a": "Claude Code is tied to the Anthropic model ecosystem. DAL CLI supports multi-model routing, your own API keys, and shares the same account and workflow system with DAL Code and DAL Office."
|
||
},
|
||
"byok": {
|
||
"q": "Can I use my own API keys?",
|
||
"a": "Yes. DAL supports connecting your own API keys from OpenAI, Anthropic, Google, and other major providers. You can also take advantage of DeepAILab platform API discounts."
|
||
},
|
||
"apiDiscount": {
|
||
"q": "How do DeepAILab API discounts work?",
|
||
"a": "Calling model APIs through the DeepAILab platform costs less than connecting to providers directly. Exact discounts depend on your usage tier — see the pricing page for details."
|
||
},
|
||
"models": {
|
||
"q": "Which AI models are supported?",
|
||
"a": "We support Claude (Opus/Sonnet/Haiku), GPT series, Gemini series, and 20+ other leading models, with new models added continuously. Smart Routing automatically selects the best model for each task."
|
||
},
|
||
"enterprise": {
|
||
"q": "Do you support enterprise private deployment?",
|
||
"a": "Private deployment, SSO, audit logs, and custom security policies are priority items on our roadmap. If your team has specific requirements, contact us to start with a concrete use case."
|
||
}
|
||
}
|
||
},
|
||
"footer": {
|
||
"newsletter": {
|
||
"placeholder": "Your email for product updates",
|
||
"submit": "Subscribe",
|
||
"success": "Subscribed.",
|
||
"error": "Failed to subscribe. Please try again."
|
||
},
|
||
"groups": {
|
||
"products": "Products",
|
||
"resources": "Resources",
|
||
"community": "Community",
|
||
"company": "Company"
|
||
},
|
||
"links": {
|
||
"code": "DAL Code",
|
||
"cli": "DAL CLI",
|
||
"office": "DAL Office",
|
||
"apiPlatform": "API Platform",
|
||
"pricing": "Pricing",
|
||
"docs": "Docs",
|
||
"blog": "Blog",
|
||
"changelog": "Changelog",
|
||
"faq": "FAQ",
|
||
"discord": "Discord",
|
||
"github": "GitHub",
|
||
"twitter": "X / Twitter",
|
||
"about": "About",
|
||
"careers": "Careers",
|
||
"contact": "Contact"
|
||
},
|
||
"copyright": "© 2026 DeepAILab. All rights reserved.",
|
||
"privacy": "Privacy",
|
||
"terms": "Terms"
|
||
},
|
||
"codePage": {
|
||
"hero": {
|
||
"label": "DAL CODE",
|
||
"headline": "Not just an editor. An AI engineering workspace.",
|
||
"subheadline": "From requirements interview to code delivery, one workspace covering the complete development workflow. Intent Capture helps you think clearly, Mission Mode handles the heavy lifting.",
|
||
"cta": "Download DAL Code"
|
||
}
|
||
},
|
||
"cliPage": {
|
||
"hero": {
|
||
"label": "DAL CLI",
|
||
"headline": "Your AI development partner in the terminal",
|
||
"subheadline": "Lightweight, fast, pipeline-friendly. Use agents to go from requirements to shipped code, right in your terminal.",
|
||
"cta": "Install DAL CLI",
|
||
"cliCommand": "curl -fsSL https://cli.deepailab.ai/install | bash"
|
||
}
|
||
},
|
||
"officePage": {
|
||
"hero": {
|
||
"label": "DAL OFFICE",
|
||
"headline": "AI-powered document workspace",
|
||
"subheadline": "Developers do more than write code. Generate and edit Word documents, Excel spreadsheets, and PowerPoint presentations with AI — seamlessly connected to DAL Code.",
|
||
"cta": "Explore DAL Office"
|
||
}
|
||
},
|
||
"platformPage": {
|
||
"hero": {
|
||
"label": "API PLATFORM",
|
||
"headline": "The AI infrastructure behind every DAL product",
|
||
"subheadline": "Model aggregation, smart routing, cost optimization, usage analytics — one platform providing unified capabilities for every AI development scenario.",
|
||
"cta": "Explore API Platform"
|
||
}
|
||
},
|
||
"pricingPage": {
|
||
"hero": {
|
||
"label": "PRICING",
|
||
"headline": "Simple, transparent pricing",
|
||
"subheadline": "From individual developers to enterprise teams, choose the plan that fits."
|
||
}
|
||
},
|
||
"about": {
|
||
"hero": {
|
||
"label": "ABOUT",
|
||
"headline": "Building next-generation AI development infrastructure",
|
||
"subheadline": "DeepAILab believes AI development tools should be open, composable, and built to genuinely serve developers."
|
||
}
|
||
},
|
||
"contact": {
|
||
"hero": {
|
||
"label": "CONTACT",
|
||
"headline": "Tell us about your real-world scenario",
|
||
"subheadline": "Whether it's a product trial, enterprise deployment, or ecosystem partnership — start with a concrete use case."
|
||
}
|
||
},
|
||
"blog": {
|
||
"hero": {
|
||
"label": "BLOG",
|
||
"headline": "Product thinking and engineering practice",
|
||
"subheadline": "Deep dives on AI development tools, multi-model routing, and engineering workflows."
|
||
}
|
||
},
|
||
"common": {
|
||
"learnMore": "Learn more",
|
||
"getStarted": "Get started",
|
||
"comingSoon": "Coming soon",
|
||
"backToHome": "Back to home"
|
||
}
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add messages/
|
||
git commit -m "feat: rewrite i18n content for platform redesign"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 3: Site content data + ScrollReveal component
|
||
|
||
**Files:**
|
||
- Rewrite: `lib/site-content.ts`
|
||
- Create: `components/ScrollReveal.tsx`
|
||
|
||
- [ ] **Step 1: Rewrite lib/site-content.ts**
|
||
|
||
```typescript
|
||
export const SITE_NAME = "DAL"
|
||
export const SITE_BRAND = "DAL by DeepAILab"
|
||
export const SITE_TAGLINE = "The Open AI Development Platform"
|
||
export const SITE_DESCRIPTION =
|
||
"从想法到产品的完整 AI 开发平台。自由选模型,全链路覆盖,一个账号搞定一切。"
|
||
|
||
export interface NavProductItem {
|
||
key: string
|
||
href: string
|
||
}
|
||
|
||
export const NAV_PRODUCT_ITEMS: NavProductItem[] = [
|
||
{ key: "code", href: "/code" },
|
||
{ key: "cli", href: "/cli" },
|
||
{ key: "office", href: "/office" },
|
||
{ key: "platform", href: "/platform" },
|
||
]
|
||
|
||
export interface FooterGroup {
|
||
key: string
|
||
links: { key: string; href: string; external?: boolean }[]
|
||
}
|
||
|
||
export const FOOTER_GROUPS: FooterGroup[] = [
|
||
{
|
||
key: "products",
|
||
links: [
|
||
{ key: "code", href: "/code" },
|
||
{ key: "cli", href: "/cli" },
|
||
{ key: "office", href: "/office" },
|
||
{ key: "apiPlatform", href: "/platform" },
|
||
{ key: "pricing", href: "/pricing" },
|
||
],
|
||
},
|
||
{
|
||
key: "resources",
|
||
links: [
|
||
{ key: "docs", href: "/docs" },
|
||
{ key: "blog", href: "/blog" },
|
||
{ key: "changelog", href: "/coming-soon" },
|
||
{ key: "faq", href: "/#faq" },
|
||
],
|
||
},
|
||
{
|
||
key: "community",
|
||
links: [
|
||
{ key: "discord", href: "https://discord.gg/deepailab", external: true },
|
||
{ key: "github", href: "https://github.com/deepailab", external: true },
|
||
{ key: "twitter", href: "https://x.com/deepailab", external: true },
|
||
],
|
||
},
|
||
{
|
||
key: "company",
|
||
links: [
|
||
{ key: "about", href: "/about" },
|
||
{ key: "careers", href: "/careers" },
|
||
{ key: "contact", href: "/contact" },
|
||
],
|
||
},
|
||
]
|
||
|
||
export const PRODUCT_KEYS = ["code", "cli", "office", "platform"] as const
|
||
export type ProductKey = (typeof PRODUCT_KEYS)[number]
|
||
|
||
export const PRODUCT_ICONS: Record<ProductKey, string> = {
|
||
code: "/assets/icons/product-code.svg",
|
||
cli: "/assets/icons/product-cli.svg",
|
||
office: "/assets/icons/product-office.svg",
|
||
platform: "/assets/icons/product-platform.svg",
|
||
}
|
||
|
||
export const PRODUCT_HREFS: Record<ProductKey, string> = {
|
||
code: "/code",
|
||
cli: "/cli",
|
||
office: "/office",
|
||
platform: "/platform",
|
||
}
|
||
|
||
export const WORKFLOW_STEPS = ["intent", "build", "ship"] as const
|
||
export type WorkflowStep = (typeof WORKFLOW_STEPS)[number]
|
||
|
||
export const FEATURE_KEYS = [
|
||
"routing", "skills", "mission", "byok",
|
||
"context", "audit", "rag", "cost",
|
||
] as const
|
||
export type FeatureKey = (typeof FEATURE_KEYS)[number]
|
||
|
||
export const FEATURE_ICONS: Record<FeatureKey, string> = {
|
||
routing: "⚡",
|
||
skills: "🧩",
|
||
mission: "🎯",
|
||
byok: "🔑",
|
||
context: "🧠",
|
||
audit: "🛡️",
|
||
rag: "📚",
|
||
cost: "📊",
|
||
}
|
||
|
||
export const PLATFORM_ADVANTAGE_KEYS = ["account", "discount", "dashboard"] as const
|
||
|
||
export const FAQ_KEYS = [
|
||
"vsCursor", "vsClaude", "byok", "apiDiscount", "models", "enterprise",
|
||
] as const
|
||
```
|
||
|
||
- [ ] **Step 2: Create ScrollReveal component**
|
||
|
||
Create `components/ScrollReveal.tsx`:
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import { useEffect, useRef } from "react"
|
||
|
||
interface ScrollRevealProps {
|
||
children: React.ReactNode
|
||
className?: string
|
||
delay?: number
|
||
as?: keyof HTMLElementTagNameMap
|
||
}
|
||
|
||
export default function ScrollReveal({
|
||
children,
|
||
className = "",
|
||
delay = 0,
|
||
as: Tag = "div" as any,
|
||
}: ScrollRevealProps) {
|
||
const ref = useRef<HTMLElement>(null)
|
||
|
||
useEffect(() => {
|
||
const el = ref.current
|
||
if (!el) return
|
||
|
||
const observer = new IntersectionObserver(
|
||
([entry]) => {
|
||
if (entry.isIntersecting) {
|
||
setTimeout(() => {
|
||
el.classList.add("reveal-visible")
|
||
}, delay)
|
||
observer.unobserve(el)
|
||
}
|
||
},
|
||
{ threshold: 0.1 },
|
||
)
|
||
observer.observe(el)
|
||
return () => observer.disconnect()
|
||
}, [delay])
|
||
|
||
return (
|
||
<Tag ref={ref} className={`reveal-up ${className}`}>
|
||
{children}
|
||
</Tag>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add lib/site-content.ts components/ScrollReveal.tsx
|
||
git commit -m "feat: add new site content data and ScrollReveal component"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 4: Header — New navigation with Products dropdown
|
||
|
||
**Files:**
|
||
- Rewrite: `components/Header.tsx`
|
||
|
||
- [ ] **Step 1: Write new Header.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import { useState, useEffect, useCallback } from "react"
|
||
import Image from "next/image"
|
||
import Link from "next/link"
|
||
import { usePathname } from "next/navigation"
|
||
import { useTranslations } from "next-intl"
|
||
import LocaleSwitcher from "@/components/LocaleSwitcher"
|
||
import { NAV_PRODUCT_ITEMS } from "@/lib/site-content"
|
||
|
||
export default function Header() {
|
||
const t = useTranslations("nav")
|
||
const [mobileOpen, setMobileOpen] = useState(false)
|
||
const [productsOpen, setProductsOpen] = useState(false)
|
||
const [scrolled, setScrolled] = useState(false)
|
||
const pathname = usePathname()
|
||
|
||
const closeAll = useCallback(() => {
|
||
setMobileOpen(false)
|
||
setProductsOpen(false)
|
||
}, [])
|
||
|
||
useEffect(() => {
|
||
const onScroll = () => setScrolled(window.scrollY > 20)
|
||
window.addEventListener("scroll", onScroll, { passive: true })
|
||
return () => window.removeEventListener("scroll", onScroll)
|
||
}, [])
|
||
|
||
useEffect(() => { closeAll() }, [pathname, closeAll])
|
||
|
||
const navLinks = [
|
||
{ href: "/docs", label: t("docs") },
|
||
{ href: "/pricing", label: t("pricing") },
|
||
{ href: "/blog", label: t("blog") },
|
||
]
|
||
|
||
return (
|
||
<header
|
||
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
||
scrolled
|
||
? "bg-bg-primary/80 backdrop-blur-xl border-b border-border"
|
||
: "bg-transparent"
|
||
}`}
|
||
>
|
||
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
|
||
{/* Logo */}
|
||
<Link href="/" className="flex items-center gap-2" onClick={closeAll}>
|
||
<Image
|
||
src="/assets/dalcode-app-icon.svg"
|
||
width={32}
|
||
height={32}
|
||
alt="DAL"
|
||
/>
|
||
<span className="font-display font-semibold text-lg text-text-primary">
|
||
DAL
|
||
</span>
|
||
</Link>
|
||
|
||
{/* Desktop Nav */}
|
||
<nav className="hidden md:flex items-center gap-1">
|
||
{/* Products Dropdown */}
|
||
<div
|
||
className="relative"
|
||
onMouseEnter={() => setProductsOpen(true)}
|
||
onMouseLeave={() => setProductsOpen(false)}
|
||
>
|
||
<button
|
||
type="button"
|
||
className="px-3 py-2 text-sm text-text-secondary hover:text-text-primary transition-colors flex items-center gap-1"
|
||
onClick={() => setProductsOpen((v) => !v)}
|
||
>
|
||
{t("products")}
|
||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" className={`transition-transform ${productsOpen ? "rotate-180" : ""}`}>
|
||
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||
</svg>
|
||
</button>
|
||
|
||
{productsOpen && (
|
||
<div className="absolute top-full left-0 pt-2">
|
||
<div className="bg-bg-card border border-border rounded-xl p-2 min-w-[240px] shadow-2xl">
|
||
{NAV_PRODUCT_ITEMS.map((item) => (
|
||
<Link
|
||
key={item.key}
|
||
href={item.href}
|
||
className="flex flex-col gap-0.5 px-3 py-2.5 rounded-lg hover:bg-bg-card-hover transition-colors"
|
||
onClick={closeAll}
|
||
>
|
||
<span className="text-sm font-medium text-text-primary">
|
||
{t(`productItems.${item.key}.name`)}
|
||
</span>
|
||
<span className="text-xs text-text-muted">
|
||
{t(`productItems.${item.key}.tagline`)}
|
||
</span>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{navLinks.map((link) => (
|
||
<Link
|
||
key={link.href}
|
||
href={link.href}
|
||
className={`px-3 py-2 text-sm transition-colors ${
|
||
pathname === link.href
|
||
? "text-text-primary"
|
||
: "text-text-secondary hover:text-text-primary"
|
||
}`}
|
||
>
|
||
{link.label}
|
||
</Link>
|
||
))}
|
||
</nav>
|
||
|
||
{/* Right side */}
|
||
<div className="hidden md:flex items-center gap-3">
|
||
<LocaleSwitcher />
|
||
<Link
|
||
href="/contact"
|
||
className="text-sm text-text-secondary hover:text-text-primary transition-colors"
|
||
>
|
||
{t("signIn")}
|
||
</Link>
|
||
<Link
|
||
href="/code"
|
||
className="px-4 py-2 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors"
|
||
>
|
||
{t("downloads")}
|
||
</Link>
|
||
</div>
|
||
|
||
{/* Mobile hamburger */}
|
||
<button
|
||
type="button"
|
||
className="md:hidden p-2"
|
||
onClick={() => setMobileOpen((v) => !v)}
|
||
aria-label={t("toggleMenu")}
|
||
>
|
||
<div className="w-5 flex flex-col gap-1.5">
|
||
<span className={`block h-px bg-text-primary transition-all ${mobileOpen ? "rotate-45 translate-y-[3.5px]" : ""}`} />
|
||
<span className={`block h-px bg-text-primary transition-all ${mobileOpen ? "-rotate-45 -translate-y-[3.5px]" : ""}`} />
|
||
</div>
|
||
</button>
|
||
</div>
|
||
|
||
{/* Mobile menu */}
|
||
{mobileOpen && (
|
||
<div className="md:hidden bg-bg-primary border-t border-border">
|
||
<div className="px-6 py-4 flex flex-col gap-2">
|
||
{NAV_PRODUCT_ITEMS.map((item) => (
|
||
<Link
|
||
key={item.key}
|
||
href={item.href}
|
||
className="py-2 text-sm text-text-secondary hover:text-text-primary"
|
||
onClick={closeAll}
|
||
>
|
||
{t(`productItems.${item.key}.name`)}
|
||
</Link>
|
||
))}
|
||
<hr className="border-border my-2" />
|
||
{navLinks.map((link) => (
|
||
<Link
|
||
key={link.href}
|
||
href={link.href}
|
||
className="py-2 text-sm text-text-secondary hover:text-text-primary"
|
||
onClick={closeAll}
|
||
>
|
||
{link.label}
|
||
</Link>
|
||
))}
|
||
<hr className="border-border my-2" />
|
||
<Link
|
||
href="/code"
|
||
className="py-2 text-sm font-medium text-accent"
|
||
onClick={closeAll}
|
||
>
|
||
{t("downloads")}
|
||
</Link>
|
||
<LocaleSwitcher />
|
||
</div>
|
||
</div>
|
||
)}
|
||
</header>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Verify Header renders**
|
||
|
||
```bash
|
||
cd /Users/leon/本地开发项目/claude-code/dalcode-website && PORT=55132 npx next dev &
|
||
sleep 5
|
||
curl -s http://localhost:55132 | head -50
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add components/Header.tsx
|
||
git commit -m "feat: new Header with Products dropdown and dark theme"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 5: Footer — New 4-column layout
|
||
|
||
**Files:**
|
||
- Rewrite: `components/Footer.tsx`
|
||
|
||
- [ ] **Step 1: Write new Footer.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import Image from "next/image"
|
||
import Link from "next/link"
|
||
import { useTranslations } from "next-intl"
|
||
import NewsletterForm from "@/components/NewsletterForm"
|
||
import LocaleSwitcher from "@/components/LocaleSwitcher"
|
||
import { FOOTER_GROUPS } from "@/lib/site-content"
|
||
|
||
export default function Footer() {
|
||
const t = useTranslations("footer")
|
||
|
||
return (
|
||
<footer className="border-t border-border bg-bg-primary">
|
||
<div className="max-w-7xl mx-auto px-6">
|
||
{/* Top: logo + newsletter */}
|
||
<div className="py-12 flex flex-col md:flex-row justify-between items-start gap-8">
|
||
<div className="flex items-center gap-2">
|
||
<Image src="/assets/dalcode-app-icon.svg" width={28} height={28} alt="DAL" />
|
||
<span className="font-display font-semibold text-text-primary">DAL</span>
|
||
</div>
|
||
<div className="w-full md:w-80">
|
||
<NewsletterForm />
|
||
</div>
|
||
</div>
|
||
|
||
{/* Link columns */}
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 pb-12">
|
||
{FOOTER_GROUPS.map((group) => (
|
||
<div key={group.key}>
|
||
<h3 className="text-xs font-semibold uppercase tracking-wider text-text-muted mb-4">
|
||
{t(`groups.${group.key}`)}
|
||
</h3>
|
||
<ul className="flex flex-col gap-2.5">
|
||
{group.links.map((link) => (
|
||
<li key={link.key}>
|
||
<Link
|
||
href={link.href}
|
||
className="text-sm text-text-secondary hover:text-text-primary transition-colors"
|
||
{...(link.external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
|
||
>
|
||
{t(`links.${link.key}`)}
|
||
</Link>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Bottom bar */}
|
||
<div className="border-t border-border py-6 flex flex-col md:flex-row justify-between items-center gap-4 text-xs text-text-muted">
|
||
<p>{t("copyright")}</p>
|
||
<div className="flex items-center gap-6">
|
||
<Link href="/privacy" className="hover:text-text-secondary transition-colors">
|
||
{t("privacy")}
|
||
</Link>
|
||
<Link href="/terms" className="hover:text-text-secondary transition-colors">
|
||
{t("terms")}
|
||
</Link>
|
||
<LocaleSwitcher />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Commit**
|
||
|
||
```bash
|
||
git add components/Footer.tsx
|
||
git commit -m "feat: new Footer with 4-column layout"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 6: Homepage sections — Hero + ProductEcosystem
|
||
|
||
**Files:**
|
||
- Rewrite: `components/home/HeroSection.tsx`
|
||
- Create: `components/home/ProductEcosystem.tsx`
|
||
|
||
- [ ] **Step 1: Write new HeroSection.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import Link from "next/link"
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
|
||
export default function HeroSection() {
|
||
const t = useTranslations("hero")
|
||
|
||
return (
|
||
<section className="relative min-h-screen flex items-center justify-center overflow-hidden pt-16">
|
||
{/* Background gradient */}
|
||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,var(--color-accent-glow)_0%,transparent_70%)]" />
|
||
|
||
<div className="relative z-10 max-w-4xl mx-auto px-6 text-center">
|
||
<ScrollReveal>
|
||
<span className="inline-block px-3 py-1 text-xs font-medium text-accent border border-accent/30 rounded-full mb-8">
|
||
{t("badge")}
|
||
</span>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={100}>
|
||
<h1 className="font-display text-5xl md:text-7xl font-bold tracking-tight text-text-primary leading-[1.1]">
|
||
{t("headline")}
|
||
</h1>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={200}>
|
||
<p className="mt-6 text-lg md:text-xl text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={300}>
|
||
<div className="mt-10 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||
<Link
|
||
href="/code"
|
||
className="px-6 py-3 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors"
|
||
>
|
||
{t("ctaPrimary")}
|
||
</Link>
|
||
<Link
|
||
href="/cli"
|
||
className="px-6 py-3 text-sm font-medium text-text-primary border border-border hover:border-border-hover rounded-lg transition-colors"
|
||
>
|
||
{t("ctaSecondary")}
|
||
</Link>
|
||
</div>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={400}>
|
||
<div className="mt-6 inline-flex items-center gap-2 px-4 py-2 bg-bg-card border border-border rounded-lg font-mono text-sm text-text-muted">
|
||
<span className="text-accent">$</span>
|
||
<span>{t("cliCommand")}</span>
|
||
<button
|
||
type="button"
|
||
className="ml-2 text-text-muted hover:text-text-primary transition-colors"
|
||
onClick={() => navigator.clipboard.writeText(t("cliCommand"))}
|
||
aria-label="Copy command"
|
||
>
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
|
||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</ScrollReveal>
|
||
|
||
{/* Product screenshot placeholder */}
|
||
<ScrollReveal delay={500}>
|
||
<div className="mt-16 rounded-xl border border-border bg-bg-card overflow-hidden shadow-2xl">
|
||
<div className="aspect-video flex items-center justify-center text-text-muted">
|
||
<div className="text-center">
|
||
<div className="text-4xl mb-2">⌘</div>
|
||
<p className="text-sm">Product screenshot</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</ScrollReveal>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Write ProductEcosystem.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import Link from "next/link"
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
import { PRODUCT_KEYS, PRODUCT_HREFS } from "@/lib/site-content"
|
||
|
||
export default function ProductEcosystem() {
|
||
const t = useTranslations("ecosystem")
|
||
|
||
return (
|
||
<section className="py-32 px-6">
|
||
<div className="max-w-6xl mx-auto">
|
||
<ScrollReveal>
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h2 className="font-display text-3xl md:text-5xl font-bold text-text-primary">
|
||
{t("title")}
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
<div className="mt-16 grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
{PRODUCT_KEYS.map((key, i) => (
|
||
<ScrollReveal key={key} delay={i * 100}>
|
||
<Link
|
||
href={PRODUCT_HREFS[key]}
|
||
className="group block p-8 rounded-xl border border-border bg-bg-card hover:bg-bg-card-hover hover:border-border-hover transition-all card-glow"
|
||
>
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-3">
|
||
{t(`products.${key}.name`)}
|
||
</p>
|
||
<h3 className="font-display text-xl font-semibold text-text-primary mb-2">
|
||
{t(`products.${key}.tagline`)}
|
||
</h3>
|
||
<p className="text-sm text-text-secondary mb-6 leading-relaxed">
|
||
{t(`products.${key}.description`)}
|
||
</p>
|
||
<div className="flex flex-wrap gap-2 mb-6">
|
||
{(t.raw(`products.${key}.features`) as string[]).map((f: string) => (
|
||
<span key={f} className="px-2 py-1 text-xs text-text-muted border border-border rounded-md">
|
||
{f}
|
||
</span>
|
||
))}
|
||
</div>
|
||
<span className="text-sm text-accent group-hover:underline">
|
||
{t(`products.${key}.cta`)} →
|
||
</span>
|
||
</Link>
|
||
</ScrollReveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add components/home/HeroSection.tsx components/home/ProductEcosystem.tsx
|
||
git commit -m "feat: new Hero and ProductEcosystem sections"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 7: Homepage sections — WorkflowSteps + FeatureGrid
|
||
|
||
**Files:**
|
||
- Create: `components/home/WorkflowSteps.tsx`
|
||
- Create: `components/home/FeatureGrid.tsx`
|
||
|
||
- [ ] **Step 1: Write WorkflowSteps.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
import { WORKFLOW_STEPS } from "@/lib/site-content"
|
||
|
||
export default function WorkflowSteps() {
|
||
const t = useTranslations("workflow")
|
||
|
||
return (
|
||
<section className="py-32 px-6 bg-bg-secondary">
|
||
<div className="max-w-6xl mx-auto">
|
||
<ScrollReveal>
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h2 className="font-display text-3xl md:text-5xl font-bold text-text-primary max-w-2xl">
|
||
{t("title")}
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
<div className="mt-16 grid grid-cols-1 md:grid-cols-3 gap-6">
|
||
{WORKFLOW_STEPS.map((step, i) => (
|
||
<ScrollReveal key={step} delay={i * 150}>
|
||
<div className="relative p-8 rounded-xl border border-border bg-bg-card h-full">
|
||
<span className="font-display text-6xl font-bold text-border">
|
||
{t(`steps.${step}.number`)}
|
||
</span>
|
||
<p className="mt-4 text-xs font-semibold uppercase tracking-widest text-accent">
|
||
{t(`steps.${step}.name`)}
|
||
</p>
|
||
<h3 className="mt-2 font-display text-xl font-semibold text-text-primary">
|
||
{t(`steps.${step}.title`)}
|
||
</h3>
|
||
<p className="mt-3 text-sm text-text-secondary leading-relaxed">
|
||
{t(`steps.${step}.description`)}
|
||
</p>
|
||
{/* Screenshot placeholder */}
|
||
<div className="mt-6 rounded-lg border border-border bg-bg-secondary aspect-video flex items-center justify-center">
|
||
<span className="text-xs text-text-muted">Screenshot</span>
|
||
</div>
|
||
</div>
|
||
</ScrollReveal>
|
||
))}
|
||
</div>
|
||
|
||
{/* Connecting line */}
|
||
<div className="hidden md:flex items-center justify-center mt-8 gap-2">
|
||
{WORKFLOW_STEPS.map((_, i) => (
|
||
<div key={i} className="flex items-center">
|
||
<div className="w-3 h-3 rounded-full border-2 border-accent bg-bg-primary" />
|
||
{i < WORKFLOW_STEPS.length - 1 && (
|
||
<div className="w-32 h-px bg-gradient-to-r from-accent to-border" />
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Write FeatureGrid.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
import { FEATURE_KEYS, FEATURE_ICONS } from "@/lib/site-content"
|
||
|
||
export default function FeatureGrid() {
|
||
const t = useTranslations("features")
|
||
|
||
return (
|
||
<section className="py-32 px-6">
|
||
<div className="max-w-6xl mx-auto">
|
||
<ScrollReveal>
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h2 className="font-display text-3xl md:text-5xl font-bold text-text-primary">
|
||
{t("title")}
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
<div className="mt-16 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{FEATURE_KEYS.map((key, i) => (
|
||
<ScrollReveal key={key} delay={i * 80}>
|
||
<div className="p-6 rounded-xl border border-border bg-bg-card hover:bg-bg-card-hover hover:border-border-hover transition-all card-glow h-full">
|
||
<span className="text-2xl">{FEATURE_ICONS[key]}</span>
|
||
<h3 className="mt-4 font-display text-base font-semibold text-text-primary">
|
||
{t(`items.${key}.title`)}
|
||
</h3>
|
||
<p className="mt-2 text-sm text-text-secondary leading-relaxed">
|
||
{t(`items.${key}.description`)}
|
||
</p>
|
||
</div>
|
||
</ScrollReveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add components/home/WorkflowSteps.tsx components/home/FeatureGrid.tsx
|
||
git commit -m "feat: add WorkflowSteps and FeatureGrid homepage sections"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 8: Homepage sections — EcosystemSection + BottomCta + FaqSection
|
||
|
||
**Files:**
|
||
- Create: `components/home/EcosystemSection.tsx`
|
||
- Create: `components/home/BottomCta.tsx`
|
||
- Create: `components/home/FaqSection.tsx`
|
||
|
||
- [ ] **Step 1: Write EcosystemSection.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import Link from "next/link"
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
import { PLATFORM_ADVANTAGE_KEYS } from "@/lib/site-content"
|
||
|
||
export default function EcosystemSection() {
|
||
const t = useTranslations("platform")
|
||
|
||
return (
|
||
<section className="py-32 px-6 bg-gradient-to-b from-bg-secondary to-[#0d0518]">
|
||
<div className="max-w-6xl mx-auto">
|
||
<ScrollReveal>
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h2 className="font-display text-3xl md:text-5xl font-bold text-text-primary max-w-3xl">
|
||
{t("title")}
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
{/* Architecture diagram */}
|
||
<ScrollReveal delay={200}>
|
||
<div className="mt-16 flex justify-center">
|
||
<div className="relative">
|
||
{/* Center node */}
|
||
<div className="w-40 h-40 rounded-2xl border-2 border-accent bg-bg-card flex flex-col items-center justify-center text-center">
|
||
<span className="text-sm font-semibold text-accent">DeepAILab</span>
|
||
<span className="text-xs text-text-muted mt-1">Platform</span>
|
||
</div>
|
||
{/* Branch nodes positioned absolutely */}
|
||
{(["Code", "CLI", "Office", "API"] as const).map((name, i) => {
|
||
const positions = [
|
||
"-top-20 left-1/2 -translate-x-1/2",
|
||
"top-1/2 -right-28 -translate-y-1/2",
|
||
"-bottom-20 left-1/2 -translate-x-1/2",
|
||
"top-1/2 -left-28 -translate-y-1/2",
|
||
]
|
||
return (
|
||
<div key={name} className={`absolute ${positions[i]} px-3 py-2 rounded-lg border border-border bg-bg-card text-xs text-text-secondary`}>
|
||
{name}
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
</div>
|
||
</ScrollReveal>
|
||
|
||
{/* Advantage cards */}
|
||
<div className="mt-20 grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
{PLATFORM_ADVANTAGE_KEYS.map((key, i) => (
|
||
<ScrollReveal key={key} delay={i * 100}>
|
||
<div className="p-6 rounded-xl border border-border bg-bg-card/50 backdrop-blur-sm">
|
||
<h3 className="font-display text-lg font-semibold text-text-primary">
|
||
{t(`advantages.${key}.title`)}
|
||
</h3>
|
||
<p className="mt-2 text-sm text-text-secondary leading-relaxed">
|
||
{t(`advantages.${key}.description`)}
|
||
</p>
|
||
</div>
|
||
</ScrollReveal>
|
||
))}
|
||
</div>
|
||
|
||
<ScrollReveal delay={400}>
|
||
<div className="mt-12 text-center">
|
||
<a
|
||
href="https://deepailab.ai"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="inline-flex items-center gap-2 px-6 py-3 text-sm font-medium text-accent border border-accent/30 hover:border-accent rounded-lg transition-colors"
|
||
>
|
||
{t("cta")}
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||
<path d="M7 17L17 7M17 7H7M17 7V17" />
|
||
</svg>
|
||
</a>
|
||
</div>
|
||
</ScrollReveal>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Write BottomCta.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import Link from "next/link"
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
|
||
export default function BottomCta() {
|
||
const t = useTranslations("bottomCta")
|
||
const hero = useTranslations("hero")
|
||
|
||
return (
|
||
<section className="relative py-32 px-6 overflow-hidden">
|
||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,var(--color-accent-glow)_0%,transparent_70%)]" />
|
||
|
||
<div className="relative z-10 max-w-3xl mx-auto text-center">
|
||
<ScrollReveal>
|
||
<h2 className="font-display text-3xl md:text-5xl font-bold text-text-primary">
|
||
{t("headline")}
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={100}>
|
||
<p className="mt-6 text-lg text-text-secondary">
|
||
{t("subheadline")}
|
||
</p>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={200}>
|
||
<div className="mt-10 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||
<Link
|
||
href="/code"
|
||
className="px-6 py-3 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors"
|
||
>
|
||
{t("ctaPrimary")}
|
||
</Link>
|
||
<Link
|
||
href="/cli"
|
||
className="px-6 py-3 text-sm font-medium text-text-primary border border-border hover:border-border-hover rounded-lg transition-colors"
|
||
>
|
||
{t("ctaSecondary")}
|
||
</Link>
|
||
</div>
|
||
</ScrollReveal>
|
||
|
||
<ScrollReveal delay={300}>
|
||
<div className="mt-6 inline-flex items-center gap-2 px-4 py-2 bg-bg-card border border-border rounded-lg font-mono text-sm text-text-muted">
|
||
<span className="text-accent">$</span>
|
||
<span>{hero("cliCommand")}</span>
|
||
</div>
|
||
</ScrollReveal>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Write FaqSection.tsx**
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { useTranslations } from "next-intl"
|
||
import ScrollReveal from "@/components/ScrollReveal"
|
||
import { FAQ_KEYS } from "@/lib/site-content"
|
||
|
||
export default function FaqSection() {
|
||
const t = useTranslations("faq")
|
||
const [openIndex, setOpenIndex] = useState<number | null>(null)
|
||
|
||
return (
|
||
<section id="faq" className="py-32 px-6 bg-bg-secondary">
|
||
<div className="max-w-3xl mx-auto">
|
||
<ScrollReveal>
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h2 className="font-display text-3xl md:text-5xl font-bold text-text-primary">
|
||
{t("title")}
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
<div className="mt-12 flex flex-col divide-y divide-border">
|
||
{FAQ_KEYS.map((key, i) => (
|
||
<ScrollReveal key={key} delay={i * 60}>
|
||
<div>
|
||
<button
|
||
type="button"
|
||
className="w-full py-5 flex items-center justify-between text-left group"
|
||
onClick={() => setOpenIndex(openIndex === i ? null : i)}
|
||
>
|
||
<span className="text-base font-medium text-text-primary group-hover:text-accent transition-colors pr-4">
|
||
{t(`items.${key}.q`)}
|
||
</span>
|
||
<svg
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
className={`flex-shrink-0 text-text-muted transition-transform ${openIndex === i ? "rotate-45" : ""}`}
|
||
>
|
||
<path d="M12 5v14M5 12h14" />
|
||
</svg>
|
||
</button>
|
||
{openIndex === i && (
|
||
<div className="pb-5 text-sm text-text-secondary leading-relaxed">
|
||
{t(`items.${key}.a`)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</ScrollReveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 4: Commit**
|
||
|
||
```bash
|
||
git add components/home/EcosystemSection.tsx components/home/BottomCta.tsx components/home/FaqSection.tsx
|
||
git commit -m "feat: add EcosystemSection, BottomCta, and FaqSection"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 9: Wire up homepage + delete old components
|
||
|
||
**Files:**
|
||
- Rewrite: `app/page.tsx`
|
||
- Rewrite: `components/home/index.ts`
|
||
- Delete: `components/home/IntegrationsSection.tsx`
|
||
- Delete: `components/home/PrinciplesSection.tsx`
|
||
- Delete: `components/home/BlogPreviewSection.tsx`
|
||
- Delete: `components/home/CtaSection.tsx`
|
||
|
||
- [ ] **Step 1: Rewrite components/home/index.ts**
|
||
|
||
```typescript
|
||
export { default as HeroSection } from "./HeroSection"
|
||
export { default as ProductEcosystem } from "./ProductEcosystem"
|
||
export { default as WorkflowSteps } from "./WorkflowSteps"
|
||
export { default as FeatureGrid } from "./FeatureGrid"
|
||
export { default as EcosystemSection } from "./EcosystemSection"
|
||
export { default as BottomCta } from "./BottomCta"
|
||
export { default as FaqSection } from "./FaqSection"
|
||
```
|
||
|
||
- [ ] **Step 2: Rewrite app/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import {
|
||
HeroSection,
|
||
ProductEcosystem,
|
||
WorkflowSteps,
|
||
FeatureGrid,
|
||
EcosystemSection,
|
||
BottomCta,
|
||
FaqSection,
|
||
} from "@/components/home"
|
||
import { SITE_BRAND, SITE_DESCRIPTION } from "@/lib/site-content"
|
||
|
||
export const metadata: Metadata = {
|
||
title: SITE_BRAND,
|
||
description: SITE_DESCRIPTION,
|
||
openGraph: {
|
||
title: SITE_BRAND,
|
||
description: SITE_DESCRIPTION,
|
||
},
|
||
}
|
||
|
||
export default function HomePage() {
|
||
return (
|
||
<>
|
||
<HeroSection />
|
||
<ProductEcosystem />
|
||
<WorkflowSteps />
|
||
<FeatureGrid />
|
||
<EcosystemSection />
|
||
<BottomCta />
|
||
<FaqSection />
|
||
</>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Delete old components**
|
||
|
||
```bash
|
||
rm components/home/IntegrationsSection.tsx
|
||
rm components/home/PrinciplesSection.tsx
|
||
rm components/home/BlogPreviewSection.tsx
|
||
rm components/home/CtaSection.tsx
|
||
```
|
||
|
||
- [ ] **Step 4: Verify homepage loads**
|
||
|
||
Start dev server, navigate to `http://localhost:55132`, take a screenshot and verify all 7 sections render.
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "feat: wire up new homepage sections, remove old components"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 10: Subpages — /code, /cli, /office, /platform, /pricing
|
||
|
||
**Files:**
|
||
- Create: `app/code/page.tsx`
|
||
- Create: `app/cli/page.tsx`
|
||
- Create: `app/office/page.tsx`
|
||
- Create: `app/platform/page.tsx`
|
||
- Create: `app/pricing/page.tsx`
|
||
|
||
- [ ] **Step 1: Write app/code/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
import Link from "next/link"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("codePage.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function CodePage() {
|
||
const t = await getTranslations("codePage.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
<div className="mt-10">
|
||
<Link
|
||
href="/contact"
|
||
className="px-6 py-3 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors"
|
||
>
|
||
{t("cta")}
|
||
</Link>
|
||
</div>
|
||
<div className="mt-16 rounded-xl border border-border bg-bg-card overflow-hidden">
|
||
<div className="aspect-video flex items-center justify-center text-text-muted">
|
||
<p className="text-sm">DAL Code product screenshots coming soon</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Write app/cli/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
import Link from "next/link"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("cliPage.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function CliPage() {
|
||
const t = await getTranslations("cliPage.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
<div className="mt-10 flex flex-col items-center gap-4">
|
||
<div className="inline-flex items-center gap-2 px-4 py-2 bg-bg-card border border-border rounded-lg font-mono text-sm text-text-muted">
|
||
<span className="text-accent">$</span>
|
||
<span>{t("cliCommand")}</span>
|
||
</div>
|
||
</div>
|
||
<div className="mt-16 rounded-xl border border-border bg-bg-card overflow-hidden">
|
||
<div className="aspect-video flex items-center justify-center text-text-muted bg-[#1a1a2e]">
|
||
<div className="font-mono text-sm text-left max-w-md">
|
||
<p><span className="text-accent">$</span> dal init</p>
|
||
<p className="text-text-muted mt-1">Initializing DAL CLI...</p>
|
||
<p className="text-green-400 mt-1">✓ Connected to DeepAILab Platform</p>
|
||
<p className="text-text-muted mt-1">Ready. Type `dal` to get started.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Write app/office/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
import Link from "next/link"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("officePage.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function OfficePage() {
|
||
const t = await getTranslations("officePage.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
<div className="mt-10">
|
||
<Link
|
||
href="/contact"
|
||
className="px-6 py-3 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors"
|
||
>
|
||
{t("cta")}
|
||
</Link>
|
||
</div>
|
||
<div className="mt-16 grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
{(["Word", "Excel", "PPT"] as const).map((name) => (
|
||
<div key={name} className="p-8 rounded-xl border border-border bg-bg-card">
|
||
<h3 className="font-display text-lg font-semibold text-text-primary">{name}</h3>
|
||
<p className="mt-2 text-sm text-text-muted">Coming soon</p>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 4: Write app/platform/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("platformPage.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function PlatformPage() {
|
||
const t = await getTranslations("platformPage.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
<div className="mt-10">
|
||
<a
|
||
href="https://deepailab.ai"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="inline-flex items-center gap-2 px-6 py-3 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors"
|
||
>
|
||
{t("cta")}
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||
<path d="M7 17L17 7M17 7H7M17 7V17" />
|
||
</svg>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 5: Write app/pricing/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("pricingPage.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function PricingPage() {
|
||
const t = await getTranslations("pricingPage.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
<div className="mt-16 text-text-muted text-sm">
|
||
Pricing details coming soon
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add app/code/ app/cli/ app/office/ app/platform/ app/pricing/
|
||
git commit -m "feat: add product subpages (code, cli, office, platform, pricing)"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 11: Update existing subpages (about, blog, contact, careers) for dark theme
|
||
|
||
**Files:**
|
||
- Modify: `app/about/page.tsx`
|
||
- Modify: `app/blog/page.tsx`
|
||
- Modify: `app/contact/page.tsx`
|
||
- Modify: `app/careers/page.tsx`
|
||
- Modify: `app/coming-soon/page.tsx`
|
||
- Modify: `app/not-found.tsx`
|
||
|
||
These pages currently use webflow CSS classes. They need to be converted to Tailwind. Since they are secondary pages, we use a minimal hero + content pattern consistent with the new subpages.
|
||
|
||
- [ ] **Step 1: Rewrite app/about/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("about.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function AboutPage() {
|
||
const t = await getTranslations("about.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Rewrite app/blog/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("blog.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function BlogPage() {
|
||
const t = await getTranslations("blog.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Rewrite app/contact/page.tsx**
|
||
|
||
```tsx
|
||
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
import ContactForm from "@/components/ContactForm"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("contact.hero")
|
||
return { title: t("headline") }
|
||
}
|
||
|
||
export default async function ContactPage() {
|
||
const t = await getTranslations("contact.hero")
|
||
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6">
|
||
<div className="max-w-4xl mx-auto">
|
||
<div className="text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">
|
||
{t("label")}
|
||
</p>
|
||
<h1 className="font-display text-4xl md:text-6xl font-bold text-text-primary leading-tight">
|
||
{t("headline")}
|
||
</h1>
|
||
<p className="mt-6 text-lg text-text-secondary max-w-2xl mx-auto leading-relaxed">
|
||
{t("subheadline")}
|
||
</p>
|
||
</div>
|
||
<div className="mt-16 max-w-xl mx-auto">
|
||
<ContactForm />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 4: Simplify app/careers/page.tsx, app/coming-soon/page.tsx, app/not-found.tsx**
|
||
|
||
Apply the same pattern: minimal hero with label + headline + description, using Tailwind classes, no webflow references.
|
||
|
||
For `not-found.tsx`:
|
||
|
||
```tsx
|
||
import Link from "next/link"
|
||
|
||
export default function NotFound() {
|
||
return (
|
||
<section className="min-h-screen pt-32 pb-20 px-6 flex items-center">
|
||
<div className="max-w-xl mx-auto text-center">
|
||
<p className="text-xs font-semibold uppercase tracking-widest text-accent mb-4">404</p>
|
||
<h1 className="font-display text-4xl font-bold text-text-primary">Page not found</h1>
|
||
<p className="mt-4 text-text-secondary">The page you're looking for doesn't exist or has been moved.</p>
|
||
<div className="mt-8">
|
||
<Link href="/" className="px-6 py-3 text-sm font-medium bg-accent hover:bg-accent-hover text-white rounded-lg transition-colors">
|
||
Back to home
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 5: Delete old about/blog/contact subcomponents that use webflow classes**
|
||
|
||
```bash
|
||
rm -rf components/about/
|
||
rm -rf components/blog/
|
||
rm -rf components/contact/
|
||
```
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "feat: rewrite all subpages for dark Tailwind theme"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 12: Update GsapAnimations + NewsletterForm + LocaleSwitcher
|
||
|
||
**Files:**
|
||
- Modify: `components/GsapAnimations.tsx`
|
||
- Modify: `components/NewsletterForm.tsx`
|
||
- Modify: `components/LocaleSwitcher.tsx`
|
||
|
||
- [ ] **Step 1: Simplify GsapAnimations.tsx**
|
||
|
||
Remove marquee, counter, and button hover init (no longer needed). Keep scroll reveal and smooth scroll:
|
||
|
||
```tsx
|
||
"use client"
|
||
|
||
import { useEffect } from "react"
|
||
|
||
export default function GsapAnimations() {
|
||
useEffect(() => {
|
||
let ctx: ReturnType<typeof import("gsap").gsap.context> | null = null
|
||
|
||
import("gsap").then(async ({ gsap }) => {
|
||
const { ScrollTrigger } = await import("gsap/ScrollTrigger")
|
||
gsap.registerPlugin(ScrollTrigger)
|
||
|
||
ctx = gsap.context(() => {
|
||
ScrollTrigger.batch(".reveal-up:not(.reveal-visible)", {
|
||
onEnter: (batch) =>
|
||
gsap.to(batch, {
|
||
opacity: 1,
|
||
y: 0,
|
||
stagger: 0.1,
|
||
duration: 0.6,
|
||
ease: "power2.out",
|
||
overwrite: true,
|
||
}),
|
||
})
|
||
})
|
||
})
|
||
|
||
return () => { ctx?.revert() }
|
||
}, [])
|
||
|
||
return null
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Update NewsletterForm.tsx to use Tailwind**
|
||
|
||
The existing form needs its webflow classes replaced with Tailwind. Update the component to use:
|
||
- `bg-bg-card border border-border` for input
|
||
- `bg-accent text-white` for submit button
|
||
- Use `useTranslations("footer.newsletter")` for all strings
|
||
|
||
- [ ] **Step 3: Update LocaleSwitcher.tsx to use Tailwind**
|
||
|
||
Replace webflow classes with:
|
||
- `text-sm text-text-muted hover:text-text-primary` styling
|
||
- Simple `<select>` or button toggle between zh-CN and en
|
||
|
||
- [ ] **Step 4: Commit**
|
||
|
||
```bash
|
||
git add components/GsapAnimations.tsx components/NewsletterForm.tsx components/LocaleSwitcher.tsx
|
||
git commit -m "refactor: update GsapAnimations, NewsletterForm, LocaleSwitcher for new design"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 13: Update ContactForm for dark theme
|
||
|
||
**Files:**
|
||
- Modify: `components/ContactForm.tsx`
|
||
|
||
- [ ] **Step 1: Update ContactForm to use Tailwind classes**
|
||
|
||
Replace all webflow CSS classes with Tailwind equivalents:
|
||
- Inputs: `w-full px-4 py-3 bg-bg-card border border-border rounded-lg text-text-primary placeholder:text-text-muted focus:border-accent focus:outline-none`
|
||
- Labels: `text-sm text-text-secondary`
|
||
- Submit button: `w-full px-6 py-3 bg-accent hover:bg-accent-hover text-white font-medium rounded-lg transition-colors`
|
||
- Error messages: `text-xs text-red-400`
|
||
|
||
Keep all existing React Hook Form + Zod validation logic unchanged.
|
||
|
||
- [ ] **Step 2: Commit**
|
||
|
||
```bash
|
||
git add components/ContactForm.tsx
|
||
git commit -m "refactor: update ContactForm for dark Tailwind theme"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 14: Full build verification + browser test
|
||
|
||
**Files:** None (verification only)
|
||
|
||
- [ ] **Step 1: Run TypeScript check**
|
||
|
||
```bash
|
||
cd /Users/leon/本地开发项目/claude-code/dalcode-website && npx tsc --noEmit 2>&1 | tail -30
|
||
```
|
||
|
||
Expected: No type errors.
|
||
|
||
- [ ] **Step 2: Run Next.js build**
|
||
|
||
```bash
|
||
npx next build 2>&1 | tail -30
|
||
```
|
||
|
||
Expected: Build succeeds with all pages generated.
|
||
|
||
- [ ] **Step 3: Start dev server and verify in browser**
|
||
|
||
```bash
|
||
PORT=55132 npx next dev &
|
||
```
|
||
|
||
Navigate to `http://localhost:55132` and verify:
|
||
- Homepage: all 7 sections render (Hero, ProductEcosystem, WorkflowSteps, FeatureGrid, EcosystemSection, BottomCta, FAQ)
|
||
- Navigation: Products dropdown works, all links navigate correctly
|
||
- Subpages: `/code`, `/cli`, `/office`, `/platform`, `/pricing`, `/about`, `/blog`, `/contact` all load
|
||
- Footer: 4-column layout renders correctly
|
||
- Language switch: toggle between zh-CN and en
|
||
- Mobile: responsive layout works at mobile breakpoints
|
||
- Scroll animations: sections fade in on scroll
|
||
|
||
- [ ] **Step 4: Take screenshots of key pages**
|
||
|
||
Screenshot homepage, `/code`, `/cli` pages and verify visual quality.
|
||
|
||
- [ ] **Step 5: Final commit if any fixes needed**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "fix: address build and visual issues from full verification"
|
||
```
|