Files
agent/docs/superpowers/plans/2026-07-21-forest-ai-frontend-foundation.md

249 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 森林AI Frontend Foundation 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:** 将 Web 客户端统一为“森林AI”品牌并建立可在桌面和移动浏览器使用的基础布局与视觉系统。
**Architecture:** 保留 React、Arco Design 和现有工作台信息架构。品牌资产通过公共 SVG 文件引用,主题令牌集中到独立样式文件,移动导航状态由 `ProjectPage` 管理,避免组件各自实现断点逻辑。
**Tech Stack:** React 18、TypeScript 6、Vite 8、Arco Design、Playwright visual check、CSS custom properties。
## Global Constraints
- 产品可见名称和 HTML title 必须为“森林AI”。
- 主色固定为 `#165DFF`ICON 使用已批准的年轮知识树方案。
- 桌面优先,但 390×844 视口必须能够访问主内容。
- 不增加新的前端运行时依赖。
- 超出 MVP 的探索同步、支付、窗口停靠和自主 Agent 控件不得伪装为可用功能。
---
### Task 1: 品牌资产与静态契约
**Files:**
- Create: `apps/web_v1/public/senlinai-icon.svg`
- Modify: `apps/web_v1/public/favicon.svg`
- Modify: `apps/web_v1/index.html`
- Modify: `apps/web_v1/scripts/structure-check.mjs`
- Modify: `apps/web_v1/src/pages/login.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-topbar.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-rail.tsx`
**Interfaces:**
- Produces: `/senlinai-icon.svg` as the single brand image consumed by login, topbar and project rail.
- [ ] **Step 1: Add failing brand checks**
Extend `structure-check.mjs` with exact assertions:
```js
const html = readFileSync('index.html', 'utf8')
if (!html.includes('<html lang="zh-CN">')) failures.push('index language must be zh-CN')
if (!html.includes('<title>森林AI</title>')) failures.push('document title must be 森林AI')
if (!existsSync('public/senlinai-icon.svg')) failures.push('missing public/senlinai-icon.svg')
for (const file of ['src/pages/login.tsx', 'src/pages/projects/project-topbar.tsx', 'src/pages/projects/project-rail.tsx']) {
const source = readFileSync(file, 'utf8')
if (!source.includes('/senlinai-icon.svg')) failures.push(`${file} must use the brand icon`)
}
```
- [ ] **Step 2: Verify the check fails**
Run: `node scripts/structure-check.mjs`
Expected: FAIL with `missing public/senlinai-icon.svg` and title/asset usage failures.
- [ ] **Step 3: Add the approved SVG and replace all brand placeholders**
Use one `<img className="brand-icon" src="/senlinai-icon.svg" alt="" />` at decorative positions, and `aria-label="森林AI 工作台"` on the rail brand button. Set `lang="zh-CN"`, title `森林AI`, and favicon `/senlinai-icon.svg` in `index.html`. Replace visible `森林Agent` and `SenlinAI` labels with `森林AI`.
- [ ] **Step 4: Verify brand contracts**
Run: `node scripts/structure-check.mjs && npm run build && npm run lint`
Expected: all commands PASS; no visible `S` placeholder remains in brand components.
- [ ] **Step 5: Commit**
```powershell
git add apps/web_v1/public apps/web_v1/index.html apps/web_v1/scripts/structure-check.mjs apps/web_v1/src/pages/login.tsx apps/web_v1/src/pages/projects/project-topbar.tsx apps/web_v1/src/pages/projects/project-rail.tsx
git commit -m "feat(web): apply forest AI brand identity"
```
### Task 2: 主题令牌、字体与基础文案
**Files:**
- Create: `apps/web_v1/src/styles/tokens.css`
- Modify: `apps/web_v1/src/main.tsx`
- Modify: `apps/web_v1/src/index.css`
- Modify: `apps/web_v1/src/App.css`
- Modify: `apps/web_v1/src/pages/workspace-body.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-overview.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-ai.tsx`
**Interfaces:**
- Produces: semantic custom properties `--color-*`, `--space-*`, `--radius-*` used by all page CSS.
- [ ] **Step 1: Add failing text and token checks**
Add to `structure-check.mjs`:
```js
const tokenSource = existsSync('src/styles/tokens.css') ? readFileSync('src/styles/tokens.css', 'utf8') : ''
for (const token of ['--color-primary: #165dff', '--font-sans', '--space-4: 16px']) {
if (!tokenSource.toLowerCase().includes(token)) failures.push(`missing token ${token}`)
}
for (const forbidden of ['森林Agent', 'AI智能体', '实时接口', '进度 60%']) {
for (const file of requiredFiles.filter((name) => name.endsWith('.tsx'))) {
if (readFileSync(file, 'utf8').includes(forbidden)) failures.push(`${file} contains forbidden copy ${forbidden}`)
}
}
```
- [ ] **Step 2: Verify failures**
Run: `node scripts/structure-check.mjs`
Expected: FAIL for missing tokens and old copy.
- [ ] **Step 3: Introduce semantic tokens and Chinese system font**
Create tokens beginning with:
```css
:root {
--color-primary: #165dff;
--color-bg: #f7f8fa;
--color-panel: #ffffff;
--color-border: #e5e6eb;
--color-text: #1d2129;
--color-muted: #6b7785;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--radius-control: 8px;
}
```
Import it before `index.css`. Replace old `--senlin-*` variables and scattered brand colors with semantic tokens. Rename visible `AI智能体` to `AI 助手`; remove `实时接口` and fixed progress copy.
- [ ] **Step 4: Verify tokens and copy**
Run: `node scripts/structure-check.mjs && npm run build && npm run lint`
Expected: PASS.
- [ ] **Step 5: Commit**
```powershell
git add apps/web_v1/src/styles apps/web_v1/src/main.tsx apps/web_v1/src/index.css apps/web_v1/src/App.css apps/web_v1/src/pages
git commit -m "refactor(web): unify tokens and product copy"
```
### Task 3: 登录页响应式重构
**Files:**
- Modify: `apps/web_v1/src/pages/login.tsx`
- Modify: `apps/web_v1/src/App.css`
- Modify: `apps/web_v1/scripts/visual-check.mjs`
**Interfaces:**
- Consumes: semantic tokens and `/senlinai-icon.svg`.
- Produces: two-column desktop and one-column mobile login layout.
- [ ] **Step 1: Add desktop and mobile login assertions**
In `visual-check.mjs`, capture login at 1440×1024 and 390×844 and assert:
```js
const loginMetrics = await page.evaluate(() => ({
overflowX: document.documentElement.scrollWidth > document.documentElement.clientWidth,
title: document.title,
columns: getComputedStyle(document.querySelector('.login-card')).gridTemplateColumns,
}))
if (loginMetrics.overflowX) failures.push('login must not overflow horizontally')
if (loginMetrics.title !== '森林AI') failures.push(`unexpected title ${loginMetrics.title}`)
```
At the mobile viewport assert `.login-card` width is at most 390 and its computed column count is one.
- [ ] **Step 2: Verify the current layout fails**
Run: `$env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs`
Expected: FAIL on mobile overflow or login column assertions.
- [ ] **Step 3: Implement the two-column login**
Keep `.login-brand-panel` and `.login-form-panel`; remove the third marketing panel. Add `@media (max-width: 760px)` that sets `grid-template-columns: 1fr`, reduces outer padding to 16px, and keeps every input/button at full available width.
- [ ] **Step 4: Verify at both viewports**
Run: `$env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs`
Expected: login checks PASS with no clipping.
- [ ] **Step 5: Commit**
```powershell
git add apps/web_v1/src/pages/login.tsx apps/web_v1/src/App.css apps/web_v1/scripts/visual-check.mjs
git commit -m "fix(web): make login responsive"
```
### Task 4: 移动工作台导航与有效 DOM
**Files:**
- Modify: `apps/web_v1/src/pages/workspace-home.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-topbar.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-rail.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-sidebar.tsx`
- Modify: `apps/web_v1/src/pages/projects/project-statusbar.tsx`
- Modify: `apps/web_v1/src/App.css`
- Modify: `apps/web_v1/scripts/visual-check.mjs`
**Interfaces:**
- Produces: `navOpen: 'projects' | 'channels' | null` state controlled by `ProjectPage`.
- `ProjectTopbar` emits `onOpenProjects` and `onOpenChannels`.
- [ ] **Step 1: Add failing DOM and mobile navigation checks**
Assert that the status user container has no descendant button, the mobile viewport has no horizontal overflow, and buttons labelled `打开项目导航` and `打开频道导航` can reveal their respective asides.
- [ ] **Step 2: Verify failures**
Run: `$env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs`
Expected: FAIL for nested button console error and missing mobile navigation.
- [ ] **Step 3: Implement controlled drawers**
Add `const [navOpen, setNavOpen] = useState<'projects' | 'channels' | null>(null)` to `ProjectPage`. Pass an `open` class and close callback to rail/sidebar. Add topbar buttons with exact accessible names. CSS must position asides as fixed overlays below 768px, add a backdrop button, and remove `.workbench-shell { min-width: 1180px; }`.
Replace the status user outer `<button>` with a non-nested structure:
```tsx
<div className="status-user">
<button className="status-profile" type="button" onClick={() => setProfileOpen(true)}>
<span className="status-avatar" aria-hidden="true"></span>
<span className="status-name"></span>
</button>
<Button className="status-upgrade" size="mini" type="primary" onClick={() => setUpgradeOpen(true)}></Button>
</div>
```
- [ ] **Step 4: Run full frontend verification**
Run: `node scripts/structure-check.mjs; $env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs; npm run build; npm run lint`
Expected: all PASS and browser console errors are empty.
- [ ] **Step 5: Commit**
```powershell
git add apps/web_v1/src/pages/workspace-home.tsx apps/web_v1/src/pages/projects apps/web_v1/src/App.css apps/web_v1/scripts/visual-check.mjs
git commit -m "feat(web): add responsive workbench navigation"
```