@szc-ft/mcp-szcd-client 0.34.2 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/build.js +59 -1
- package/agents/platforms.json +7 -0
- package/agents/szcd-component-expert.qoder.md +2 -0
- package/opencode-extension/opencode.json +9 -0
- package/opencode-extension/skills/local-browser-test/SKILL.md +91 -0
- package/opencode-extension/skills/local-browser-test/config.example.yaml +51 -0
- package/opencode-extension/skills/local-browser-test/lib/api-call-executor.js +251 -0
- package/opencode-extension/skills/local-browser-test/lib/browser-engine.js +95 -21
- package/opencode-extension/skills/local-browser-test/lib/config-loader.js +104 -0
- package/opencode-extension/skills/local-browser-test/lib/console-archiver.js +100 -0
- package/opencode-extension/skills/local-browser-test/lib/global-setup.js +72 -0
- package/opencode-extension/skills/local-browser-test/lib/har-collector.js +124 -0
- package/opencode-extension/skills/local-browser-test/lib/html-reporter.js +248 -0
- package/opencode-extension/skills/local-browser-test/lib/projects.js +46 -0
- package/opencode-extension/skills/local-browser-test/lib/raw-script-helpers.js +93 -0
- package/opencode-extension/skills/local-browser-test/lib/redact.js +94 -0
- package/opencode-extension/skills/local-browser-test/lib/report-retain.js +84 -0
- package/opencode-extension/skills/local-browser-test/lib/retry-policy.js +160 -0
- package/opencode-extension/skills/local-browser-test/lib/storage-state.js +111 -0
- package/opencode-extension/skills/local-browser-test/lib/tag-runner.js +103 -0
- package/opencode-extension/skills/local-browser-test/lib/test-plan.js +2 -0
- package/opencode-extension/skills/local-browser-test/lib/trace-collector.js +94 -0
- package/opencode-extension/skills/local-browser-test/lib/trend-aggregator.js +97 -0
- package/opencode-extension/skills/local-browser-test/lib/workspace-init.js +178 -0
- package/opencode-extension/skills/local-browser-test/local-browser-executor.js +226 -2
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-01.test.js +254 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-02.test.js +263 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-03.test.js +308 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-04.test.js +168 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-05.test.js +183 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-06.test.js +252 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-07.test.js +168 -0
- package/opencode-extension/skills/local-browser-test/tests/integration/pr-08.test.js +293 -0
- package/opencode-extension/skills/shadcn-design-to-code/SKILL.md +352 -0
- package/opencode-extension/skills/shadcn-design-to-code/examples/1.1-overview-page.tsx +382 -0
- package/opencode-extension/skills/shadcn-design-to-code/references/install-pitfalls.md +526 -0
- package/opencode-extension/skills/shadcn-design-to-code/references/layouts.md +551 -0
- package/opencode-extension/skills/shadcn-design-to-code/references/sketch-mapping.md +247 -0
- package/opencode-extension/skills/shadcn-design-to-code/references/tokens.md +534 -0
- package/opencode-extension/skills/szcd-upload-zip/SKILL.md +45 -0
- package/package.json +70 -70
- package/qwen-extension/qwen-extension.json +10 -1
- package/qwen-extension/skills/local-browser-test/SKILL.md +91 -0
- package/qwen-extension/skills/local-browser-test/config.example.yaml +51 -0
- package/qwen-extension/skills/local-browser-test/lib/api-call-executor.js +251 -0
- package/qwen-extension/skills/local-browser-test/lib/browser-engine.js +95 -21
- package/qwen-extension/skills/local-browser-test/lib/config-loader.js +104 -0
- package/qwen-extension/skills/local-browser-test/lib/console-archiver.js +100 -0
- package/qwen-extension/skills/local-browser-test/lib/global-setup.js +72 -0
- package/qwen-extension/skills/local-browser-test/lib/har-collector.js +124 -0
- package/qwen-extension/skills/local-browser-test/lib/html-reporter.js +248 -0
- package/qwen-extension/skills/local-browser-test/lib/projects.js +46 -0
- package/qwen-extension/skills/local-browser-test/lib/raw-script-helpers.js +93 -0
- package/qwen-extension/skills/local-browser-test/lib/redact.js +94 -0
- package/qwen-extension/skills/local-browser-test/lib/report-retain.js +84 -0
- package/qwen-extension/skills/local-browser-test/lib/retry-policy.js +160 -0
- package/qwen-extension/skills/local-browser-test/lib/storage-state.js +111 -0
- package/qwen-extension/skills/local-browser-test/lib/tag-runner.js +103 -0
- package/qwen-extension/skills/local-browser-test/lib/test-plan.js +2 -0
- package/qwen-extension/skills/local-browser-test/lib/trace-collector.js +94 -0
- package/qwen-extension/skills/local-browser-test/lib/trend-aggregator.js +97 -0
- package/qwen-extension/skills/local-browser-test/lib/workspace-init.js +178 -0
- package/qwen-extension/skills/local-browser-test/local-browser-executor.js +226 -2
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-01.test.js +254 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-02.test.js +263 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-03.test.js +308 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-04.test.js +168 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-05.test.js +183 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-06.test.js +252 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-07.test.js +168 -0
- package/qwen-extension/skills/local-browser-test/tests/integration/pr-08.test.js +293 -0
- package/qwen-extension/skills/shadcn-design-to-code/SKILL.md +352 -0
- package/qwen-extension/skills/shadcn-design-to-code/examples/1.1-overview-page.tsx +382 -0
- package/qwen-extension/skills/shadcn-design-to-code/references/install-pitfalls.md +526 -0
- package/qwen-extension/skills/shadcn-design-to-code/references/layouts.md +551 -0
- package/qwen-extension/skills/shadcn-design-to-code/references/sketch-mapping.md +247 -0
- package/qwen-extension/skills/shadcn-design-to-code/references/tokens.md +534 -0
- package/qwen-extension/skills/szcd-upload-zip/SKILL.md +45 -0
- package/scripts/lib/common.js +8 -1
- package/standard-skill/local-browser-test/SKILL.md +91 -0
- package/standard-skill/local-browser-test/config.example.yaml +51 -0
- package/standard-skill/local-browser-test/lib/api-call-executor.js +251 -0
- package/standard-skill/local-browser-test/lib/browser-engine.js +95 -21
- package/standard-skill/local-browser-test/lib/config-loader.js +104 -0
- package/standard-skill/local-browser-test/lib/console-archiver.js +100 -0
- package/standard-skill/local-browser-test/lib/global-setup.js +72 -0
- package/standard-skill/local-browser-test/lib/har-collector.js +124 -0
- package/standard-skill/local-browser-test/lib/html-reporter.js +248 -0
- package/standard-skill/local-browser-test/lib/projects.js +46 -0
- package/standard-skill/local-browser-test/lib/raw-script-helpers.js +93 -0
- package/standard-skill/local-browser-test/lib/redact.js +94 -0
- package/standard-skill/local-browser-test/lib/report-retain.js +84 -0
- package/standard-skill/local-browser-test/lib/retry-policy.js +160 -0
- package/standard-skill/local-browser-test/lib/storage-state.js +111 -0
- package/standard-skill/local-browser-test/lib/tag-runner.js +103 -0
- package/standard-skill/local-browser-test/lib/test-plan.js +2 -0
- package/standard-skill/local-browser-test/lib/trace-collector.js +94 -0
- package/standard-skill/local-browser-test/lib/trend-aggregator.js +97 -0
- package/standard-skill/local-browser-test/lib/workspace-init.js +178 -0
- package/standard-skill/local-browser-test/local-browser-executor.js +226 -2
- package/standard-skill/local-browser-test/tests/integration/pr-01.test.js +254 -0
- package/standard-skill/local-browser-test/tests/integration/pr-02.test.js +263 -0
- package/standard-skill/local-browser-test/tests/integration/pr-03.test.js +308 -0
- package/standard-skill/local-browser-test/tests/integration/pr-04.test.js +168 -0
- package/standard-skill/local-browser-test/tests/integration/pr-05.test.js +183 -0
- package/standard-skill/local-browser-test/tests/integration/pr-06.test.js +252 -0
- package/standard-skill/local-browser-test/tests/integration/pr-07.test.js +168 -0
- package/standard-skill/local-browser-test/tests/integration/pr-08.test.js +293 -0
- package/standard-skill/shadcn-design-to-code/SKILL.md +352 -0
- package/standard-skill/shadcn-design-to-code/examples/1.1-overview-page.tsx +382 -0
- package/standard-skill/shadcn-design-to-code/references/install-pitfalls.md +526 -0
- package/standard-skill/shadcn-design-to-code/references/layouts.md +551 -0
- package/standard-skill/shadcn-design-to-code/references/sketch-mapping.md +247 -0
- package/standard-skill/shadcn-design-to-code/references/tokens.md +534 -0
- package/standard-skill/szcd-upload-zip/SKILL.md +45 -0
- package/opencode-extension/skills/local-browser-test/local-browser-executor.cjs +0 -742
- package/qwen-extension/skills/local-browser-test/local-browser-executor.cjs +0 -742
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
# shadcn 布局模式库
|
|
2
|
+
|
|
3
|
+
> 15 种常见设计稿布局模式 → Tailwind 落地代码片段
|
|
4
|
+
> 按"区块分布特征"反查,按 layouts 排序
|
|
5
|
+
|
|
6
|
+
## 推理流程
|
|
7
|
+
|
|
8
|
+
1. 看 .sketch 画板的 x 分布(大区分列)
|
|
9
|
+
2. 看 y 分布(大区内纵序)
|
|
10
|
+
3. 看主区内部的"卡片栅格"
|
|
11
|
+
4. 命中下面的 15 种之一 → 直接用对应 Tailwind 模板
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## L01: sidebar-main(侧边栏 + 主内容)
|
|
16
|
+
|
|
17
|
+
**Sketch 特征**:
|
|
18
|
+
- 左侧 200-280px 固定宽度,1 列深色/浅色导航,含 logo + 菜单项 + 底部用户
|
|
19
|
+
- 右侧剩余宽度,主内容上下排列
|
|
20
|
+
|
|
21
|
+
**典型场景**:SaaS 后台、Admin Panel、文档站
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
<div className="flex h-screen bg-background">
|
|
25
|
+
<aside className="w-64 border-r bg-slate-50 dark:bg-slate-900 flex flex-col">
|
|
26
|
+
<div className="h-16 border-b flex items-center px-6">{/* logo */}</div>
|
|
27
|
+
<nav className="flex-1 p-4 space-y-1">{/* 菜单项 */}</nav>
|
|
28
|
+
<div className="p-4 border-t">{/* user */}</div>
|
|
29
|
+
</aside>
|
|
30
|
+
<main className="flex-1 overflow-auto">
|
|
31
|
+
<div className="container mx-auto p-6 space-y-6">{/* 主内容 */}</div>
|
|
32
|
+
</main>
|
|
33
|
+
</div>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**shadcn 组件**:Sidebar (sidebar-07 block) + Sheet(移动端抽屉)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## L02: topbar-content(顶部栏 + 内容)
|
|
41
|
+
|
|
42
|
+
**Sketch 特征**:
|
|
43
|
+
- 顶部 56-64px 高度,含 logo + 水平导航 + 搜索 + 头像
|
|
44
|
+
- 下方全宽内容区
|
|
45
|
+
|
|
46
|
+
**典型场景**:营销页、文档首页
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<div className="min-h-screen bg-background">
|
|
50
|
+
<header className="sticky top-0 z-50 h-16 border-b bg-background/95 backdrop-blur">
|
|
51
|
+
<div className="container mx-auto h-full flex items-center justify-between px-4">
|
|
52
|
+
<div className="flex items-center gap-8">{/* logo + nav */}</div>
|
|
53
|
+
<div className="flex items-center gap-4">{/* 搜索 + 头像 */}</div>
|
|
54
|
+
</div>
|
|
55
|
+
</header>
|
|
56
|
+
<main className="container mx-auto px-4 py-8">{/* content */}</main>
|
|
57
|
+
</div>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**shadcn 组件**:NavigationMenu + Input + Avatar + Button
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## L03: dashboard-grid(多卡片仪表盘)
|
|
65
|
+
|
|
66
|
+
**Sketch 特征**:
|
|
67
|
+
- 顶部 4 个统计卡片(Stat)
|
|
68
|
+
- 中部 1-2 个大图表卡片
|
|
69
|
+
- 底部表格 + 活动 feed
|
|
70
|
+
|
|
71
|
+
**典型场景**:运营 Dashboard、监控大屏
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<div className="flex-1 space-y-6 p-6">
|
|
75
|
+
{/* 4 个 Stat 卡片 */}
|
|
76
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
77
|
+
{stats.map((s) => <StatCard key={s.title} {...s} />)}
|
|
78
|
+
</div>
|
|
79
|
+
{/* 2 个图表卡片 */}
|
|
80
|
+
<div className="grid grid-cols-1 gap-4 lg:grid-cols-7">
|
|
81
|
+
<Card className="lg:col-span-4"><ChartContainer config={chartConfig}>
|
|
82
|
+
<LineChart data={data} /></ChartContainer></Card>
|
|
83
|
+
<Card className="lg:col-span-3"><ChartContainer config={chartConfig2}>
|
|
84
|
+
<BarChart data={data2} /></ChartContainer></Card>
|
|
85
|
+
</div>
|
|
86
|
+
{/* 表格 + 活动 */}
|
|
87
|
+
<div className="grid grid-cols-1 gap-4 lg:grid-cols-7">
|
|
88
|
+
<Card className="lg:col-span-4">{/* 表格 */}</Card>
|
|
89
|
+
<Card className="lg:col-span-3">{/* 活动 feed */}</Card>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**shadcn 组件**:Card + Chart(基于 Recharts)+ Table + Avatar
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## L04: left-right(左内容 + 右详情)
|
|
99
|
+
|
|
100
|
+
**Sketch 特征**:
|
|
101
|
+
- 左侧 35-45% 宽,列表/卡片网格
|
|
102
|
+
- 右侧 55-65% 宽,单条详情/大图
|
|
103
|
+
- 移动端垂直堆叠
|
|
104
|
+
|
|
105
|
+
**典型场景**:邮件客户端、文件管理、电商详情
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
|
109
|
+
<div className="lg:col-span-1 space-y-2">
|
|
110
|
+
{items.map((item) => (
|
|
111
|
+
<Card key={item.id} className={cn("cursor-pointer", selected === item.id && "border-primary")}>
|
|
112
|
+
{/* item summary */}
|
|
113
|
+
</Card>
|
|
114
|
+
))}
|
|
115
|
+
</div>
|
|
116
|
+
<div className="lg:col-span-2">
|
|
117
|
+
<Card>{/* 详情 */}</Card>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**shadcn 组件**:Card + ScrollArea + Separator
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## L05: form-page(表单页)
|
|
127
|
+
|
|
128
|
+
**Sketch 特征**:
|
|
129
|
+
- 顶部标题 + 描述
|
|
130
|
+
- 居中卡片(max-width 800-1000px)
|
|
131
|
+
- 表单字段 1-2 列
|
|
132
|
+
- 底部固定操作栏(保存/取消)
|
|
133
|
+
|
|
134
|
+
**典型场景**:设置页、新建/编辑表单
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<div className="container max-w-3xl py-8 space-y-6">
|
|
138
|
+
<div>
|
|
139
|
+
<h1 className="text-2xl font-semibold">页面标题</h1>
|
|
140
|
+
<p className="text-muted-foreground">页面描述</p>
|
|
141
|
+
</div>
|
|
142
|
+
<Card>
|
|
143
|
+
<CardContent className="pt-6">
|
|
144
|
+
<Form {...form}>
|
|
145
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
|
146
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
147
|
+
<FormField control={form.control} name="name" render={({ field }) => (
|
|
148
|
+
<FormItem><FormLabel>名称</FormLabel>
|
|
149
|
+
<FormControl><Input {...field} /></FormControl>
|
|
150
|
+
<FormMessage />
|
|
151
|
+
</FormItem>
|
|
152
|
+
)} />
|
|
153
|
+
{/* 其他字段 */}
|
|
154
|
+
</div>
|
|
155
|
+
<div className="flex justify-end gap-2">
|
|
156
|
+
<Button type="button" variant="outline" onClick={onCancel}>取消</Button>
|
|
157
|
+
<Button type="submit">保存</Button>
|
|
158
|
+
</div>
|
|
159
|
+
</form>
|
|
160
|
+
</Form>
|
|
161
|
+
</CardContent>
|
|
162
|
+
</Card>
|
|
163
|
+
</div>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**shadcn 组件**:Form + Input + Select + Textarea + Checkbox + Button
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## L06: list-card-switch(列表/卡片切换)
|
|
171
|
+
|
|
172
|
+
**Sketch 特征**:
|
|
173
|
+
- 顶部筛选/搜索 + 切换按钮(grid / list)
|
|
174
|
+
- 下方卡片网格或列表
|
|
175
|
+
|
|
176
|
+
**典型场景**:商品列表、数据浏览
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
<div className="space-y-4">
|
|
180
|
+
<div className="flex items-center justify-between">
|
|
181
|
+
<div className="flex items-center gap-2">{/* 筛选 */}</div>
|
|
182
|
+
<div className="flex items-center gap-2">
|
|
183
|
+
<Button variant={view === 'grid' ? 'secondary' : 'ghost'} size="icon" onClick={() => setView('grid')}>
|
|
184
|
+
<LayoutGrid />
|
|
185
|
+
</Button>
|
|
186
|
+
<Button variant={view === 'list' ? 'secondary' : 'ghost'} size="icon" onClick={() => setView('list')}>
|
|
187
|
+
<List />
|
|
188
|
+
</Button>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
{view === 'grid' ? (
|
|
192
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
|
193
|
+
{items.map((item) => <ItemCard key={item.id} {...item} />)}
|
|
194
|
+
</div>
|
|
195
|
+
) : (
|
|
196
|
+
<div className="space-y-2">{items.map((item) => <ItemRow key={item.id} {...item} />)}</div>
|
|
197
|
+
)}
|
|
198
|
+
</div>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**shadcn 组件**:Button + ToggleGroup + Card + lucide-react 图标
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## L07: tabs-vertical(左侧 Tab + 右侧内容)
|
|
206
|
+
|
|
207
|
+
**Sketch 特征**:
|
|
208
|
+
- 左侧 200-240px 垂直 Tab 列表(含图标)
|
|
209
|
+
- 右侧 Tab 对应内容
|
|
210
|
+
|
|
211
|
+
**典型场景**:设置页(账户/通知/隐私)、个人中心
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-[200px_1fr] lg:grid-cols-[240px_1fr]">
|
|
215
|
+
<nav className="flex flex-col gap-1">
|
|
216
|
+
{tabs.map((tab) => (
|
|
217
|
+
<button key={tab.value} onClick={() => setActive(tab.value)}
|
|
218
|
+
className={cn("flex items-center gap-2 rounded-md px-3 py-2 text-sm",
|
|
219
|
+
active === tab.value ? "bg-muted font-medium" : "hover:bg-muted/50")}>
|
|
220
|
+
<tab.icon className="h-4 w-4" />{tab.label}
|
|
221
|
+
</button>
|
|
222
|
+
))}
|
|
223
|
+
</nav>
|
|
224
|
+
<div>{/* tab content */}</div>
|
|
225
|
+
</div>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**shadcn 组件**:Tabs(也可用 vertical orientation 的 Radix Tabs)
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## L08: wizard-steps(步骤向导)
|
|
233
|
+
|
|
234
|
+
**Sketch 特征**:
|
|
235
|
+
- 顶部 Stepper(3-5 步)
|
|
236
|
+
- 中部当前步骤表单
|
|
237
|
+
- 底部 上一步/下一步 按钮
|
|
238
|
+
|
|
239
|
+
**典型场景**:注册流程、配置向导
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
<div className="container max-w-3xl py-8">
|
|
243
|
+
<ol className="flex items-center w-full mb-8">
|
|
244
|
+
{steps.map((step, i) => (
|
|
245
|
+
<li key={step} className={cn("flex items-center", i < steps.length - 1 && "w-full")}>
|
|
246
|
+
<span className={cn("flex items-center justify-center w-8 h-8 rounded-full",
|
|
247
|
+
i <= current ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground")}>
|
|
248
|
+
{i < current ? <Check /> : i + 1}
|
|
249
|
+
</span>
|
|
250
|
+
{i < steps.length - 1 && <span className={cn("flex-1 h-0.5 mx-2", i < current ? "bg-primary" : "bg-muted")} />}
|
|
251
|
+
</li>
|
|
252
|
+
))}
|
|
253
|
+
</ol>
|
|
254
|
+
<Card>
|
|
255
|
+
<CardContent className="pt-6">
|
|
256
|
+
{/* current step form */}
|
|
257
|
+
</CardContent>
|
|
258
|
+
<CardFooter className="flex justify-between">
|
|
259
|
+
<Button variant="outline" onClick={prev} disabled={current === 0}>上一步</Button>
|
|
260
|
+
<Button onClick={next}>{current === steps.length - 1 ? '完成' : '下一步'}</Button>
|
|
261
|
+
</CardFooter>
|
|
262
|
+
</Card>
|
|
263
|
+
</div>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**shadcn 组件**:Button + Card + lucide-react Check 图标
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## L09: modal-form(弹窗表单)
|
|
271
|
+
|
|
272
|
+
**Sketch 特征**:
|
|
273
|
+
- 背景遮罩
|
|
274
|
+
- 居中 480-640px 模态框
|
|
275
|
+
- 标题 + 描述 + 表单 + 底部按钮
|
|
276
|
+
|
|
277
|
+
**典型场景**:新建/编辑操作
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
281
|
+
<DialogContent className="sm:max-w-[540px]">
|
|
282
|
+
<DialogHeader>
|
|
283
|
+
<DialogTitle>新建项目</DialogTitle>
|
|
284
|
+
<DialogDescription>填写项目信息</DialogDescription>
|
|
285
|
+
</DialogHeader>
|
|
286
|
+
<Form {...form}>
|
|
287
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
288
|
+
<div className="space-y-4 py-4">
|
|
289
|
+
<FormField control={form.control} name="name" render={({ field }) => (
|
|
290
|
+
<FormItem><FormLabel>名称</FormLabel>
|
|
291
|
+
<FormControl><Input {...field} /></FormControl>
|
|
292
|
+
<FormMessage />
|
|
293
|
+
</FormItem>
|
|
294
|
+
)} />
|
|
295
|
+
</div>
|
|
296
|
+
<DialogFooter>
|
|
297
|
+
<Button type="button" variant="outline" onClick={() => setOpen(false)}>取消</Button>
|
|
298
|
+
<Button type="submit">确认</Button>
|
|
299
|
+
</DialogFooter>
|
|
300
|
+
</form>
|
|
301
|
+
</Form>
|
|
302
|
+
</DialogContent>
|
|
303
|
+
</Dialog>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**shadcn 组件**:Dialog + Form + Input + Button
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## L10: data-table-page(数据表页)
|
|
311
|
+
|
|
312
|
+
**Sketch 特征**:
|
|
313
|
+
- 顶部筛选条 + 操作按钮
|
|
314
|
+
- 列头含排序 + 过滤 + 列选择
|
|
315
|
+
- 行支持选择(checkbox)
|
|
316
|
+
- 分页器在底部
|
|
317
|
+
|
|
318
|
+
**典型场景**:管理后台表格
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
<div className="space-y-4">
|
|
322
|
+
<div className="flex items-center justify-between">
|
|
323
|
+
<Input placeholder="搜索..." className="max-w-sm" />
|
|
324
|
+
<div className="flex items-center gap-2">
|
|
325
|
+
<Button variant="outline" size="sm">导出</Button>
|
|
326
|
+
<Button size="sm"><Plus />新建</Button>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
<div className="rounded-md border">
|
|
330
|
+
<Table>
|
|
331
|
+
<TableHeader>
|
|
332
|
+
{table.getHeaderGroups().map((hg) => (
|
|
333
|
+
<TableRow key={hg.id}>{hg.headers.map((h) => <TableHead key={h.id}>{flexRender(h.column.columnDef.header, h.getContext())}</TableHead>)}</TableRow>
|
|
334
|
+
))}
|
|
335
|
+
</TableHeader>
|
|
336
|
+
<TableBody>
|
|
337
|
+
{table.getRowModel().rows.map((row) => (
|
|
338
|
+
<TableRow key={row.id}>{row.getVisibleCells().map((cell) => <TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>)}</TableRow>
|
|
339
|
+
))}
|
|
340
|
+
</TableBody>
|
|
341
|
+
</Table>
|
|
342
|
+
</div>
|
|
343
|
+
<DataTablePagination table={table} />
|
|
344
|
+
</div>
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**shadcn 组件**:Table + Checkbox + Button + DropdownMenu(基于 @tanstack/react-table)
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## L11: empty-state(空状态)
|
|
352
|
+
|
|
353
|
+
**Sketch 特征**:
|
|
354
|
+
- 居中 360-480px 区域
|
|
355
|
+
- 顶部插图/图标(60-120px)
|
|
356
|
+
- 中部标题 + 描述
|
|
357
|
+
- 底部主操作按钮
|
|
358
|
+
|
|
359
|
+
**典型场景**:空列表、404、首次使用引导
|
|
360
|
+
|
|
361
|
+
```tsx
|
|
362
|
+
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
363
|
+
<div className="rounded-full bg-muted p-4 mb-4">
|
|
364
|
+
<Inbox className="h-8 w-8 text-muted-foreground" />
|
|
365
|
+
</div>
|
|
366
|
+
<h3 className="text-lg font-semibold">暂无数据</h3>
|
|
367
|
+
<p className="text-sm text-muted-foreground mt-1 max-w-sm">开始创建你的第一个项目</p>
|
|
368
|
+
<Button className="mt-6"><Plus />新建项目</Button>
|
|
369
|
+
</div>
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**shadcn 组件**:Button + lucide-react 图标
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## L12: profile-header(用户主页头部)
|
|
377
|
+
|
|
378
|
+
**Sketch 特征**:
|
|
379
|
+
- 顶部 Cover 图(200-320px)
|
|
380
|
+
- 头像悬浮在 Cover 底部边缘
|
|
381
|
+
- 用户名 + 简介 + 操作按钮
|
|
382
|
+
|
|
383
|
+
**典型场景**:用户主页、团队介绍
|
|
384
|
+
|
|
385
|
+
```tsx
|
|
386
|
+
<div>
|
|
387
|
+
<div className="h-48 md:h-64 bg-gradient-to-r from-slate-200 to-slate-300 dark:from-slate-800 dark:to-slate-900" />
|
|
388
|
+
<div className="container mx-auto px-4">
|
|
389
|
+
<div className="flex flex-col sm:flex-row sm:items-end sm:gap-6 -mt-12 sm:-mt-16">
|
|
390
|
+
<Avatar className="h-24 w-24 sm:h-32 sm:w-32 border-4 border-background">
|
|
391
|
+
<AvatarImage src={user.avatar} />
|
|
392
|
+
<AvatarFallback>{user.name[0]}</AvatarFallback>
|
|
393
|
+
</Avatar>
|
|
394
|
+
<div className="flex-1 mt-4 sm:mt-0 sm:mb-2">
|
|
395
|
+
<h1 className="text-2xl font-semibold">{user.name}</h1>
|
|
396
|
+
<p className="text-muted-foreground">{user.bio}</p>
|
|
397
|
+
</div>
|
|
398
|
+
<div className="flex gap-2 sm:mb-2">
|
|
399
|
+
<Button variant="outline">编辑</Button>
|
|
400
|
+
<Button>关注</Button>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**shadcn 组件**:Avatar + Button
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## L13: kanban-board(看板)
|
|
412
|
+
|
|
413
|
+
**Sketch 特征**:
|
|
414
|
+
- 横向多列(待办 / 进行中 / 已完成)
|
|
415
|
+
- 每列含卡片堆叠
|
|
416
|
+
- 卡片可拖拽
|
|
417
|
+
|
|
418
|
+
**典型场景**:项目管理、Trello 风格
|
|
419
|
+
|
|
420
|
+
```tsx
|
|
421
|
+
<div className="flex gap-4 overflow-x-auto p-4">
|
|
422
|
+
{columns.map((col) => (
|
|
423
|
+
<div key={col.id} className="w-72 shrink-0 rounded-lg bg-muted/40 p-3">
|
|
424
|
+
<div className="flex items-center justify-between mb-3">
|
|
425
|
+
<h3 className="font-medium">{col.title}</h3>
|
|
426
|
+
<Badge variant="secondary">{col.cards.length}</Badge>
|
|
427
|
+
</div>
|
|
428
|
+
<div className="space-y-2">
|
|
429
|
+
{col.cards.map((card) => (
|
|
430
|
+
<Card key={card.id} className="cursor-grab active:cursor-grabbing">
|
|
431
|
+
<CardContent className="p-3">
|
|
432
|
+
<p className="text-sm">{card.title}</p>
|
|
433
|
+
{card.tags && <div className="flex gap-1 mt-2">{card.tags.map((t) => <Badge key={t} variant="outline">{t}</Badge>)}</div>}
|
|
434
|
+
</CardContent>
|
|
435
|
+
</Card>
|
|
436
|
+
))}
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
))}
|
|
440
|
+
</div>
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**shadcn 组件**:Card + Badge + dnd-kit(拖拽)
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## L14: timeline(时间线)
|
|
448
|
+
|
|
449
|
+
**Sketch 特征**:
|
|
450
|
+
- 垂直轴 + 时间点
|
|
451
|
+
- 每点配内容卡片
|
|
452
|
+
|
|
453
|
+
**典型场景**:活动日志、订单历史
|
|
454
|
+
|
|
455
|
+
```tsx
|
|
456
|
+
<div className="space-y-6">
|
|
457
|
+
{events.map((event, i) => (
|
|
458
|
+
<div key={event.id} className="flex gap-4">
|
|
459
|
+
<div className="flex flex-col items-center">
|
|
460
|
+
<div className={cn("h-2 w-2 rounded-full", i === 0 ? "bg-primary" : "bg-muted-foreground")} />
|
|
461
|
+
{i < events.length - 1 && <div className="w-px flex-1 bg-border mt-2" />}
|
|
462
|
+
</div>
|
|
463
|
+
<Card className="flex-1">
|
|
464
|
+
<CardContent className="p-4">
|
|
465
|
+
<div className="flex items-center justify-between">
|
|
466
|
+
<p className="font-medium">{event.title}</p>
|
|
467
|
+
<time className="text-xs text-muted-foreground">{event.time}</time>
|
|
468
|
+
</div>
|
|
469
|
+
<p className="text-sm text-muted-foreground mt-1">{event.description}</p>
|
|
470
|
+
</CardContent>
|
|
471
|
+
</Card>
|
|
472
|
+
</div>
|
|
473
|
+
))}
|
|
474
|
+
</div>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**shadcn 组件**:Card
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## L15: pricing-cards(价格卡片)
|
|
482
|
+
|
|
483
|
+
**Sketch 特征**:
|
|
484
|
+
- 3-4 列响应式
|
|
485
|
+
- 中间一列"推荐"(高亮边框 + 徽章)
|
|
486
|
+
- 每列:标题 + 价格 + 特性列表 + CTA 按钮
|
|
487
|
+
|
|
488
|
+
**典型场景**:SaaS 定价页
|
|
489
|
+
|
|
490
|
+
```tsx
|
|
491
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-3">
|
|
492
|
+
{plans.map((plan) => (
|
|
493
|
+
<Card key={plan.id} className={cn("relative", plan.featured && "border-primary shadow-lg")}>
|
|
494
|
+
{plan.featured && <Badge className="absolute -top-3 left-1/2 -translate-x-1/2">推荐</Badge>}
|
|
495
|
+
<CardHeader>
|
|
496
|
+
<CardTitle>{plan.name}</CardTitle>
|
|
497
|
+
<CardDescription>{plan.description}</CardDescription>
|
|
498
|
+
<div className="mt-4">
|
|
499
|
+
<span className="text-4xl font-bold">¥{plan.price}</span>
|
|
500
|
+
<span className="text-muted-foreground">/月</span>
|
|
501
|
+
</div>
|
|
502
|
+
</CardHeader>
|
|
503
|
+
<CardContent>
|
|
504
|
+
<ul className="space-y-2">
|
|
505
|
+
{plan.features.map((f) => (
|
|
506
|
+
<li key={f} className="flex items-center gap-2 text-sm">
|
|
507
|
+
<Check className="h-4 w-4 text-primary" />{f}
|
|
508
|
+
</li>
|
|
509
|
+
))}
|
|
510
|
+
</ul>
|
|
511
|
+
</CardContent>
|
|
512
|
+
<CardFooter>
|
|
513
|
+
<Button className="w-full" variant={plan.featured ? 'default' : 'outline'}>
|
|
514
|
+
{plan.cta}
|
|
515
|
+
</Button>
|
|
516
|
+
</CardFooter>
|
|
517
|
+
</Card>
|
|
518
|
+
))}
|
|
519
|
+
</div>
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**shadcn 组件**:Card + Badge + Button + lucide-react Check
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## 反查决策树
|
|
527
|
+
|
|
528
|
+
```
|
|
529
|
+
画板 1 列 → L02 topbar-content
|
|
530
|
+
画板 2 列 → x<300 侧栏 L01 sidebar-main | x>700 主区单独
|
|
531
|
+
画板 2 列 35/65 → L04 left-right
|
|
532
|
+
画板 3+ 列 → 顶部 grid(d-grid-cols-3/4)
|
|
533
|
+
画板 卡片栅格 → L03 dashboard-grid
|
|
534
|
+
画板 表单 → L05 form-page
|
|
535
|
+
画板 弹窗 → L09 modal-form
|
|
536
|
+
画板 步骤 → L08 wizard-steps
|
|
537
|
+
画板 表格 → L10 data-table-page
|
|
538
|
+
画板 价格 → L15 pricing-cards
|
|
539
|
+
画板 时间线 → L14 timeline
|
|
540
|
+
画板 看板 → L13 kanban-board
|
|
541
|
+
画板 列表/卡片切换 → L06 list-card-switch
|
|
542
|
+
画板 垂直 Tab → L07 tabs-vertical
|
|
543
|
+
画板 空状态 → L11 empty-state
|
|
544
|
+
画板 用户主页 → L12 profile-header
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**多种模式可叠加**(常见组合):
|
|
548
|
+
- L01 + L03:侧边栏 + 仪表盘
|
|
549
|
+
- L02 + L10:顶部栏 + 表格
|
|
550
|
+
- L01 + L05:侧边栏 + 设置表单
|
|
551
|
+
- L01 + L07:侧边栏 + 垂直 Tab 设置
|