# 森林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('')) failures.push('index language must be zh-CN') if (!html.includes('森林AI')) 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 `` 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 ` ``` - [ ] **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" ```