@h-ai/cli 0.1.0-alpha5

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.
Files changed (109) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +167 -0
  3. package/dist/chunk-2H7UOFLK.js +10 -0
  4. package/dist/chunk-2H7UOFLK.js.map +1 -0
  5. package/dist/chunk-LANIDJC7.js +659 -0
  6. package/dist/chunk-LANIDJC7.js.map +1 -0
  7. package/dist/chunk-YV7WPUI6.js +206 -0
  8. package/dist/chunk-YV7WPUI6.js.map +1 -0
  9. package/dist/config-templates-S5RI2MC6.js +5 -0
  10. package/dist/config-templates-S5RI2MC6.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +1645 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/skill-templates-N5DU5FNX.js +5 -0
  15. package/dist/skill-templates-N5DU5FNX.js.map +1 -0
  16. package/dist/src-XJ6YXNAF.js +15030 -0
  17. package/dist/src-XJ6YXNAF.js.map +1 -0
  18. package/package.json +59 -0
  19. package/templates/README.md +126 -0
  20. package/templates/apps/admin/messages/en-US.json +33 -0
  21. package/templates/apps/admin/messages/zh-CN.json +33 -0
  22. package/templates/apps/admin/src/routes/+layout.svelte.hbs +30 -0
  23. package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -0
  24. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +44 -0
  25. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +45 -0
  26. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +37 -0
  27. package/templates/apps/admin/src/routes/api/health/+server.ts +12 -0
  28. package/templates/apps/android-app/.env.hbs +3 -0
  29. package/templates/apps/android-app/capacitor.config.ts.hbs +12 -0
  30. package/templates/apps/android-app/messages/en-US.json +24 -0
  31. package/templates/apps/android-app/messages/zh-CN.json +24 -0
  32. package/templates/apps/android-app/src/lib/api.ts.hbs +30 -0
  33. package/templates/apps/android-app/src/lib/capacitor.ts +21 -0
  34. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +42 -0
  35. package/templates/apps/android-app/src/routes/+layout.ts +7 -0
  36. package/templates/apps/android-app/src/routes/+page.svelte.hbs +27 -0
  37. package/templates/apps/api/src/routes/+layout.svelte +14 -0
  38. package/templates/apps/api/src/routes/+page.svelte +11 -0
  39. package/templates/apps/api/src/routes/api/v1/health/+server.ts +14 -0
  40. package/templates/apps/api/src/routes/api/v1/items/+server.ts +37 -0
  41. package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +30 -0
  42. package/templates/apps/h5/messages/en-US.json +37 -0
  43. package/templates/apps/h5/messages/zh-CN.json +37 -0
  44. package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -0
  45. package/templates/apps/h5/src/routes/+page.svelte.hbs +27 -0
  46. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +27 -0
  47. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +27 -0
  48. package/templates/apps/website/messages/en-US.json +32 -0
  49. package/templates/apps/website/messages/zh-CN.json +32 -0
  50. package/templates/apps/website/src/routes/+layout.svelte.hbs +66 -0
  51. package/templates/apps/website/src/routes/+page.svelte.hbs +33 -0
  52. package/templates/apps/website/src/routes/about/+page.svelte.hbs +27 -0
  53. package/templates/apps/website/src/routes/api/health/+server.ts +12 -0
  54. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +59 -0
  55. package/templates/apps/website/src/routes/services/+page.svelte.hbs +63 -0
  56. package/templates/base/e2e/helpers.ts +49 -0
  57. package/templates/base/package.json.hbs +67 -0
  58. package/templates/base/playwright.config.ts +32 -0
  59. package/templates/base/src/app.css +2 -0
  60. package/templates/base/src/app.d.ts.hbs +18 -0
  61. package/templates/base/src/app.html.hbs +16 -0
  62. package/templates/base/src/hooks.server.ts.hbs +123 -0
  63. package/templates/base/src/lib/server/init.ts.hbs +190 -0
  64. package/templates/base/svelte.config.js.hbs +30 -0
  65. package/templates/base/tsconfig.json +8 -0
  66. package/templates/base/vite.config.ts.hbs +27 -0
  67. package/templates/features/ai/routes/api/chat/+server.ts +26 -0
  68. package/templates/features/datapipe/routes/api/datapipe/pipeline/+server.ts +41 -0
  69. package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +21 -0
  70. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +98 -0
  71. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +124 -0
  72. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +98 -0
  73. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +114 -0
  74. package/templates/features/iam/routes-shared/api/auth/login/+server.ts +32 -0
  75. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +15 -0
  76. package/templates/features/iam/routes-shared/api/auth/me/+server.ts +12 -0
  77. package/templates/features/iam/routes-shared/api/auth/register/+server.ts +26 -0
  78. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +30 -0
  79. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +42 -0
  80. package/templates/features/payment/routes/api/v1/payment/query/[orderNo]/+server.ts +25 -0
  81. package/templates/features/storage/routes/api/upload/+server.ts +35 -0
  82. package/templates/features/vecdb/routes/api/vecdb/search/+server.ts +36 -0
  83. package/templates/i18n/project.inlang/settings.json +11 -0
  84. package/templates/skills/AGENTS.md +26 -0
  85. package/templates/skills/CLAUDE.md +12 -0
  86. package/templates/skills/copilot-instructions.md +61 -0
  87. package/templates/skills/hai-ai/SKILL.md +659 -0
  88. package/templates/skills/hai-api-client/SKILL.md +346 -0
  89. package/templates/skills/hai-app-create/SKILL.md +371 -0
  90. package/templates/skills/hai-app-review/SKILL.md +156 -0
  91. package/templates/skills/hai-app-tests/SKILL.md +468 -0
  92. package/templates/skills/hai-audit/SKILL.md +141 -0
  93. package/templates/skills/hai-build/SKILL.md +319 -0
  94. package/templates/skills/hai-cache/SKILL.md +184 -0
  95. package/templates/skills/hai-capacitor/SKILL.md +389 -0
  96. package/templates/skills/hai-core/SKILL.md +544 -0
  97. package/templates/skills/hai-crypto/SKILL.md +183 -0
  98. package/templates/skills/hai-datapipe/SKILL.md +214 -0
  99. package/templates/skills/hai-deploy/SKILL.md +210 -0
  100. package/templates/skills/hai-iam/SKILL.md +355 -0
  101. package/templates/skills/hai-kit/SKILL.md +319 -0
  102. package/templates/skills/hai-payment/SKILL.md +289 -0
  103. package/templates/skills/hai-reach/SKILL.md +325 -0
  104. package/templates/skills/hai-reldb/SKILL.md +459 -0
  105. package/templates/skills/hai-scheduler/SKILL.md +242 -0
  106. package/templates/skills/hai-storage/SKILL.md +230 -0
  107. package/templates/skills/hai-ui/SKILL.md +275 -0
  108. package/templates/skills/hai-vecdb/SKILL.md +273 -0
  109. package/templates/skills/opencode.json +11 -0
