Files
hunjing/frontend/AGENTS.md
T

188 lines
8.2 KiB
Markdown
Raw 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.
# 前端开发规范
## 技术栈
Next.js + TypeScript + React + Tailwind CSS + Zustand/Jotai + pnpm
### 核心依赖
- **实时通信**: SSE / WebSocket
- **可视化**: Mermaid + 图谱可视化库
- **测试**: Vitest + Testing Library
- **代码质量**: ESLint (flat config) + Prettier + Husky + lint-staged
## 开发命令
```bash
pnpm install # 安装依赖
pnpm add <pkg> # 添加依赖
pnpm remove <pkg> # 移除依赖
pnpm dev # 启动开发服务器 (默认端口 3000)
pnpm build # 构建生产版本
pnpm start # 启动生产服务器
pnpm lint # 运行 ESLint 检查
pnpm type-check # TypeScript 类型检查
# 代码格式化(Prettier)
pnpm format # 格式化全部文件
pnpm format:check # 检查格式是否合规(CI / 提交钩子使用)
# 测试(Vitest)
pnpm test # 运行全部测试(单次)
pnpm test:watch # 监听模式
pnpm test:coverage # 运行测试并生成覆盖率报告
```
## 代码规范
### 页面设计
图标:统一使用 Lucide 图标,界面全程禁止使用表情符号。
设计标准:对标 Awwwards 顶级网站水准,达到 Awwwards、FWA、CSS Design Awards 每日最佳网站同等设计品质。
创意自由度:将浏览器视作交互式艺术画布,跳出传统布局框架,追求先锋视觉风格、实验性排版、流畅物理动效、极具冲击力的文字版式。
沉浸式体验:融合代码、高级渲染逻辑、图片素材,打造统一完整的精品页面,做出突破常规 UI 认知、令人惊艳的数字交互体验。
### 通用规范
- 遵循 ESLint + Prettier 配置,提交前必须通过 lint 与格式检查
- 使用 TypeScript 严格模式 (`strict: true`),禁止使用 `any` 类型
- 组件使用函数式组件 + Hooks,优先使用 Server Components,必要时使用 `'use client'`
- 文件命名: 组件使用 PascalCase (`UserProfile.tsx`),工具函数使用 camelCase (`formatDate.ts`)
- 使用 `path` 别名 (`@/*`) 导入模块,避免相对路径层级过深
- 状态管理: 全局状态使用 Zustand/Jotai,局部状态使用 React useState/useReducer
### CSS 变量引用
CSS 变量引用遵循 **三层递进规则**,优先级由上至下。
#### 规则
```text
Tailwind 映射类 → 优先使用
Tailwind 任意值 [var(--)] → 仅当变量不在 @theme 映射表中时使用
内联 style → 仅限复合值 / 动态运行时值
```
#### 具体对照
`globals.css` 的 `@theme inline {}` 块已映射的部分,直接用 Tailwind 类:
```tsx
// ✅ 正确:变量在 @theme inline {} 中有 --color-X 映射 → 用 Tailwind 类
<div className="bg-patina text-fg-dim border-rule" />
<span className="text-cinnabar" />
<div className="bg-night-bronze text-fg" />
<div className="bg-surface" />
<button className="border-gilt text-gilt" />
<div className="bg-btn-primary-bg" /> {/* Layer 2 组件 token 同理 */}
// ✅ 正确:变量未映射到 @theme inline {} → 用 Tailwind 任意值
<div className="bg-[var(--patina-wash)]" />
<span className="text-[var(--fg-faint)]" />
<div className="border-[var(--gilt-dim)]" />
<div className="bg-[var(--cinnabar-wash)]" />
```
> `bg-[var(--x)]` 是 Tailwind v4 的合法任意值语法(非 hack),属于 Tailwind 体系内,**不是** style 违规。`--patina-wash`、`--patina-dim`、`--gilt-faint`、`--gilt-dim`、`--cinnabar-wash`、`--cinnabar-dim` 当前均未直接映射,使用任意值是正确做法。
```tsx
// ❌ 禁止:变量已在 @theme inline {} 中有映射,却用任意值
// 不要用 bg-[var(--patina)] —— 应写 bg-patina(已映射)
// 不要用 text-[var(--cinnabar)] —— 应写 text-cinnabar(已映射)
// 不要用 border-[var(--rule)] —— 应写 border-rule(已映射)
// 不要用 text-[var(--fg-dim)] —— 应写 text-fg-dim(已映射)
// ❌ 禁止:用内联 style 表达单值 CSS 变量
// 不要写 style={{ color: "var(--patina)" }}
// 不要写 style={{ background: "var(--surface)" }}
// ✅ 正确:渐变色/复合 CSS 用内联 style(Tailwind 无法表达)
<div style={{
background: "linear-gradient(180deg, var(--patina-wash), var(--surface))",
boxShadow: "inset 0 1px 0 var(--face-in-top), var(--shadow)",
}} />
// ✅ 正确:动态运行时值用内联 style
<div style={{ color: health === "ok" ? "var(--patina)" : "var(--cinnabar)" }} />
// ✅ 正确:SVG 属性用内联 style 或 className
<circle style={{ fill: "var(--patina)", stroke: "var(--gilt)" }} />
```
#### 映射速查
当前 `@theme inline {}` 中已映射的 铜镜鉴心 变量(查阅 `globals.css` 确认完整列表):
| CSS 变量 | Tailwind 类前缀 | 示例 |
| ---------- | ---------------- | ------ |
| `--patina` | `patina` | `bg-patina` `text-patina` `border-patina` |
| `--patina-bright` | `patina-bright` | `bg-patina-bright` |
| `--gilt` | `gilt` | `bg-gilt` `text-gilt` |
| `--cinnabar` | `cinnabar` | `bg-cinnabar` `text-cinnabar` |
| `--ink` | `ink` | `bg-ink` |
| `--night-bronze` | `night-bronze` | `bg-night-bronze` |
| `--fg` | `fg` | `text-fg` |
| `--fg-dim` | `fg-dim` | `text-fg-dim` |
| `--fg-faint` | `fg-faint` | `text-fg-faint` |
| `--rule` | `rule` | `border-rule` `bg-rule` |
| `--surface` | `surface` | `bg-surface` |
| `--surface-hi` | `surface-hi` | `bg-surface-hi` |
| `--patina-wash` | `patina-wash` | `bg-patina-wash` |
| `--patina-dim` | `patina-dim` | `border-patina-dim` `bg-patina-dim` |
| `--gilt-dim` | `gilt-dim` | `border-gilt-dim` `text-gilt-dim` `bg-gilt-dim` |
| `--gilt-faint` | `gilt-faint` | `bg-gilt-faint` |
| `--cinnabar-wash` | `cinnabar-wash` | `bg-cinnabar-wash` |
| `--cinnabar-dim` | `cinnabar-dim` | `border-cinnabar-dim` |
| `--glass` | `glass` | `bg-glass` |
| `--glass-border` | `glass-border` | `border-glass-border` |
| `--overlay-hover` | `overlay-hover` | `bg-overlay-hover` |
**未映射**(用 `bg-[var(--x)]`):`--face-sheen` `--sweep-gradient` `--face-in-top` `--face-in-bot` `--shadow` `--aurora-*` `--code-*` 以及 SVG 特有的 `--raw-*`
#### 例外清单
以下变量是复合 CSS 值或动画属性,**必须**用内联 style,不能抽象为 Tailwind 类:
- 渐变/光照效果:`--face-sheen` `--sweep-gradient` `--face-in-top` `--face-in-bot`
- 阴影:`--shadow`
- 背景光晕:`--aurora-*`
- 动态 `color-mix()` 表达式
> 规则生效日:此约定写入后,新代码必须遵守。存量代码暂不回溯,待 P0/P1 功能补齐后再做 codemod 迁移。
- 统一通过 `lib/api`(`client.ts` 出口)调用后端,禁止在组件内散落 fetch
- SSE 连接封装在 `lib/sse-client.ts`,不在组件内直接实例化 EventSource
- 所有 API 调用必须有 TypeScript 类型定义和错误处理(`ApiError` 统一承载 code/trace_id)
## 可视化规范
- 图谱可视化使用专用图谱库,Mermaid 用于流程图/时序图等
- 可视化组件必须支持响应式和主题切换 (暗色/亮色)
## 代码审查
```bash
pnpm lint # ESLint 检查
pnpm type-check # TypeScript 类型检查
pnpm format:check # Prettier 格式检查
pnpm test # Vitest 测试
```
- 必须同时通过 lint、type-check 与格式检查才能提交
- Husky + lint-staged 已配置 `pre-commit` 钩子:对暂存文件自动跑 ESLint --fix + Prettier,再整体 type-check;不通过则阻止提交(临时跳过用 `git commit --no-verify`)
- 注:本仓库 git 根在父目录(monorepo),`prepare` 脚本以 `cd .. && husky frontend/.husky` 安装钩子,`core.hooksPath` 指向 `frontend/.husky/_`
## 绝对禁止事项
- 直接修改 `package.json` 或 `pnpm-lock.yaml`(依赖必须用 `pnpm add/remove`;scripts 字段可用 `pnpm pkg set`,注意带冒号的键需用方括号语法 `scripts["name"]`)
- 在客户端代码中硬编码敏感信息 (密钥、Token等)
- 使用 `any` 类型 (除非经过团队评审)
- 忽略 TypeScript 或 ESLint 错误强制提交
- 在 Server Component 中直接使用 `useState`、`useEffect` 等客户端 Hooks
- 使用 CSS-in-JS 方案 (统一使用 Tailwind CSS)
- 在 Client Component 中直接调用数据库
- 在 useEffect 中做页面初始数据请求
- 创建 Class 组件