feat(skills): 创建 design-handoff skill 骨架 + 配置文件
- SKILL.md: skill 入口,含 6 步核心流程 + 组件映射推断规则 - defaults/tokens.yml: 从 tokens.scss 提取的完整 Token 注册表 - defaults/components.yml: 16 个 UI 组件映射 + 5 个框架组件 - rules/interaction-rules.yml: 8 条交互推断规则 - package.json + js-yaml 依赖
This commit is contained in:
422
.claude/skills/design-handoff/SKILL.md
Normal file
422
.claude/skills/design-handoff/SKILL.md
Normal file
@@ -0,0 +1,422 @@
|
||||
---
|
||||
name: design-handoff
|
||||
description: 将 HTML 原型转换为结构化设计交付包(截图 + SPEC.md + Token 映射),供新会话 LLM 高保真实现
|
||||
---
|
||||
|
||||
# 设计交付 Skill (design-handoff)
|
||||
|
||||
将 huashu-design 生成的 HTML 原型转换为结构化设计交付包,使新会话中的 LLM 能够高保真还原 UI 实现。
|
||||
|
||||
## 触发词
|
||||
|
||||
- `design-handoff`
|
||||
- `设计交付`
|
||||
- `handoff`
|
||||
|
||||
---
|
||||
|
||||
## 前置检查
|
||||
|
||||
执行任何步骤前,必须完成以下检查:
|
||||
|
||||
### 1. 输入验证
|
||||
|
||||
确认输入文件为 huashu-design 产物,须同时满足:
|
||||
- 文件为 `.html` 格式
|
||||
- 包含 React + Babel 的 script 标签(`<script src="...babel...">` 或 `type="text/babel"`)
|
||||
- 包含 Token 定义块(`const T = {` 或等效全局样式常量)
|
||||
|
||||
若不满足,输出错误并终止:
|
||||
```
|
||||
[design-handoff] 错误:输入文件不是 huashu-design 产物。
|
||||
期望特征:
|
||||
- React/Babel script 标签
|
||||
- const T = { ... } 样式定义块
|
||||
请确认输入文件来源。
|
||||
```
|
||||
|
||||
### 2. Token 配置文件初始化
|
||||
|
||||
检查项目根目录下的 `.design/tokens.yml` 是否存在:
|
||||
|
||||
- **存在** → 直接使用,跳过初始化
|
||||
- **不存在** → 从 `defaults/tokens.yml` 复制到 `.design/tokens.yml`
|
||||
|
||||
若 `defaults/tokens.yml` 也不存在,输出警告并使用内置最小 Token 集:
|
||||
```yaml
|
||||
# 内置最小 Token 集(defaults/tokens.yml 缺失时的降级方案)
|
||||
color:
|
||||
primary: "#1890ff"
|
||||
success: "#52c41a"
|
||||
warning: "#faad14"
|
||||
danger: "#ff4d4f"
|
||||
text: "#333333"
|
||||
text_secondary: "#666666"
|
||||
bg: "#ffffff"
|
||||
bg_secondary: "#f5f5f5"
|
||||
border: "#d9d9d9"
|
||||
spacing:
|
||||
xs: 4
|
||||
sm: 8
|
||||
md: 16
|
||||
lg: 24
|
||||
xl: 32
|
||||
fontSize:
|
||||
h1: 28
|
||||
h2: 22
|
||||
body_lg: 18
|
||||
body: 16
|
||||
body_sm: 14
|
||||
caption: 13
|
||||
radius:
|
||||
sm: 4
|
||||
md: 8
|
||||
lg: 16
|
||||
pill: 999
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心流程(6 步)
|
||||
|
||||
### Step 1: 解析 HTML 原型
|
||||
|
||||
调用 `scripts/parse-prototype.mjs` 解析输入 HTML 文件:
|
||||
|
||||
```bash
|
||||
node scripts/parse-prototype.mjs <html文件路径>
|
||||
```
|
||||
|
||||
**输出:** JSON 格式的 DOM 结构树,包含:
|
||||
- 节点层级关系
|
||||
- 每个节点的样式属性(从 inline style + `const T = {}` + CSS class 提取)
|
||||
- 文本内容
|
||||
- 嵌套组件边界推断
|
||||
|
||||
**若脚本不存在:** LLM 自行解析 HTML,提取以下信息:
|
||||
- 从 `const T = {}` 提取所有 Token 值
|
||||
- 遍历 DOM 树提取每个节点的 `style` 属性和文本内容
|
||||
- 按缩进/嵌套层级推断组件边界
|
||||
|
||||
### Step 2: 截图
|
||||
|
||||
调用 `scripts/extract-screenshots.mjs` 生成截图:
|
||||
|
||||
```bash
|
||||
node scripts/extract-screenshots.mjs <html文件路径> --output <输出目录>
|
||||
```
|
||||
|
||||
**输出:**
|
||||
- `screenshots/full.png` — 整页截图
|
||||
- `screenshots/sections/` — 按语义区块拆分的局部截图(若脚本支持)
|
||||
|
||||
**若脚本不存在:** 指导用户手动截图或使用浏览器 DevTools 截图,保存到 `docs/design/{原型名}/screenshots/`。
|
||||
|
||||
### Step 3: Token 匹配
|
||||
|
||||
调用 `scripts/match-tokens.mjs` 进行 Token 匹配:
|
||||
|
||||
```bash
|
||||
node scripts/match-tokens.mjs <解析结果.json> --tokens <tokens.yml路径>
|
||||
```
|
||||
|
||||
**输出:** Token 匹配报告,包含:
|
||||
- `matched` — 已匹配的 Token(原型中的值 → Token 名称)
|
||||
- `unmatched` — 未匹配的值(需要新增 Token 或确认别名)
|
||||
- `pending` — 接近匹配但需人工确认的项
|
||||
|
||||
**若脚本不存在:** LLM 自行匹配:
|
||||
1. 读取 `.design/tokens.yml` 中的所有 Token 定义
|
||||
2. 将 HTML 中的每个样式值(颜色、字号、间距、圆角等)与 Token 比对
|
||||
3. 精确匹配 → `matched`
|
||||
4. 无匹配 → `unmatched`(附带建议的 Token 名称)
|
||||
5. 相似但不确定 → `pending`
|
||||
|
||||
### Step 4: 组件映射推断
|
||||
|
||||
读取 `defaults/components.yml`,然后 LLM 按 DOM 特征推断组件映射。
|
||||
|
||||
**若 `defaults/components.yml` 不存在:** 使用以下内置组件映射规则:
|
||||
|
||||
#### 组件推断规则(8 条)
|
||||
|
||||
按优先级从高到低依次匹配,首个命中的规则决定组件类型:
|
||||
|
||||
| # | DOM 特征 | 推断组件 | 关键判定信号 |
|
||||
|---|----------|----------|-------------|
|
||||
| 1 | 容器节点 + `borderRadius` + `boxShadow` + 内含标题元素 + 正文元素 | `ContentCard` | borderRadius > 0 + boxShadow 存在 + 子节点含标题层级文本 |
|
||||
| 2 | 左侧竖线装饰(`borderLeft` / `::before` 伪元素宽度 3-6px)+ 标题文本 + 可选右侧链接文字 | `SectionTitle` | 3-6px 左侧彩色边框 + 标题级字号 |
|
||||
| 3 | 按钮节点 + 主色背景(匹配 `color.primary`)+ 白色文字 + `height` 44-56px | `PrimaryButton` | 背景色 = primary + 文字色 = 白/接近白 + 按钮语义 |
|
||||
| 4 | 按钮节点 + 边框存在 + 背景透明/白色 + 文字色 = 主色或中性色 | `SecondaryButton` | border 存在 + 背景无填充 + 按钮语义 |
|
||||
| 5 | 页面最外层容器节点 + `padding` + 可滚动(`overflow: auto/scroll` 或页面 body 级) | `PageShell` | DOM 深度 = 1-2 + padding + 无固定高度 |
|
||||
| 6 | 小型容器 + 接近正方形/圆形(宽高比 0.8-1.2)+ 包含数字或短文字 + 有背景色 | `StatusTag` | 宽高比 ≈ 1 + 内容简短 + 背景色非白 |
|
||||
| 7 | 列表行 + 左侧图标区 + 双行文字(主文字 + 副文字)+ 右侧箭头或 chevron 符号 | `ListItem` | 行级容器 + 左图标 + 双行文本 + 右箭头 |
|
||||
| 8 | 未匹配上述任何规则 | `需新建组件` | 标记为 `Unknown__<描述>`,需在 SPEC.md 中描述视觉特征 |
|
||||
|
||||
**推断方法:**
|
||||
1. 对解析后的 DOM 树做深度优先遍历
|
||||
2. 对每个非叶子节点,按上述 8 条规则依次检测
|
||||
3. 命中规则 → 标记组件类型 + 记录判定依据
|
||||
4. 全部未命中 → 标记 `需新建组件` + 附带节点样式摘要
|
||||
5. 输出组件映射表到交付包
|
||||
|
||||
### Step 5: 交互推断
|
||||
|
||||
调用 `scripts/infer-interactions.mjs` 推断交互行为:
|
||||
|
||||
```bash
|
||||
node scripts/infer-interactions.mjs <解析结果.json>
|
||||
```
|
||||
|
||||
**输出:** 交互行为清单,包含:
|
||||
- `onClick` — 可点击元素及其预期行为(导航、弹窗、状态切换等)
|
||||
- `onScroll` — 滚动相关行为(无限加载、吸顶、视差等)
|
||||
- `onInput` — 表单输入行为(验证、联动、提交等)
|
||||
- `transitions` — 过渡动画(hover 效果、展开折叠等)
|
||||
|
||||
**若脚本不存在:** LLM 自行推断:
|
||||
1. 检查 DOM 中的 `onClick` / `onChange` 等事件绑定
|
||||
2. 检查 CSS 中的 `transition` / `animation` / `@keyframes`
|
||||
3. 检查 `cursor: pointer` 元素(隐含可点击)
|
||||
4. 检查 `overflow: scroll/auto` 容器(隐含滚动行为)
|
||||
5. 按钮语义元素(`<button>`、`role="button"`)推断点击行为
|
||||
|
||||
### Step 6: 组装 SPEC.md
|
||||
|
||||
读取 `templates/spec-template.md`,将前 5 步收集的数据组装为 SPEC.md。
|
||||
|
||||
**若模板不存在:** 使用以下结构:
|
||||
|
||||
```markdown
|
||||
# {原型名称} 设计规格
|
||||
|
||||
> 由 design-handoff 自动生成 | 源文件: {HTML文件名} | 生成时间: {ISO日期}
|
||||
|
||||
## 1. 概览
|
||||
|
||||
- **原型文件**: {文件名}
|
||||
- **截图**: screenshots/full.png
|
||||
- **设计 Token 数**: {matched数}/{总Token数} 已匹配
|
||||
- **组件数**: {组件总数}
|
||||
- **交互行为数**: {交互总数}
|
||||
|
||||
## 2. 设计 Token
|
||||
|
||||
### 2.1 颜色
|
||||
|
||||
| Token 名称 | 值 | 使用位置 |
|
||||
|------------|-----|---------|
|
||||
| ... | ... | ... |
|
||||
|
||||
### 2.2 字号
|
||||
|
||||
| Token 名称 | 值 (px) | 使用位置 |
|
||||
|------------|---------|---------|
|
||||
| ... | ... | ... |
|
||||
|
||||
### 2.3 间距
|
||||
|
||||
| Token 名称 | 值 (px) | 使用位置 |
|
||||
|------------|---------|---------|
|
||||
| ... | ... | ... |
|
||||
|
||||
### 2.4 圆角
|
||||
|
||||
| Token 名称 | 值 (px) | 使用位置 |
|
||||
|------------|---------|---------|
|
||||
| ... | ... | ... |
|
||||
|
||||
## 3. 组件清单
|
||||
|
||||
### 3.1 组件树
|
||||
|
||||
{组件层级树形结构}
|
||||
|
||||
### 3.2 组件详情
|
||||
|
||||
#### {组件名}
|
||||
|
||||
- **推断规则**: 命中规则 #{N}
|
||||
- **Token 依赖**: [列出使用的 Token]
|
||||
- **子组件**: [列出子组件]
|
||||
- **截图**: screenshots/sections/{组件名}.png(如有)
|
||||
- **样式属性**:
|
||||
```
|
||||
{原始 CSS 属性键值对}
|
||||
```
|
||||
|
||||
## 4. 交互行为
|
||||
|
||||
| 元素 | 事件类型 | 行为描述 | 实现建议 |
|
||||
|------|---------|---------|---------|
|
||||
| ... | click/scroll/input/transition | ... | ... |
|
||||
|
||||
## 5. 未匹配项
|
||||
|
||||
### 5.1 未匹配 Token
|
||||
|
||||
| 值 | 类型 | 出现位置 | 建议 Token 名称 |
|
||||
|----|------|---------|---------------|
|
||||
| ... | color/fontSize/spacing/radius | ... | ... |
|
||||
|
||||
### 5.2 需新建组件
|
||||
|
||||
| 组件名建议 | 视觉特征摘要 | 出现位置 |
|
||||
|-----------|------------|---------|
|
||||
| ... | ... | ... |
|
||||
|
||||
## 6. 实施注意事项
|
||||
|
||||
{LLM 根据原型复杂度自动生成的实现提示}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 输出流程
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
docs/design/{原型名}/
|
||||
SPEC.md # 设计规格文档(Step 6 产物)
|
||||
tokens.json # Token 匹配结果(Step 3 产物)
|
||||
META.yml # 元数据
|
||||
screenshots/
|
||||
full.png # 整页截图(Step 2 产物)
|
||||
sections/ # 局部截图(可选)
|
||||
```
|
||||
|
||||
### META.yml 格式
|
||||
|
||||
```yaml
|
||||
prototype: {原型文件名}
|
||||
source: {HTML文件绝对路径}
|
||||
generated_at: {ISO 8601 时间戳}
|
||||
tokens:
|
||||
matched: {数}
|
||||
unmatched: {数}
|
||||
pending: {数}
|
||||
components:
|
||||
total: {数}
|
||||
mapped: {数}
|
||||
new: {数}
|
||||
interactions: {数}
|
||||
```
|
||||
|
||||
### 终端输出
|
||||
|
||||
完成全部步骤后,在终端输出实施 Prompt 模板:
|
||||
|
||||
```
|
||||
============================================================
|
||||
设计交付完成: {原型名}
|
||||
输出目录: docs/design/{原型名}/
|
||||
============================================================
|
||||
|
||||
下一步:在新会话中粘贴以下 Prompt 实现设计
|
||||
|
||||
--- BEGIN PROMPT ---
|
||||
请根据设计规格实现 {原型名称} 页面。
|
||||
|
||||
设计规格文件: docs/design/{原型名}/SPEC.md
|
||||
截图参考: docs/design/{原型名}/screenshots/full.png
|
||||
Token 文件: docs/design/{原型名}/tokens.json
|
||||
|
||||
实现要求:
|
||||
1. 严格按照 SPEC.md 中的 Token 值设置样式
|
||||
2. 使用 SPEC.md 中映射的组件,若标记为"需新建"则先创建组件
|
||||
3. 实现所有交互行为(见 SPEC.md 第 4 节)
|
||||
4. 未匹配的 Token 需确认后补充到 .design/tokens.yml
|
||||
--- END PROMPT ---
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 批处理模式
|
||||
|
||||
当输入为 glob 模式(如 `docs/design/*.html`)或多个文件路径时:
|
||||
|
||||
1. 展开为文件列表
|
||||
2. 逐个执行 6 步流程(串行,避免截图冲突)
|
||||
3. 每个文件输出到 `docs/design/{各自原型名}/`
|
||||
4. 全部完成后生成索引文件:
|
||||
|
||||
### docs/design/INDEX.md
|
||||
|
||||
```markdown
|
||||
# 设计交付索引
|
||||
|
||||
> 自动生成于 {ISO 日期}
|
||||
|
||||
| # | 原型名 | 截图 | SPEC | Token 匹配率 | 组件数 | 状态 |
|
||||
|---|--------|------|------|------------|--------|------|
|
||||
| 1 | {名称} | [截图](./{名称}/screenshots/full.png) | [SPEC](./{名称}/SPEC.md) | {N}/{M} | {数} | 待实施 |
|
||||
| 2 | ... | ... | ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 待确认项交互
|
||||
|
||||
完成 6 步流程后,若有 `pending` 或 `unmatched` Token,需与用户交互确认:
|
||||
|
||||
### 输出确认清单
|
||||
|
||||
```
|
||||
[design-handoff] 以下 Token 需要确认:
|
||||
|
||||
【待确认 (pending)】
|
||||
1. 值 "#2b85e4" ≈ color.primary (#1890ff) — 是否作为别名?
|
||||
2. 值 15px ≈ spacing.lg (24px) — 是否新增 Token spacing.md_lg?
|
||||
|
||||
【未匹配 (unmatched)】
|
||||
3. 值 "#722ed1" — 建议新增 Token: color.accent_purple
|
||||
4. 值 10px — 建议新增 Token: spacing.ms
|
||||
|
||||
请回复序号+确认结果(如 "1:是, 2:新增, 3:color.purple, 4:忽略")
|
||||
```
|
||||
|
||||
### 处理用户确认
|
||||
|
||||
用户确认后:
|
||||
1. 将 `pending` 项的别名关系写入 `.design/tokens.yml` 的 `aliases` 字段
|
||||
2. 将 `unmatched` 项中确认新增的 Token 写入 `.design/tokens.yml` 对应分类
|
||||
3. 更新 `tokens.json` 和 `SPEC.md` 中的匹配状态
|
||||
|
||||
### aliases 格式示例
|
||||
|
||||
```yaml
|
||||
# .design/tokens.yml
|
||||
color:
|
||||
primary: "#1890ff"
|
||||
aliases:
|
||||
blue_hover: "#2b85e4" # 用户确认: primary 的 hover 态别名
|
||||
accent_purple: "#722ed1" # 用户确认: 新增 accent 色值
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 脚本说明
|
||||
|
||||
本 Skill 引用以下脚本(位于 `scripts/` 目录):
|
||||
|
||||
| 脚本 | 用途 | 输入 | 输出 |
|
||||
|------|------|------|------|
|
||||
| `parse-prototype.mjs` | 解析 HTML 原型为结构化 JSON | HTML 文件路径 | JSON DOM 树 |
|
||||
| `extract-screenshots.mjs` | 使用 Puppeteer/Playwright 截图 | HTML 文件路径 + 输出目录 | PNG 截图文件 |
|
||||
| `match-tokens.mjs` | 样式值与 Token 库匹配 | 解析 JSON + tokens.yml | 匹配报告 JSON |
|
||||
| `infer-interactions.mjs` | 推断交互行为 | 解析 JSON | 交互清单 JSON |
|
||||
|
||||
**降级策略:** 每个脚本缺失时,LLM 自行执行对应步骤(详见各 Step 说明)。脚本仅为加速工具,不影响核心功能。
|
||||
|
||||
## 模板说明
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| `templates/spec-template.md` | SPEC.md 的自定义模板(可选) |
|
||||
| `defaults/tokens.yml` | Token 初始定义(新项目首次使用时复制到 `.design/`) |
|
||||
| `defaults/components.yml` | 组件映射规则的自定义扩展(可选,覆盖内置 8 条规则) |
|
||||
|
||||
## 规则文件
|
||||
|
||||
`rules/` 目录可放置额外的设计规范约束文件(如品牌色限制、无障碍要求等),在 Step 4 组件推断和 Step 6 组装 SPEC 时自动加载。
|
||||
139
.claude/skills/design-handoff/defaults/components.yml
Normal file
139
.claude/skills/design-handoff/defaults/components.yml
Normal file
@@ -0,0 +1,139 @@
|
||||
version: 1
|
||||
updated: "2026-05-17"
|
||||
|
||||
# ============================================================================
|
||||
# 小程序 UI 组件映射注册表
|
||||
# 数据源: apps/miniprogram/src/components/ui/
|
||||
# 每个组件记录 import 路径和实际 props(从源码接口定义提取)
|
||||
# ============================================================================
|
||||
|
||||
components:
|
||||
# --- 数据展示 ---
|
||||
ContentCard:
|
||||
miniprogram:
|
||||
import: "@components/ui/ContentCard"
|
||||
props: "variant('default'|'outlined'|'elevated'), padding('none'|'sm'|'md'|'lg'), margin('none'|'md'), activeFeedback('bg'|'opacity'|'scale'|'none'), onPress, className, style, children"
|
||||
notes: "通用卡片容器,padding 映射到 --tk-card-padding-* token"
|
||||
|
||||
AlertCard:
|
||||
miniprogram:
|
||||
import: "@components/ui/AlertCard"
|
||||
props: "variant('gradient'|'left-border'|'bordered'), title, subtitle, children, className"
|
||||
notes: "告警/提示卡片,默认 left-border 变体"
|
||||
|
||||
VitalCard:
|
||||
miniprogram:
|
||||
import: "@components/ui/VitalCard"
|
||||
props: "label, value, unit, status, onPress, className"
|
||||
notes: "体征数据卡片,内嵌 StatusTag 显示状态"
|
||||
|
||||
ListItem:
|
||||
miniprogram:
|
||||
import: "@components/ui/ListItem"
|
||||
props: "title, subtitle, extra(ReactNode), leftIcon(ReactNode), onPress, showArrow, unread, className"
|
||||
notes: "列表行组件,支持图标/箭头/未读标记"
|
||||
|
||||
InfoRow:
|
||||
miniprogram:
|
||||
import: "@components/ui/InfoRow"
|
||||
props: "label, value, valueNode(ReactNode), last, className"
|
||||
notes: "键值对信息行,last 控制底部分隔线"
|
||||
|
||||
ChatBubble:
|
||||
miniprogram:
|
||||
import: "@components/ui/ChatBubble"
|
||||
props: "content, isMine, time, className"
|
||||
notes: "聊天气泡,isMine 控制左右侧和配色"
|
||||
|
||||
# --- 导航与标题 ---
|
||||
SectionTitle:
|
||||
miniprogram:
|
||||
import: "@components/ui/SectionTitle"
|
||||
props: "title, subtitle, action({text, onPress}), icon(ReactNode)"
|
||||
notes: "区块标题,左侧竖线装饰 + 可选右侧操作链接"
|
||||
|
||||
TabFilter:
|
||||
miniprogram:
|
||||
import: "@components/ui/TabFilter"
|
||||
props: "tabs(string[]), activeIndex, onChange(index), variant('fill'|'pill'|'segment'), className"
|
||||
notes: "标签页筛选器,三种视觉变体"
|
||||
|
||||
GradientHeader:
|
||||
miniprogram:
|
||||
import: "@components/ui/GradientHeader"
|
||||
props: "children, className"
|
||||
notes: "渐变头部容器,承载页面顶部标题区域"
|
||||
|
||||
# --- 输入控件 ---
|
||||
FormInput:
|
||||
miniprogram:
|
||||
import: "@components/ui/FormInput"
|
||||
props: "label, placeholder, value, onInput(value), type('text'|'number'|'idcard'|'digit'), maxLength, disabled, error, className"
|
||||
notes: "表单输入框,支持错误提示和多种输入类型"
|
||||
|
||||
# --- 按钮 ---
|
||||
PrimaryButton:
|
||||
miniprogram:
|
||||
import: "@components/ui/PrimaryButton"
|
||||
props: "children, onClick, disabled, loading, size('default'|'large'), className"
|
||||
notes: "主色按钮,高度映射 --tk-btn-primary-h"
|
||||
|
||||
SecondaryButton:
|
||||
miniprogram:
|
||||
import: "@components/ui/SecondaryButton"
|
||||
props: "children, onClick, disabled, className"
|
||||
notes: "次要/描边按钮,与 PrimaryButton 配套使用"
|
||||
|
||||
# --- 状态指示 ---
|
||||
StatusTag:
|
||||
miniprogram:
|
||||
import: "@components/ui/StatusTag"
|
||||
props: "status, colorMap(Record<string, TagColor>), size('sm'|'md'), className, children"
|
||||
notes: "状态标签,内置 status→color 映射(success/warning/error/info/default)"
|
||||
|
||||
ProgressRing:
|
||||
miniprogram:
|
||||
import: "@components/ui/ProgressRing"
|
||||
props: "progress(0-1), size('sm'|'lg'), label, className"
|
||||
notes: "环形进度条,使用 conic-gradient + --tk-pri 色"
|
||||
|
||||
LoadingCard:
|
||||
miniprogram:
|
||||
import: "@components/ui/LoadingCard"
|
||||
props: "count, layout('card'|'list'|'detail')"
|
||||
notes: "骨架屏加载占位,三种布局形态"
|
||||
|
||||
PageShell:
|
||||
miniprogram:
|
||||
import: "@components/ui/PageShell"
|
||||
props: "padding('none'|'sm'|'md'|'lg'), safeBottom, scroll, className, children"
|
||||
notes: "页面外壳,统一页面内边距和底部安全区,scroll 控制是否 ScrollView 包裹"
|
||||
|
||||
# ============================================================================
|
||||
# 框架/平台组件(非自研,Taro/微信原生)
|
||||
# ============================================================================
|
||||
framework_components:
|
||||
Swiper:
|
||||
import: "@tarojs/components"
|
||||
props: "autoplay, interval, duration, circular, indicatorDots, indicatorColor, indicatorActiveColor, onChange, children"
|
||||
notes: "Taro Swiper 组件,用于轮播图场景"
|
||||
|
||||
TabBar:
|
||||
import: "framework-config"
|
||||
props: "N/A(app.config.ts 中声明 tabBar 配置)"
|
||||
notes: "微信小程序原生 TabBar,在 app.config.ts 的 tabBar 字段配置"
|
||||
|
||||
ScrollView:
|
||||
import: "@tarojs/components"
|
||||
props: "scrollY, scrollX, scrollTop, onScroll, onScrollToLower, onScrollToUpper, children"
|
||||
notes: "Taro ScrollView,PageShell 内部使用"
|
||||
|
||||
Input:
|
||||
import: "@tarojs/components"
|
||||
props: "value, placeholder, type, maxlength, disabled, onInput, onFocus, onBlur"
|
||||
notes: "Taro Input,FormInput 内部使用"
|
||||
|
||||
Picker:
|
||||
import: "@tarojs/components"
|
||||
props: "mode('date'|'time'|'selector'), value, range, onChange, children"
|
||||
notes: "Taro Picker,用于日期/时间/选项选择"
|
||||
406
.claude/skills/design-handoff/defaults/tokens.yml
Normal file
406
.claude/skills/design-handoff/defaults/tokens.yml
Normal file
@@ -0,0 +1,406 @@
|
||||
version: 1
|
||||
updated: "2026-05-17"
|
||||
|
||||
# ============================================================================
|
||||
# Design Token 注册表
|
||||
# 数据源: apps/miniprogram/src/styles/tokens.scss + variables.scss
|
||||
# ============================================================================
|
||||
|
||||
colors:
|
||||
# --- 主色系(赤土橙) ---
|
||||
- token: --tk-pri
|
||||
value: "#C4623A"
|
||||
scss_var: "$pri"
|
||||
role: 主色/赤土橙 accent
|
||||
|
||||
- token: --tk-pri-l
|
||||
value: "#F0DDD4"
|
||||
scss_var: "$pri-l"
|
||||
role: 主色浅/赤土浅
|
||||
|
||||
- token: --tk-pri-d
|
||||
value: "#8B3E1F"
|
||||
scss_var: "$pri-d"
|
||||
role: 主色深/赤土深
|
||||
|
||||
# --- 阴影色(含透明度) ---
|
||||
- token: --tk-shadow-btn
|
||||
value: "0 4px 16px rgba(196, 98, 58, 0.3)"
|
||||
scss_var: "$shadow-btn"
|
||||
role: 主按钮阴影
|
||||
|
||||
- token: --tk-shadow-tab
|
||||
value: "0 2px 8px rgba(196, 98, 58, 0.25)"
|
||||
scss_var: "$shadow-tab"
|
||||
role: 选中Tab阴影
|
||||
|
||||
# --- 文字色 ---
|
||||
- token: --tk-text-secondary
|
||||
value: "#78716C"
|
||||
scss_var: "$tx3"
|
||||
role: 淡文字/辅助文字
|
||||
|
||||
# --- 卡片背景 ---
|
||||
- token: --tk-card-bg
|
||||
value: "#FFFFFF"
|
||||
scss_var: "$card"
|
||||
role: 卡片白底
|
||||
|
||||
# --- 医生端覆盖色(.doctor-mode 下自动替换 --tk-pri*) ---
|
||||
- token: --tk-pri.doctor
|
||||
value: "#3A6B8C"
|
||||
scss_var: "$doc-pri"
|
||||
role: 医生端主色/靛蓝
|
||||
note: 仅在 .doctor-mode 下覆盖 --tk-pri
|
||||
|
||||
- token: --tk-pri-l.doctor
|
||||
value: "#D4E5F0"
|
||||
scss_var: "$doc-pri-l"
|
||||
role: 医生端浅色
|
||||
|
||||
- token: --tk-pri-d.doctor
|
||||
value: "#2A4F6A"
|
||||
scss_var: "$doc-pri-d"
|
||||
role: 医生端深色
|
||||
|
||||
# --- 未映射到 Token 的 SCSS 变量(原型中有但 tokens.scss 未声明为 CSS 变量) ---
|
||||
unmapped_scss_variables:
|
||||
- scss_var: "$bg"
|
||||
value: "#F5F0EB"
|
||||
role: 页面主背景/温润米底
|
||||
note: "原型 T.bg 映射目标,tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
- scss_var: "$tx"
|
||||
value: "#2D2A26"
|
||||
role: 主文字色/暖黑
|
||||
note: "原型 T.tx 映射目标,tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
- scss_var: "$tx2"
|
||||
value: "#5A554F"
|
||||
role: 次文字色/暖灰
|
||||
note: "原型 T.tx2 近似映射,elder-mode 下 --tk-text-secondary 覆盖为此值"
|
||||
|
||||
- scss_var: "$bd"
|
||||
value: "#E8E2DC"
|
||||
role: 边框色
|
||||
note: "原型 T.bd 映射目标,tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
- scss_var: "$bd-l"
|
||||
value: "#F0EBE5"
|
||||
role: 浅边框色
|
||||
|
||||
- scss_var: "$acc"
|
||||
value: "#5B7A5E"
|
||||
role: 鼠尾草绿/成功色
|
||||
note: "原型中成功色,tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
- scss_var: "$acc-l"
|
||||
value: "#E8F0E8"
|
||||
role: 成功浅色
|
||||
|
||||
- scss_var: "$dan"
|
||||
value: "#B54A4A"
|
||||
role: 危险色/柔红
|
||||
note: "原型中危险色,tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
- scss_var: "$dan-l"
|
||||
value: "#FDEAEA"
|
||||
role: 危险浅色
|
||||
|
||||
- scss_var: "$wrn"
|
||||
value: "#C4873A"
|
||||
role: 警告色/暖琥珀
|
||||
note: "原型中警告色,tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
- scss_var: "$wrn-l"
|
||||
value: "#FFF3E0"
|
||||
role: 警告浅色
|
||||
|
||||
- scss_var: "$surface-alt"
|
||||
value: "#EDE8E2"
|
||||
role: 辅助底色
|
||||
|
||||
- scss_var: "$wechat"
|
||||
value: "#07C160"
|
||||
role: 微信绿
|
||||
|
||||
typography:
|
||||
- token: --tk-font-display
|
||||
value: "72px"
|
||||
note: 大屏展示
|
||||
elder: "80px"
|
||||
|
||||
- token: --tk-font-hero
|
||||
value: "48px"
|
||||
note: 启动页标题
|
||||
elder: "56px"
|
||||
|
||||
- token: --tk-font-h1
|
||||
value: "28px"
|
||||
note: 页面标题 serif bold
|
||||
elder: "32px"
|
||||
|
||||
- token: --tk-font-h2
|
||||
value: "22px"
|
||||
note: 副标题、用户名 serif bold
|
||||
elder: "25px"
|
||||
|
||||
- token: --tk-font-body-lg
|
||||
value: "18px"
|
||||
note: 按钮文字、section 标题 fontWeight:600
|
||||
elder: "22px"
|
||||
|
||||
- token: --tk-font-body
|
||||
value: "16px"
|
||||
note: 正文、输入框、icon 文字(最常用 UI 字号)
|
||||
elder: "22px"
|
||||
|
||||
- token: --tk-font-body-sm
|
||||
value: "14px"
|
||||
note: 副文本、描述
|
||||
elder: "19px"
|
||||
|
||||
- token: --tk-font-num
|
||||
value: "30px"
|
||||
note: 数值 serif bold
|
||||
elder: "34px"
|
||||
|
||||
- token: --tk-font-num-lg
|
||||
value: "34px"
|
||||
note: 大数值
|
||||
elder: "40px"
|
||||
|
||||
- token: --tk-font-cap
|
||||
value: "13px"
|
||||
note: 说明文字(第一高频字号)
|
||||
elder: "18px"
|
||||
|
||||
- token: --tk-font-nav
|
||||
value: "18px"
|
||||
note: 导航栏标题 serif bold
|
||||
elder: "22px"
|
||||
|
||||
- token: --tk-font-micro
|
||||
value: "11px"
|
||||
note: 角标、tag
|
||||
elder: "17px"
|
||||
|
||||
structure:
|
||||
- token: --tk-line-height
|
||||
value: "1.5"
|
||||
elder: "1.7"
|
||||
|
||||
spacing:
|
||||
- token: --tk-gap-2xs
|
||||
value: "4px"
|
||||
scss_var: "$sp-2xs"
|
||||
elder: "6px"
|
||||
|
||||
- token: --tk-gap-xs
|
||||
value: "8px"
|
||||
scss_var: "$sp-xs"
|
||||
elder: "12px"
|
||||
|
||||
- token: --tk-gap-sm
|
||||
value: "12px"
|
||||
scss_var: "$sp-sm"
|
||||
elder: "16px"
|
||||
|
||||
- token: --tk-gap-md
|
||||
value: "16px"
|
||||
scss_var: "$sp-md"
|
||||
elder: "20px"
|
||||
|
||||
- token: --tk-section-gap
|
||||
value: "20px"
|
||||
scss_var: "$sp-section"
|
||||
elder: "28px"
|
||||
|
||||
- token: --tk-gap-lg
|
||||
value: "24px"
|
||||
scss_var: "$sp-lg"
|
||||
elder: "32px"
|
||||
|
||||
- token: --tk-gap-xl
|
||||
value: "32px"
|
||||
scss_var: "$sp-xl"
|
||||
elder: "40px"
|
||||
|
||||
- token: --tk-gap-2xl
|
||||
value: "48px"
|
||||
scss_var: "$sp-2xl"
|
||||
elder: "56px"
|
||||
|
||||
- token: --tk-page-padding
|
||||
value: "20px"
|
||||
elder: "28px"
|
||||
|
||||
- token: --tk-card-padding
|
||||
value: "20px"
|
||||
elder: "28px"
|
||||
|
||||
- token: --tk-card-padding-sm
|
||||
value: "16px"
|
||||
elder: "20px"
|
||||
|
||||
- token: --tk-card-padding-lg
|
||||
value: "28px"
|
||||
elder: "36px"
|
||||
|
||||
radius:
|
||||
- token: --tk-card-radius
|
||||
value: "16px"
|
||||
scss_var: "$r"
|
||||
elder: "20px"
|
||||
|
||||
# SCSS 变量中有但 tokens.scss 未声明为 CSS 变量的圆角
|
||||
unmapped:
|
||||
- scss_var: "$r-sm"
|
||||
value: "12px"
|
||||
note: "原型 T.rSm 映射目标"
|
||||
- scss_var: "$r-xs"
|
||||
value: "8px"
|
||||
note: "原型 T.rXs 映射目标"
|
||||
- scss_var: "$r-lg"
|
||||
value: "20px"
|
||||
- scss_var: "$r-pill"
|
||||
value: "999px"
|
||||
|
||||
sizing:
|
||||
- token: --tk-touch-min
|
||||
value: "48px"
|
||||
role: 最小触控区
|
||||
elder: "56px"
|
||||
|
||||
- token: --tk-btn-primary-h
|
||||
value: "52px"
|
||||
role: 主按钮高度
|
||||
elder: "60px"
|
||||
|
||||
- token: --tk-input-height
|
||||
value: "56px"
|
||||
role: 输入框高度
|
||||
elder: "64px"
|
||||
|
||||
- token: --tk-tabbar-space
|
||||
value: "100px"
|
||||
role: TabBar 底部安全区
|
||||
elder: "120px"
|
||||
|
||||
feedback:
|
||||
- token: --tk-touch-feedback-opacity
|
||||
value: "0.85"
|
||||
role: 触控反馈透明度
|
||||
elder: "0.8"
|
||||
|
||||
tag:
|
||||
- token: --tk-tag-font-size
|
||||
value: "11px"
|
||||
elder: "13px"
|
||||
|
||||
- token: --tk-tag-padding-v
|
||||
value: "3px"
|
||||
elder: "5px"
|
||||
|
||||
- token: --tk-tag-padding-h
|
||||
value: "8px"
|
||||
elder: "12px"
|
||||
|
||||
shadow_unmapped:
|
||||
# tokens.scss 中的 --tk-shadow-btn/tab 是复合值(含偏移+模糊+颜色)
|
||||
# 以下为 variables.scss 中的其他阴影,未声明为 CSS Token
|
||||
- scss_var: "$shadow-sm"
|
||||
value: "0 1px 4px rgba(45, 42, 38, 0.06)"
|
||||
role: 小阴影
|
||||
|
||||
- scss_var: "$shadow-md"
|
||||
value: "0 2px 12px rgba(45, 42, 38, 0.10)"
|
||||
role: 中阴影
|
||||
|
||||
- scss_var: "$shadow-lg"
|
||||
value: "0 8px 32px rgba(45, 42, 38, 0.15)"
|
||||
role: 大阴影
|
||||
|
||||
# ============================================================================
|
||||
# 原型 Key → Token 映射(aliases)
|
||||
# 用于设计移交时自动匹配原型属性到实际 Token
|
||||
# ============================================================================
|
||||
aliases:
|
||||
prototype_keys:
|
||||
T.pri:
|
||||
token: --tk-pri
|
||||
status: exact_match
|
||||
|
||||
T.priL:
|
||||
token: --tk-pri-l
|
||||
status: exact_match
|
||||
|
||||
T.priD:
|
||||
token: --tk-pri-d
|
||||
status: exact_match
|
||||
|
||||
T.bg:
|
||||
token: null
|
||||
nearest: --tk-card-bg
|
||||
scss_var: "$bg"
|
||||
value: "#F5F0EB"
|
||||
status: unmatched
|
||||
note: "原型页面背景色,tokens.scss 未声明为 CSS 变量,直接用 $bg SCSS 变量"
|
||||
|
||||
T.card:
|
||||
token: --tk-card-bg
|
||||
status: exact_match
|
||||
|
||||
T.surface:
|
||||
token: --tk-card-bg
|
||||
status: approximate
|
||||
note: "原型中 surface ≈ 卡片白底"
|
||||
|
||||
T.tx:
|
||||
token: null
|
||||
nearest: --tk-text-secondary
|
||||
scss_var: "$tx"
|
||||
value: "#2D2A26"
|
||||
status: unmatched
|
||||
note: "主文字色,tokens.scss 未声明为 CSS 变量,直接用 $tx SCSS 变量"
|
||||
|
||||
T.tx2:
|
||||
token: null
|
||||
nearest: --tk-text-secondary
|
||||
scss_var: "$tx2"
|
||||
value: "#5A554F"
|
||||
status: unmatched
|
||||
note: "次文字色,tokens.scss 未声明,elder-mode 下 --tk-text-secondary 覆盖为此值"
|
||||
|
||||
T.tx3:
|
||||
token: --tk-text-secondary
|
||||
scss_var: "$tx3"
|
||||
value: "#78716C"
|
||||
status: exact_match
|
||||
|
||||
T.bd:
|
||||
token: null
|
||||
scss_var: "$bd"
|
||||
value: "#E8E2DC"
|
||||
status: unmatched
|
||||
note: "边框色(不是圆角),tokens.scss 未声明为 CSS 变量"
|
||||
|
||||
T.r:
|
||||
token: --tk-card-radius
|
||||
scss_var: "$r"
|
||||
value: "16px"
|
||||
status: exact_match
|
||||
|
||||
T.rSm:
|
||||
token: null
|
||||
scss_var: "$r-sm"
|
||||
value: "12px"
|
||||
status: unmatched
|
||||
note: "tokens.scss 未声明,需添加 --tk-radius-sm 或直接用 $r-sm SCSS 变量"
|
||||
|
||||
T.rXs:
|
||||
token: null
|
||||
scss_var: "$r-xs"
|
||||
value: "8px"
|
||||
status: unmatched
|
||||
note: "tokens.scss 未声明,需添加 --tk-radius-xs 或直接用 $r-xs SCSS 变量"
|
||||
34
.claude/skills/design-handoff/package-lock.json
generated
Normal file
34
.claude/skills/design-handoff/package-lock.json
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "design-handoff",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "design-handoff",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"js-yaml": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
.claude/skills/design-handoff/package.json
Normal file
16
.claude/skills/design-handoff/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "design-handoff",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"js-yaml": "^4.1.1"
|
||||
}
|
||||
}
|
||||
144
.claude/skills/design-handoff/rules/interaction-rules.yml
Normal file
144
.claude/skills/design-handoff/rules/interaction-rules.yml
Normal file
@@ -0,0 +1,144 @@
|
||||
version: 1
|
||||
updated: "2026-05-17"
|
||||
|
||||
# ============================================================================
|
||||
# 交互推断规则
|
||||
# 用于从静态原型 HTML 自动推断交互行为
|
||||
# 每条规则: id / name / patterns(匹配模式) / infer(推断结果) / confidence
|
||||
# ============================================================================
|
||||
|
||||
rules:
|
||||
- id: swiper-autoplay
|
||||
name: "自动轮播 + 手动滑动"
|
||||
patterns:
|
||||
- "渐变背景容器内含多张图片/卡片"
|
||||
- "底部指示点宽窄交替(当前页宽、其他窄)"
|
||||
- "容器设置了 overflow:hidden 且子元素横向排列"
|
||||
- "存在 swiper / carousel / banner 类名"
|
||||
infer:
|
||||
interaction: swiper
|
||||
trigger:
|
||||
- "自动播放(interval 3000-5000ms)"
|
||||
- "手势滑动切换"
|
||||
feedback:
|
||||
- "指示点跟随切换高亮"
|
||||
- "平滑过渡动画(cubic-bezier)"
|
||||
confidence: high
|
||||
|
||||
- id: card-tap
|
||||
name: "卡片点击跳转"
|
||||
patterns:
|
||||
- "卡片容器(ContentCard/圆角矩形)内含标题 + 摘要 + 配图"
|
||||
- "卡片有 hover/active 视觉反馈样式"
|
||||
- "卡片内无独立按钮,整体可点击"
|
||||
- "存在 card / item 等语义类名"
|
||||
infer:
|
||||
interaction: navigate
|
||||
trigger:
|
||||
- "点击整个卡片区域"
|
||||
feedback:
|
||||
- "按下时背景色变化或缩放反馈(--tk-touch-feedback-opacity)"
|
||||
- "跳转到详情页"
|
||||
confidence: high
|
||||
|
||||
- id: form-submit
|
||||
name: "表单提交"
|
||||
patterns:
|
||||
- "输入框(input/textarea)与按钮在同一个 form 容器内"
|
||||
- "按钮文案为"提交"/"确认"/"保存"等动作词"
|
||||
- "输入框有 label + placeholder 配对"
|
||||
- "存在 form / input-group 等语义结构"
|
||||
infer:
|
||||
interaction: form_submit
|
||||
trigger:
|
||||
- "点击提交按钮"
|
||||
- "输入框回车(单输入场景)"
|
||||
feedback:
|
||||
- "按钮 loading 状态"
|
||||
- "成功后 toast 提示或页面跳转"
|
||||
- "失败时输入框下方显示 error 信息"
|
||||
confidence: high
|
||||
|
||||
- id: list-scroll
|
||||
name: "下拉刷新 + 上拉加载"
|
||||
patterns:
|
||||
- "3+ 同类卡片连续纵向排列"
|
||||
- "容器设置了 overflow-y:scroll 或使用 ScrollView"
|
||||
- "列表底部有 loading 骨架屏占位"
|
||||
- "列表顶部有刷新指示区域"
|
||||
- "存在 list / scroll-view 等语义结构"
|
||||
infer:
|
||||
interaction: infinite_scroll
|
||||
trigger:
|
||||
- "下拉刷新(距顶部 < threshold)"
|
||||
- "上拉加载(距底部 < threshold)"
|
||||
feedback:
|
||||
- "下拉时显示刷新指示器"
|
||||
- "加载时底部显示 LoadingCard"
|
||||
- "无更多数据时显示"没有更多了"提示"
|
||||
confidence: medium
|
||||
|
||||
- id: tab-switch
|
||||
name: "标签页切换"
|
||||
patterns:
|
||||
- "平行区域以 tab 形式排列(2-5个选项)"
|
||||
- "选中态与未选中态有明显视觉差异(颜色/粗细/底色)"
|
||||
- "关键词包含 tab / filter / segment"
|
||||
- "切换后下方内容区域整体替换"
|
||||
infer:
|
||||
interaction: tab_switch
|
||||
trigger:
|
||||
- "点击 tab 项"
|
||||
- "滑动切换(segment 模式)"
|
||||
feedback:
|
||||
- "选中项高亮(主色底/加粗/底线)"
|
||||
- "内容区平滑切换或淡入淡出"
|
||||
- "选中 tab 阴影变化(--tk-shadow-tab)"
|
||||
confidence: high
|
||||
|
||||
- id: static-decoration
|
||||
name: "纯装饰无交互"
|
||||
patterns:
|
||||
- "元素仅有渐变背景 + 装饰性圆形/波浪"
|
||||
- "无 hover/active/click 事件绑定"
|
||||
- "opacity < 1 的背景装饰层"
|
||||
- "pointer-events: none"
|
||||
- "z-index 为负值或明确低于内容层"
|
||||
infer:
|
||||
interaction: none
|
||||
trigger: []
|
||||
feedback: []
|
||||
confidence: high
|
||||
|
||||
- id: login-cta
|
||||
name: "登录/注册触发"
|
||||
patterns:
|
||||
- "按钮文案包含"登录"/"注册"/"立即登录"/"微信登录""
|
||||
- "按钮使用主色(--tk-pri)背景"
|
||||
- "位于页面底部或居中位置"
|
||||
- "周围有辅助文案如"登录后查看更多""
|
||||
infer:
|
||||
interaction: auth_action
|
||||
trigger:
|
||||
- "点击按钮"
|
||||
feedback:
|
||||
- "微信登录:调起微信授权"
|
||||
- "账号密码登录:展开登录表单或跳转登录页"
|
||||
- "按钮 loading 状态防止重复点击"
|
||||
confidence: high
|
||||
|
||||
- id: empty-fallback
|
||||
name: "空数据降级"
|
||||
patterns:
|
||||
- "条件渲染(v-if/ng-if/三元表达式)控制内容区"
|
||||
- "占位文字如"暂无数据"/"还没有记录""
|
||||
- "空状态插图或图标(空盒子/空列表图标)"
|
||||
- "引导文案 + 操作按钮(如"去创建""去预约")"
|
||||
infer:
|
||||
interaction: empty_state
|
||||
trigger:
|
||||
- "数据加载完成且列表为空时自动展示"
|
||||
feedback:
|
||||
- "显示空状态插图 + 引导文案"
|
||||
- "可选的引导按钮(点击跳转创建页)"
|
||||
confidence: medium
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -72,4 +72,6 @@ tmp/
|
||||
screenshots/
|
||||
server-log.txt
|
||||
snapshot_*.txt
|
||||
uploads/
|
||||
uploads/g:/hms/.superpowers/
|
||||
.claude/skills/design-handoff/node_modules/
|
||||
.design/config.yml
|
||||
|
||||
Reference in New Issue
Block a user