@@ -0,0 +1,230 @@
1
+ ---
2
+ name: hai-storage
3
+ description: 使用 @h-ai/storage 进行文件存储操作(本地/S3),包括 file/dir/presign 三组能力;当需求涉及文件上传下载、目录批量删除、S3 预签名 URL 或客户端直传时使用。
4
+ ---
5
+
6
+ # hai-storage
7
+
8
+ > `@h-ai/storage` 提供统一文件存储接口,支持本地文件系统(LocalProvider)和 S3 兼容存储(S3Provider),通过 `storage.file`、`storage.dir`、`storage.presign` 三组接口访问能力。
9
+
10
+ ---
11
+
12
+ ## 适用场景
13
+
14
+ - 文件上传与下载
15
+ - 预签名 URL 生成(客户端直传)
16
+ - S3 兼容存储对接(AWS S3、MinIO、阿里云 OSS 等)
17
+ - 本地开发文件存储
18
+ - 目录前缀清理与批量文件删除
19
+
20
+ ---
21
+
22
+ ## 使用步骤
23
+
24
+ ### 1. 配置
25
+
26
+ ```yaml
27
+ # config/_storage.yml
28
+ type: ${HAI_STORAGE_TYPE:local} # local | s3
29
+ # 本地存储
30
+ root: ${HAI_STORAGE_PATH:./data/storage}
31
+ # S3 存储(type=s3 时生效)
32
+ # endpoint: ${HAI_STORAGE_S3_ENDPOINT:}
33
+ # region: ${HAI_STORAGE_S3_REGION:us-east-1}
34
+ # accessKeyId: ${HAI_STORAGE_S3_ACCESS_KEY:}
35
+ # secretAccessKey: ${HAI_STORAGE_S3_SECRET_KEY:}
36
+ # bucket: ${HAI_STORAGE_S3_BUCKET:my-bucket}
37
+ # forcePathStyle: false
38
+ # prefix: ''
39
+ # publicUrl: ''
40
+ ```
41
+
42
+ ### 2. 初始化与关闭
43
+
44
+ ```typescript
45
+ import { storage } from '@h-ai/storage'
46
+
47
+ await storage.init(core.config.get('storage'))
48
+ // 使用后关闭
49
+ await storage.close()
50
+ ```
51
+
52
+ ---
53
+
54
+ ## 核心 API
55
+
56
+ ### 文件操作
57
+
58
+ `storage.file` 提供以下方法:
59
+
60
+ - `put(key, data, options?)`
61
+ - `get(key, options?)`
62
+ - `head(key)`
63
+ - `exists(key)`
64
+ - `delete(key)`
65
+ - `deleteMany(keys)`
66
+ - `copy(sourceKey, destKey, options?)`
67
+
68
+ ```typescript
69
+ // 上传文件
70
+ const result = await storage.file.put('avatars/user-123.png', fileBuffer, {
71
+ contentType: 'image/png',
72
+ metadata: { userId: '123' },
73
+ })
74
+
75
+ // 下载文件
76
+ const file = await storage.file.get('avatars/user-123.png')
77
+
78
+ // 列出文件
79
+ const files = await storage.dir.list({ prefix: 'avatars/', maxKeys: 100 })
80
+ ```
81
+
82
+ ### 预签名 URL
83
+
84
+ `storage.presign` 提供以下方法:
85
+
86
+ - `getUrl(key, options?)`
87
+ - `putUrl(key, options?)`
88
+ - `publicUrl(key)`
89
+
90
+ ```typescript
91
+ // 客户端直传模式
92
+ const uploadUrl = await storage.presign.putUrl('uploads/doc.pdf', {
93
+ expiresIn: 3600, // 1 小时有效
94
+ contentType: 'application/pdf',
95
+ })
96
+
97
+ // 临时下载链接
98
+ const downloadUrl = await storage.presign.getUrl('uploads/doc.pdf', {
99
+ expiresIn: 300, // 5 分钟有效
100
+ })
101
+ ```
102
+
103
+ ---
104
+
105
+ ## 错误码 — `HaiStorageError`
106
+
107
+ | 错误码 | code | 说明 |
108
+ |--------|------|------|
109
+ | `HaiStorageError.CONNECTION_FAILED` | `hai:storage:001` | 连接失败 |
110
+ | `HaiStorageError.OPERATION_FAILED` | `hai:storage:002` | 操作失败 |
111
+ | `HaiStorageError.NOT_FOUND` | `hai:storage:003` | 文件不存在 |
112
+ | `HaiStorageError.ALREADY_EXISTS` | `hai:storage:004` | 文件已存在 |
113
+ | `HaiStorageError.PERMISSION_DENIED` | `hai:storage:005` | 权限不足 |
114
+ | `HaiStorageError.QUOTA_EXCEEDED` | `hai:storage:006` | 配额超限 |
115
+ | `HaiStorageError.INVALID_PATH` | `hai:storage:007` | 路径无效 |
116
+ | `HaiStorageError.IO_ERROR` | `hai:storage:008` | IO 错误 |
117
+ | `HaiStorageError.NETWORK_ERROR` | `hai:storage:009` | 网络错误 |
118
+ | `HaiStorageError.NOT_INITIALIZED` | `hai:storage:010` | 未初始化 |
119
+ | `HaiStorageError.UNSUPPORTED_TYPE` | `hai:storage:011` | 不支持的存储类型 |
120
+ | `HaiStorageError.CONFIG_ERROR` | `hai:storage:012` | 配置错误 |
121
+ | `HaiStorageError.PRESIGN_FAILED` | `hai:storage:013` | 预签名 URL 生成失败 |
122
+ | `HaiStorageError.UPLOAD_FAILED` | `hai:storage:014` | 上传失败 |
123
+ | `HaiStorageError.DOWNLOAD_FAILED` | `hai:storage:015` | 下载失败 |
124
+
125
+ ---
126
+
127
+ ## API 契约(`@h-ai/storage/api`)
128
+
129
+ `@h-ai/storage/api` 子路径导出所有存储端点的 Zod Schema 和端点契约定义,客户端与服务端共享同一份真相源,编译时保证 I/O 一致性。
130
+
131
+ ### 端点定义 — `storageEndpoints`
132
+
133
+ | 端点名 | method | path | input Schema | output Schema |
134
+ | ------------------ | ------ | ---------------------------- | ------------------------ | ------------------------ |
135
+ | `presignDownload` | POST | `/storage/presign/download` | `PresignGetInputSchema` | `PresignUrlOutputSchema` |
136
+ | `presignUpload` | POST | `/storage/presign/upload` | `PresignPutInputSchema` | `PresignUrlOutputSchema` |
137
+ | `fileInfo` | POST | `/storage/file/info` | `FileInfoInputSchema` | `FileMetadataSchema` |
138
+ | `listFiles` | GET | `/storage/files` | inline(prefix/maxKeys) | `ListFilesOutputSchema` |
139
+ | `deleteFile` | POST | `/storage/file/delete` | `DeleteFileInputSchema` | `z.void()` |
140
+ | `deleteFiles` | POST | `/storage/files/delete` | `DeleteFilesInputSchema` | `z.void()` |
141
+
142
+ ### 使用示例
143
+
144
+ ```typescript
145
+ import { storageEndpoints, PresignPutInputSchema } from '@h-ai/storage/api'
146
+
147
+ // 客户端:通过 api-client 调用端点
148
+ const { url } = await api.call(storageEndpoints.presignUpload, { key: 'avatar.png' })
149
+
150
+ // 服务端:基于契约定义路由
151
+ export const POST = kit.fromContract(storageEndpoints.presignUpload, async (input) => {
152
+ const result = await storage.presign.putUrl(input.key, input)
153
+ return result.success ? result.data : kit.response.internalError(result.error.message)
154
+ })
155
+
156
+ // 独立 Schema 校验
157
+ const parsed = PresignPutInputSchema.safeParse(requestBody)
158
+ if (!parsed.success) { /* 校验失败 */ }
159
+ ```
160
+
161
+ ### 导出的 Schema
162
+
163
+ - `FileMetadataSchema` — 文件元数据(key / size / contentType / lastModified / etag? / metadata?)
164
+ - `PresignGetInputSchema` — 下载签名入参(key + expiresIn?)
165
+ - `PresignPutInputSchema` — 上传签名入参(key + contentType? + contentLength? + expiresIn?)
166
+ - `PresignUrlOutputSchema` — 签名 URL 出参(url + key + expiresAt?)
167
+ - `ListFilesOutputSchema` — 文件列表出参(files + commonPrefixes + isTruncated + nextContinuationToken?)
168
+ - `DeleteFileInputSchema` — 删除单文件入参(key)
169
+ - `DeleteFilesInputSchema` — 批量删除入参(keys[])
170
+ - `FileInfoInputSchema` — 文件信息入参(key)
171
+
172
+ ### 导出的推导类型
173
+
174
+ `PresignGetInput` / `PresignPutInput` / `PresignUrlOutput` / `ListFilesOutput` / `DeleteFileInput` / `DeleteFilesInput` / `FileInfoInput`
175
+
176
+ ---
177
+
178
+ ## 常见模式
179
+
180
+ ### 与 kit 集成(文件上传 API)
181
+
182
+ ```typescript
183
+ import { storage } from '$lib/server/init'
184
+ // src/routes/api/files/upload/+server.ts
185
+ import { kit } from '@h-ai/kit'
186
+ import { z } from 'zod'
187
+
188
+ const UploadSchema = z.object({
189
+ key: z.string().min(1),
190
+ })
191
+
192
+ export const POST = kit.handler(async ({ request, locals }) => {
193
+ kit.guard.requirePermission(locals.session, 'storage:write')
194
+ const formData = await request.formData()
195
+ const file = formData.get('file') as File
196
+ if (!file)
197
+ return kit.response.badRequest('Missing file')
198
+
199
+ const key = `uploads/${locals.session.userId}/${file.name}`
200
+ const buffer = new Uint8Array(await file.arrayBuffer())
201
+ const result = await storage.file.put(key, buffer, { contentType: file.type })
202
+ if (!result.success)
203
+ return kit.response.internalError()
204
+ return kit.response.created({ key })
205
+ })
206
+ ```
207
+
208
+ > 说明:`@h-ai/storage` 只提供存储能力,不强制要求 `/api/storage` 路由命名。应用可按业务语义自定义 API 路径。
209
+
210
+ ### 头像上传
211
+
212
+ ```typescript
213
+ const key = `avatars/${userId}/${Date.now()}.png`
214
+ const result = await storage.file.put(key, avatarBuffer, {
215
+ contentType: 'image/png',
216
+ })
217
+ if (result.success) {
218
+ const publicUrl = storage.presign.publicUrl(key)
219
+ await iam.user.updateUser(userId, { avatarUrl: publicUrl ?? '' })
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 相关 Skills
226
+
227
+ - `hai-build`:模块初始化顺序
228
+ - `hai-core`:配置与 HaiResult 模型
229
+ - `hai-kit`:SvelteKit API 端点集成(`kit.handler` + `kit.guard`)
230
+ - `hai-ui`:Storage 场景组件(FileUpload/ImageUpload/AvatarUpload)
@@ -0,0 +1,275 @@
1
+ ---
2
+ name: hai-ui
3
+ description: 使用 @h-ai/ui 构建多端应用界面,包含三层组件架构(原子/组合/场景)、DaisyUI 样式 + Bits UI headless 交互、移动端组件(SafeArea/BottomNav/PullRefresh/ActionSheet/SwipeCell/InfiniteScroll/AppBar)、Design Token 系统与平台检测;当需求涉及界面、表单、表格、移动端适配或主题切换时使用。
4
+ ---
5
+
6
+ # hai-ui
7
+
8
+ > `@h-ai/ui` 是基于 Svelte 5 Runes 的多端 UI 组件库,采用 DaisyUI v5 + Tailwind CSS v4 + Bits UI v2,支持 32 主题、内置中英文 i18n、自动导入。新增 Design Token 系统和 7 个移动端组件。
9
+
10
+ ---
11
+
12
+ ## 适用场景
13
+
14
+ - 构建管理后台页面(表单、表格、弹窗、导航等)
15
+ - 移动端/App 界面开发(SafeArea、BottomNav、PullRefresh 等)
16
+ - 使用 Bits UI headless 交互组件(Combobox、DatePicker、Calendar)
17
+ - 使用 IAM 场景组件(登录/注册/密码/用户资料表单)
18
+ - 使用 Storage 场景组件(文件上传/图片上传/文件列表)
19
+ - 配置主题切换与 i18n 多语言
20
+ - 多端平台检测与适配
21
+
22
+ ---
23
+
24
+ ## 使用步骤
25
+
26
+ ### 1. 配置自动导入
27
+
28
+ ```typescript
29
+ // svelte.config.js
30
+ import { autoImportHaiUi } from '@h-ai/ui/auto-import'
31
+
32
+ const config = {
33
+ preprocess: [autoImportHaiUi(), vitePreprocess()],
34
+ }
35
+ ```
36
+
37
+ ### 2. 引入全局样式(移动端必须)
38
+
39
+ ```css
40
+ /* src/app.css */
41
+ @import '@h-ai/ui/styles/design-tokens.css'; /* Design Token */
42
+ @import '@h-ai/ui/styles/mobile.css'; /* 移动端触摸/安全区域优化 */
43
+ @import 'tailwindcss';
44
+ ```
45
+
46
+ ### 3. 平台检测
47
+
48
+ ```typescript
49
+ import { detectPlatform, isMobile, isNativeApp, usePlatform } from '@h-ai/ui'
50
+
51
+ // 一次性检测
52
+ const platform = detectPlatform() // 'ios' | 'android' | 'web'
53
+ const mobile = isMobile() // boolean
54
+ const native = isNativeApp() // boolean(Capacitor 环境)
55
+
56
+ // Svelte 5 响应式(组件中使用)
57
+ const p = usePlatform()
58
+ // p.platform / p.isMobile / p.isNative
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 三层组件架构
64
+
65
+ ### 原子组件(Primitives,21 个)
66
+
67
+ | 组件 | Props 要点 | 说明 |
68
+ | ------------ | ------------------------------------------------------------- | -------- |
69
+ | `Button` | `variant`, `size`, `loading`, `disabled`, `outline`, `circle` | 按钮 |
70
+ | `IconButton` | `icon: string \| Snippet`, `tooltip`, `variant`, `size` | 图标按钮 |
71
+ | `Input` | `value`, `type`, `size`, `error`, `placeholder` | 输入框 |
72
+ | `Textarea` | `value`, `rows`, `autoResize`, `error` | 文本域 |
73
+ | `Select` | `value`, `options: SelectOption[]`, `placeholder` | 下拉选择 |
74
+ | `Checkbox` | `checked`, `label`, `indeterminate` | 复选框 |
75
+ | `Switch` | `checked`, `label`, `size` | 开关 |
76
+ | `Radio` | `value`, `options`, `direction` | 单选组 |
77
+ | `Range` | `value`, `min`, `max`, `step`, `variant`, `size` | 滑块 |
78
+ | `Rating` | `value`, `max` | 评分 |
79
+ | `Badge` | `variant`, `size`, `outline` | 徽标 |
80
+ | `Avatar` | `src`, `name`, `size`, `shape` | 头像 |
81
+ | `Tag` | `text`, `variant`, `closable` | 标签 |
82
+ | `Spinner` | `size`, `variant` | 加载动画 |
83
+ | `Progress` | `value`, `max`, `striped`, `animated` | 进度条 |
84
+
85
+ ### 组合组件(Compounds,25 + 7 移动端)
86
+
87
+ 由原子组件 + Bits UI headless 交互组合。
88
+
89
+ #### 桌面端组合组件
90
+
91
+ | 组件 | Props 要点 | 说明 |
92
+ | ------------ | ------------------------------------------------------------------ | ------------- |
93
+ | `Form` | `loading`, `disabled`, `onsubmit` | 表单容器 |
94
+ | `FormField` | `label`, `name`, `error`, `hint`, `required` | 表单字段 |
95
+ | `Modal` | `open`, `title`, `size`, `closeOnBackdrop` | 模态框 |
96
+ | `Drawer` | `open`, `position`, `size` | 抽屉 |
97
+ | `DataTable` | `data`, `columns`, `keyField`, snippet slots | 数据表格 |
98
+ | `Combobox` | `options`, `value`, `multiple`, `placeholder`, `error`, `onchange` | 可搜索选择 |
99
+ | `Calendar` | `value`, `minValue`, `maxValue` | 独立日历 |
100
+ | `DatePicker` | `value`, `minValue`, `maxValue`, `error` | 日期输入+弹出 |
101
+ | `Tabs` | `items: TabItem[]`, `active`, `type` | 标签页 |
102
+ | `Pagination` | `page`, `total`, `pageSize`, `onchange` | 分页 |
103
+ | `Dropdown` | `items: DropdownItem[]`, `trigger` | 下拉菜单 |
104
+ | `Accordion` | `items: AccordionItem[]` | 折叠面板 |
105
+ | `Skeleton` | `variant`, `count`, `animation` | 骨架屏 |
106
+ | `Empty` | `title`, `description`, `icon` | 空状态 |
107
+
108
+ #### 移动端组合组件(新增 7 个)
109
+
110
+ | 组件 | Props 要点 | 说明 |
111
+ | ---------------- | ----------------------------------------------------------------------------- | ---------------- |
112
+ | `SafeArea` | `top`, `bottom`, `left`, `right` | 安全区域容器 |
113
+ | `AppBar` | `title`, `backHref`, `onback`, `fixed`, `transparent`, snippet `left`/`right` | 顶部导航栏 |
114
+ | `BottomNav` | `items: BottomNavItem[]`, `active` | 底部导航栏 |
115
+ | `ActionSheet` | `open`, `title`, `items: ActionSheetItem[]`, `cancelText`, `onselect` | 底部弹出操作面板 |
116
+ | `PullRefresh` | `refreshing`, `onrefresh`, `threshold`, `pullText`, `releaseText` | 下拉刷新 |
117
+ | `InfiniteScroll` | `loading`, `finished`, `threshold`, `onload`, `loadingText`, `finishedText` | 无限滚动加载 |
118
+ | `SwipeCell` | `leftActions`, `rightActions: SwipeCellAction[]`, `threshold` | 滑动操作单元格 |
119
+
120
+ **移动端组件用法示例**:
121
+
122
+ ```svelte
123
+ <script lang="ts">
124
+ import type { BottomNavItem } from '@h-ai/ui'
125
+
126
+ const navItems: BottomNavItem[] = [
127
+ { key: 'home', label: '首页', icon: 'tabler:home', href: '/' },
128
+ { key: 'discover', label: '发现', icon: 'tabler:compass', href: '/discover' },
129
+ { key: 'profile', label: '我的', icon: 'tabler:user', href: '/profile' },
130
+ ]
131
+ </script>
132
+
133
+ <SafeArea top bottom>
134
+ <AppBar title="首页" />
135
+ <PullRefresh bind:refreshing onrefresh={loadData}>
136
+ <main class="p-4">
137
+ <!-- 页面内容 -->
138
+ </main>
139
+ </PullRefresh>
140
+ <BottomNav items={navItems} active="home" />
141
+ </SafeArea>
142
+ ```
143
+
144
+ **ActionSheet 用法**:
145
+
146
+ ```svelte
147
+ <script lang="ts">
148
+ import type { ActionSheetItem } from '@h-ai/ui'
149
+
150
+ let showActions = $state(false)
151
+ const actions: ActionSheetItem[] = [
152
+ { key: 'camera', label: '拍照' },
153
+ { key: 'album', label: '从相册选择' },
154
+ { key: 'delete', label: '删除', destructive: true },
155
+ ]
156
+ </script>
157
+
158
+ <ActionSheet bind:open={showActions} title="选择操作" items={actions} onselect={handleAction} />
159
+ ```
160
+
161
+ **SwipeCell 用法**:
162
+
163
+ ```svelte
164
+ <script lang="ts">
165
+ import type { SwipeCellAction } from '@h-ai/ui'
166
+
167
+ const rightActions: SwipeCellAction[] = [
168
+ { key: 'edit', label: '编辑', color: '#3b82f6' },
169
+ { key: 'delete', label: '删除', color: '#ef4444' },
170
+ ]
171
+ </script>
172
+
173
+ <SwipeCell {rightActions} onaction={handleSwipeAction}>
174
+ <div class="p-4">列表项内容</div>
175
+ </SwipeCell>
176
+ ```
177
+
178
+ ### 场景组件(Scenes)
179
+
180
+ 内置中英文翻译的业务场景组件。
181
+
182
+ #### IAM 场景组件
183
+
184
+ | 组件 | Props 要点 | 说明 |
185
+ | -------------- | ----------------------------------------------- | -------- |
186
+ | `LoginForm` | `showRememberMe`, `showRegisterLink`, `errors` | 登录表单 |
187
+ | `RegisterForm` | `fields`, `minPasswordLength`, `errors` | 注册表单 |
188
+ | `UserProfile` | `user`, `editable`, `fields`, `avatarUploadUrl` | 用户资料 |
189
+
190
+ #### Storage 场景组件
191
+
192
+ | 组件 | Props 要点 | 说明 |
193
+ | ------------- | ---------------------------------------------- | -------- |
194
+ | `FileUpload` | `accept`, `maxSize`, `uploadUrl`, `autoUpload` | 文件上传 |
195
+ | `ImageUpload` | `value`, `uploadUrl`, `aspectRatio` | 图片上传 |
196
+ | `FileList` | `files: FileItem[]`, `layout`, `showPreview` | 文件列表 |
197
+
198
+ ---
199
+
200
+ ## Design Token 系统
201
+
202
+ CSS 自定义属性统一管理设计变量:
203
+
204
+ ```css
205
+ /* design-tokens.css 提供的 Token */
206
+ --hai-spacing-xs: 4px;
207
+ --hai-spacing-sm: 8px;
208
+ --hai-spacing-md: 16px;
209
+ --hai-spacing-lg: 24px;
210
+
211
+ --hai-radius-sm: 4px;
212
+ --hai-radius-md: 8px;
213
+ --hai-radius-lg: 12px;
214
+
215
+ --hai-font-size-xs: 12px;
216
+ --hai-font-size-sm: 14px;
217
+ --hai-font-size-base: 16px;
218
+
219
+ --hai-touch-target-min: 44px; /* 最小触摸目标 */
220
+ --hai-safe-area-top: env(safe-area-inset-top);
221
+ --hai-safe-area-bottom: env(safe-area-inset-bottom);
222
+
223
+ --hai-z-dropdown: 1000;
224
+ --hai-z-modal: 2000;
225
+ --hai-z-toast: 3000;
226
+
227
+ --hai-transition-fast: 150ms ease;
228
+ --hai-transition-normal: 250ms ease;
229
+ ```
230
+
231
+ ### mobile.css 提供的全局类
232
+
233
+ | 类名 | 用途 |
234
+ | ----------------------- | ------------------------------- |
235
+ | `.hai-safe-top` | 上方安全区域 padding |
236
+ | `.hai-safe-bottom` | 下方安全区域 padding |
237
+ | `.hai-safe-all` | 四周安全区域 padding |
238
+ | `.hai-scroll-container` | 优化的滚动容器(momentum 滚动) |
239
+ | `.hai-keyboard-aware` | 虚拟键盘弹起时自动调整内容 |
240
+
241
+ ---
242
+
243
+ ## 主题系统
244
+
245
+ 支持 32 个 DaisyUI 主题。
246
+
247
+ ```typescript
248
+ import { applyTheme, getCurrentTheme } from '@h-ai/ui'
249
+
250
+ applyTheme('dark')
251
+ const theme = getCurrentTheme()
252
+ ```
253
+
254
+ ---
255
+
256
+ ## 重要约定
257
+
258
+ 1. **Svelte 5 Runes**:使用 `$state`、`$derived`、`$effect`
259
+ 2. **Snippet 插槽**:使用 `{#snippet name()}...{/snippet}` 语法
260
+ 3. **三层依赖红线**:primitives 不依赖上层,compounds 只依赖 primitives + Bits UI,scenes 可依赖两者
261
+ 4. **自动导入例外**:`toast`、类型导入、`Range`/`FileList` 必须显式 `import`
262
+ 5. **Combobox 统一单选/多选**:`MultiSelect` 已删除
263
+ 6. **移动端样式**:务必引入 `design-tokens.css` + `mobile.css`,使用 SafeArea 包裹原生 App 页面
264
+
265
+ ---
266
+
267
+ ## 相关 Skills
268
+
269
+ - `hai-build`:项目架构与技能导航
270
+ - `hai-kit`:SvelteKit 集成
271
+ - `hai-iam`:IAM 模块 API(与 LoginForm/RegisterForm 配合)
272
+ - `hai-capacitor`:原生 App 开发(与 SafeArea/AppBar 配合)
273
+ - `hai-api-client`:客户端数据获取
274
+
275
+ - `hai-capacitor`:原生 App 开发(与 SafeArea/AppBar 配合)