@deernova/style 0.0.0-stage → 0.1.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.
Files changed (171) hide show
  1. package/README.md +15 -2
  2. package/bin/cli.mjs +32 -0
  3. package/package.json +18 -4
  4. package/skill/SKILL.md +36 -0
  5. package/skill/assets/design/README.md +170 -0
  6. package/skill/assets/design/components/Banner/README.md +33 -0
  7. package/skill/assets/design/components/Banner/preview.html +26 -0
  8. package/skill/assets/design/components/Button/README.md +59 -0
  9. package/skill/assets/design/components/Button/preview.html +27 -0
  10. package/skill/assets/design/components/Card/README.md +31 -0
  11. package/skill/assets/design/components/Card/preview.html +24 -0
  12. package/skill/assets/design/components/CodeBlock/README.md +34 -0
  13. package/skill/assets/design/components/CodeBlock/preview.html +16 -0
  14. package/skill/assets/design/components/Composer/README.md +42 -0
  15. package/skill/assets/design/components/Composer/preview.html +28 -0
  16. package/skill/assets/design/components/Cover/preview.html +53 -0
  17. package/skill/assets/design/components/EmptyState/README.md +28 -0
  18. package/skill/assets/design/components/EmptyState/preview.html +16 -0
  19. package/skill/assets/design/components/GlassControls/README.md +43 -0
  20. package/skill/assets/design/components/GlassControls/preview.html +40 -0
  21. package/skill/assets/design/components/ListGroup/README.md +39 -0
  22. package/skill/assets/design/components/ListGroup/preview.html +22 -0
  23. package/skill/assets/design/components/MacWindow/README.md +27 -0
  24. package/skill/assets/design/components/MacWindow/preview.html +70 -0
  25. package/skill/assets/design/components/Message/README.md +31 -0
  26. package/skill/assets/design/components/Message/preview.html +21 -0
  27. package/skill/assets/design/components/PhoneScreen/README.md +25 -0
  28. package/skill/assets/design/components/PhoneScreen/preview.html +74 -0
  29. package/skill/assets/design/components/Segmented/README.md +21 -0
  30. package/skill/assets/design/components/Segmented/preview.html +21 -0
  31. package/skill/assets/design/components/Sheet/README.md +29 -0
  32. package/skill/assets/design/components/Sheet/preview.html +31 -0
  33. package/skill/assets/design/components/Sidebar/README.md +36 -0
  34. package/skill/assets/design/components/Sidebar/preview.html +20 -0
  35. package/skill/assets/design/components/StepRow/README.md +35 -0
  36. package/skill/assets/design/components/StepRow/preview.html +17 -0
  37. package/skill/assets/design/components/Tag/README.md +36 -0
  38. package/skill/assets/design/components/Tag/preview.html +22 -0
  39. package/skill/assets/design/components/TextField/README.md +29 -0
  40. package/skill/assets/design/components/TextField/preview.html +28 -0
  41. package/skill/assets/design/components/bundle.css +189 -0
  42. package/skill/assets/design/design-system.json +25 -0
  43. package/skill/assets/design/images/Banner-dark.png +0 -0
  44. package/skill/assets/design/images/Banner-light.png +0 -0
  45. package/skill/assets/design/images/Button-dark.png +0 -0
  46. package/skill/assets/design/images/Button-light.png +0 -0
  47. package/skill/assets/design/images/Card-dark.png +0 -0
  48. package/skill/assets/design/images/Card-light.png +0 -0
  49. package/skill/assets/design/images/CodeBlock-dark.png +0 -0
  50. package/skill/assets/design/images/CodeBlock-light.png +0 -0
  51. package/skill/assets/design/images/Composer-dark.png +0 -0
  52. package/skill/assets/design/images/Composer-light.png +0 -0
  53. package/skill/assets/design/images/Cover-dark.png +0 -0
  54. package/skill/assets/design/images/Cover-light.png +0 -0
  55. package/skill/assets/design/images/EmptyState-dark.png +0 -0
  56. package/skill/assets/design/images/EmptyState-light.png +0 -0
  57. package/skill/assets/design/images/Example-iOSButtonsInPhone-dark.png +0 -0
  58. package/skill/assets/design/images/Example-iOSButtonsInPhone-light.png +0 -0
  59. package/skill/assets/design/images/GlassControls-dark.png +0 -0
  60. package/skill/assets/design/images/GlassControls-light.png +0 -0
  61. package/skill/assets/design/images/ListGroup-dark.png +0 -0
  62. package/skill/assets/design/images/ListGroup-light.png +0 -0
  63. package/skill/assets/design/images/MacWindow-dark.png +0 -0
  64. package/skill/assets/design/images/MacWindow-light.png +0 -0
  65. package/skill/assets/design/images/Message-dark.png +0 -0
  66. package/skill/assets/design/images/Message-light.png +0 -0
  67. package/skill/assets/design/images/PhoneScreen-dark.png +0 -0
  68. package/skill/assets/design/images/PhoneScreen-light.png +0 -0
  69. package/skill/assets/design/images/Segmented-dark.png +0 -0
  70. package/skill/assets/design/images/Segmented-light.png +0 -0
  71. package/skill/assets/design/images/Sheet-dark.png +0 -0
  72. package/skill/assets/design/images/Sheet-light.png +0 -0
  73. package/skill/assets/design/images/Sidebar-dark.png +0 -0
  74. package/skill/assets/design/images/Sidebar-light.png +0 -0
  75. package/skill/assets/design/images/StepRow-dark.png +0 -0
  76. package/skill/assets/design/images/StepRow-light.png +0 -0
  77. package/skill/assets/design/images/Tag-dark.png +0 -0
  78. package/skill/assets/design/images/Tag-light.png +0 -0
  79. package/skill/assets/design/images/TextField-dark.png +0 -0
  80. package/skill/assets/design/images/TextField-light.png +0 -0
  81. package/skill/assets/design/tokens.css +187 -0
  82. package/skill/assets/design/tokens.json +142 -0
  83. package/skill/manifest.json +24 -0
  84. package/skill/references/components.md +648 -0
  85. package/skill/references/foundations.md +170 -0
  86. package/skill/references/native.md +7 -0
  87. package/skill/references/review.md +13 -0
  88. package/skill/references/tokens.md +74 -0
  89. package/skill/references/web.md +11 -0
  90. package/template/app.js +7 -0
  91. package/template/index.html +1290 -0
  92. package/template/manifest.json +24 -0
  93. package/template/project/README.md +170 -0
  94. package/template/project/components/Banner/README.md +33 -0
  95. package/template/project/components/Banner/preview.html +26 -0
  96. package/template/project/components/Button/README.md +59 -0
  97. package/template/project/components/Button/preview.html +27 -0
  98. package/template/project/components/Card/README.md +31 -0
  99. package/template/project/components/Card/preview.html +24 -0
  100. package/template/project/components/CodeBlock/README.md +34 -0
  101. package/template/project/components/CodeBlock/preview.html +16 -0
  102. package/template/project/components/Composer/README.md +42 -0
  103. package/template/project/components/Composer/preview.html +28 -0
  104. package/template/project/components/Cover/preview.html +53 -0
  105. package/template/project/components/EmptyState/README.md +28 -0
  106. package/template/project/components/EmptyState/preview.html +16 -0
  107. package/template/project/components/GlassControls/README.md +43 -0
  108. package/template/project/components/GlassControls/preview.html +40 -0
  109. package/template/project/components/ListGroup/README.md +39 -0
  110. package/template/project/components/ListGroup/preview.html +22 -0
  111. package/template/project/components/MacWindow/README.md +27 -0
  112. package/template/project/components/MacWindow/preview.html +70 -0
  113. package/template/project/components/Message/README.md +31 -0
  114. package/template/project/components/Message/preview.html +21 -0
  115. package/template/project/components/PhoneScreen/README.md +25 -0
  116. package/template/project/components/PhoneScreen/preview.html +74 -0
  117. package/template/project/components/Segmented/README.md +21 -0
  118. package/template/project/components/Segmented/preview.html +21 -0
  119. package/template/project/components/Sheet/README.md +29 -0
  120. package/template/project/components/Sheet/preview.html +31 -0
  121. package/template/project/components/Sidebar/README.md +36 -0
  122. package/template/project/components/Sidebar/preview.html +20 -0
  123. package/template/project/components/StepRow/README.md +35 -0
  124. package/template/project/components/StepRow/preview.html +17 -0
  125. package/template/project/components/Tag/README.md +36 -0
  126. package/template/project/components/Tag/preview.html +22 -0
  127. package/template/project/components/TextField/README.md +29 -0
  128. package/template/project/components/TextField/preview.html +28 -0
  129. package/template/project/components/bundle.css +189 -0
  130. package/template/project/design-system.json +25 -0
  131. package/template/project/images/Banner-dark.png +0 -0
  132. package/template/project/images/Banner-light.png +0 -0
  133. package/template/project/images/Button-dark.png +0 -0
  134. package/template/project/images/Button-light.png +0 -0
  135. package/template/project/images/Card-dark.png +0 -0
  136. package/template/project/images/Card-light.png +0 -0
  137. package/template/project/images/CodeBlock-dark.png +0 -0
  138. package/template/project/images/CodeBlock-light.png +0 -0
  139. package/template/project/images/Composer-dark.png +0 -0
  140. package/template/project/images/Composer-light.png +0 -0
  141. package/template/project/images/Cover-dark.png +0 -0
  142. package/template/project/images/Cover-light.png +0 -0
  143. package/template/project/images/EmptyState-dark.png +0 -0
  144. package/template/project/images/EmptyState-light.png +0 -0
  145. package/template/project/images/Example-iOSButtonsInPhone-dark.png +0 -0
  146. package/template/project/images/Example-iOSButtonsInPhone-light.png +0 -0
  147. package/template/project/images/GlassControls-dark.png +0 -0
  148. package/template/project/images/GlassControls-light.png +0 -0
  149. package/template/project/images/ListGroup-dark.png +0 -0
  150. package/template/project/images/ListGroup-light.png +0 -0
  151. package/template/project/images/MacWindow-dark.png +0 -0
  152. package/template/project/images/MacWindow-light.png +0 -0
  153. package/template/project/images/Message-dark.png +0 -0
  154. package/template/project/images/Message-light.png +0 -0
  155. package/template/project/images/PhoneScreen-dark.png +0 -0
  156. package/template/project/images/PhoneScreen-light.png +0 -0
  157. package/template/project/images/Segmented-dark.png +0 -0
  158. package/template/project/images/Segmented-light.png +0 -0
  159. package/template/project/images/Sheet-dark.png +0 -0
  160. package/template/project/images/Sheet-light.png +0 -0
  161. package/template/project/images/Sidebar-dark.png +0 -0
  162. package/template/project/images/Sidebar-light.png +0 -0
  163. package/template/project/images/StepRow-dark.png +0 -0
  164. package/template/project/images/StepRow-light.png +0 -0
  165. package/template/project/images/Tag-dark.png +0 -0
  166. package/template/project/images/Tag-light.png +0 -0
  167. package/template/project/images/TextField-dark.png +0 -0
  168. package/template/project/images/TextField-light.png +0 -0
  169. package/template/project/tokens.css +187 -0
  170. package/template/project/tokens.json +142 -0
  171. package/template/style.css +1 -0
@@ -0,0 +1,35 @@
1
+ # StepRow
2
+
3
+ 一行显示一个执行步骤:做了什么、结果如何、用了多久。点开可以看到细节。用于 AI 的工具调用、导入导出、批量处理这类任务。
4
+
5
+ **需要提供**:状态(进行中 / 成功 / 失败)、动作名(2–4 个字的动词)、对象摘要(文件名、参数、结果)、耗时或说明;可选的详细内容,点击后展开。
6
+
7
+ **规格**
8
+
9
+ - 高 `control-mac`,`radius-sm`,悬停时底色 `fill-hover`。整行默认 `ink-secondary`,让位于正文内容。
10
+ - 状态图标 14pt:进行中是 `ink` 色的转圈,成功是 `success` 色,失败是 `danger` 色。失败时摘要要写清楚原因。
11
+ - 动作名 12pt 半粗 `ink`;摘要用 11pt 等宽,单行,在末尾截断;右侧耗时 11pt `ink-tertiary`。
12
+ - 展开后的详情缩进到和文字对齐,`surface-sunken` 底,`radius-sm`,12pt 等宽。
13
+ - 连续 3 步以上全部成功时,合并成一行「完成 5 个步骤」,点击后展开。
14
+
15
+ ```swift
16
+ DisclosureGroup(isExpanded: $expanded) {
17
+ Text(step.detail)
18
+ .font(.system(.callout, design: .monospaced))
19
+ .foregroundStyle(.inkSecondary)
20
+ .padding(.vertical, 6).padding(.horizontal, 8)
21
+ .frame(maxWidth: .infinity, alignment: .leading)
22
+ .background(.surfaceSunken, in: .rect(cornerRadius: 6))
23
+ } label: {
24
+ HStack(spacing: 7) {
25
+ StatusGlyph(step.status) // ProgressView / checkmark.circle / xmark.circle
26
+ Text(step.action).fontWeight(.semibold).foregroundStyle(.ink)
27
+ Text(step.summary).font(.callout.monospaced()).lineLimit(1)
28
+ Spacer()
29
+ Text(step.duration).font(.caption).monospacedDigit().foregroundStyle(.inkTertiary)
30
+ }
31
+ .foregroundStyle(.inkSecondary)
32
+ }
33
+ ```
34
+
35
+ **不要**:把每一步都做成卡片;成功的步骤也用醒目的颜色;把原始日志直接铺在对话里(放进折叠详情)。
@@ -0,0 +1,17 @@
1
+ <!-- @dsCard group="Content" height=190 subtitle="AI 或后台任务的执行步骤" -->
2
+ <!doctype html>
3
+ <html lang="zh-CN">
4
+ <head><link rel="stylesheet" href="../../tokens.css"><link rel="stylesheet" href="../bundle.css"><script>(function(){function a(){var t=location.hash.slice(1),r=document.documentElement;if(t==="light"||t==="dark")r.setAttribute("data-theme",t);else r.removeAttribute("data-theme");}a();addEventListener("hashchange",a);})();</script><meta charset="utf-8"><title>StepRow</title></head>
5
+ <body>
6
+ <div class="dn-stage" style="justify-content:center">
7
+ <div class="dn-steps">
8
+ <div class="dn-step dn-step-ok"><svg class="dn-icon dn-glyph" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.5 2.5L16 9.5"/></svg><span class="dn-step-name">读取</span><span class="dn-step-text">周报草稿.md、10 月数据.csv</span><span class="dn-step-meta">0.4 秒</span><svg class="dn-icon dn-chevron" viewBox="0 0 24 24"><path d="M9 6l6 6-6 6"/></svg></div>
9
+ <div class="dn-step dn-step-ok"><svg class="dn-icon dn-glyph" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.5 2.5L16 9.5"/></svg><span class="dn-step-name">计算</span><span class="dn-step-text">订阅转化率 3.1% → 4.4%</span><span class="dn-step-meta">1.2 秒</span><svg class="dn-icon dn-chevron" viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg></div>
10
+ <div class="dn-step-detail">conversions / trials = 88 / 2000 = 4.4%
11
+ 上月 = 62 / 2000 = 3.1%</div>
12
+ <div class="dn-step dn-step-fail"><svg class="dn-icon dn-glyph" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M9 9l6 6M15 9l-6 6"/></svg><span class="dn-step-name">读取</span><span class="dn-step-text">销售日报.xlsx:文件已被移动或删除</span><span class="dn-step-meta">已跳过</span></div>
13
+ <div class="dn-step"><span class="dn-spinner" role="img" aria-label="进行中"></span><span class="dn-step-name">整理</span><span class="dn-step-text">生成三条要点</span><span class="dn-step-meta">3.0 秒</span></div>
14
+ </div>
15
+ </div>
16
+ </body>
17
+ </html>
@@ -0,0 +1,36 @@
1
+ # Tag
2
+
3
+ 一到四个字的标签,标出状态或分类,放在标题旁边或元信息里。
4
+
5
+ **需要提供**:文字、语气(中性 / 强调 / success / warning / danger / info);表示状态时加一个圆点。
6
+
7
+ **规格**
8
+
9
+ - Mac:高 18pt,`radius-xs`,11pt 中粗,左右内边距 6pt。iOS:高 22pt,胶囊形,12pt。
10
+ - 中性标签:`fill-selected` 底、`ink-secondary` 字。强调标签:`accent` 黑底、`on-accent` 白字,只用于「新」「Pro」这类需要跳出来的少数标记。有语气的标签:用对应的 `-soft` 作底色,用语气色作文字和圆点,例如 `success-soft` 底配 `success` 字。
11
+ - 表示状态时一定加 5pt 圆点(`radius-full`),文字本身就要说清楚状态是什么,不能只靠颜色。
12
+
13
+ ```swift
14
+ struct Tag: View {
15
+ var text: LocalizedStringKey
16
+ var tone: Color = .inkSecondary
17
+ var background: Color = .fillSelected
18
+ var showsDot = false
19
+
20
+ var body: some View {
21
+ HStack(spacing: 4) {
22
+ if showsDot { Circle().frame(width: 5, height: 5) }
23
+ Text(text)
24
+ }
25
+ .font(.caption.weight(.medium))
26
+ .foregroundStyle(tone)
27
+ .padding(.horizontal, 6)
28
+ .frame(height: 18)
29
+ .background(background, in: .rect(cornerRadius: 4))
30
+ }
31
+ }
32
+
33
+ Tag(text: "已同步", tone: .success, background: .successSoft, showsDot: true)
34
+ ```
35
+
36
+ **不要**:用标签当按钮;一行里放超过三个标签;大量使用黑底强调标签(它和主按钮长得像,多了就分不清)。
@@ -0,0 +1,22 @@
1
+ <!-- @dsCard group="Feedback" height=120 subtitle="状态与分类" -->
2
+ <!doctype html>
3
+ <html lang="zh-CN">
4
+ <head><link rel="stylesheet" href="../../tokens.css"><link rel="stylesheet" href="../bundle.css"><script>(function(){function a(){var t=location.hash.slice(1),r=document.documentElement;if(t==="light"||t==="dark")r.setAttribute("data-theme",t);else r.removeAttribute("data-theme");}a();addEventListener("hashchange",a);})();</script><meta charset="utf-8"><title>Tag</title></head>
5
+ <body>
6
+ <div class="dn-stage dn-stack" style="align-items:flex-start">
7
+ <div class="dn-row">
8
+ <span class="dn-tag">草稿</span>
9
+ <span class="dn-tag dn-tag-accent">新功能</span>
10
+ <span class="dn-tag dn-tag-success"><span class="dn-dot"></span>已同步</span>
11
+ <span class="dn-tag dn-tag-warning"><span class="dn-dot"></span>额度剩余 10%</span>
12
+ <span class="dn-tag dn-tag-danger"><span class="dn-dot"></span>同步失败</span>
13
+ <span class="dn-tag dn-tag-info">Beta</span>
14
+ </div>
15
+ <div class="dn-row">
16
+ <span class="dn-tag dn-tag-ios">工作</span>
17
+ <span class="dn-tag dn-tag-ios dn-tag-success"><span class="dn-dot"></span>已完成</span>
18
+ <span class="dn-tag dn-tag-ios dn-tag-accent">全家桶</span>
19
+ </div>
20
+ </div>
21
+ </body>
22
+ </html>
@@ -0,0 +1,29 @@
1
+ # TextField
2
+
3
+ 单行文字输入,配一个标签和一句说明。
4
+
5
+ **需要提供**:标签(名词)、绑定的文本、可选的占位符(给示例,不要重复标签)、说明文字,校验失败时提供错误信息。
6
+
7
+ **规格**
8
+
9
+ - 底色 `surface-raised`,边框 `stroke-control` 宽、`line-control` 色。Mac 用 `radius-sm`,高 `control-mac`;iOS 用 `radius-md`,高 `control-ios`。
10
+ - 聚焦时边框变 `focus-ring`,外圈加 3pt 的 `accent-soft` 灰色光晕。
11
+ - 出错时边框变 `danger`,说明文字换成错误信息,同样用 `danger` 色。错误信息要说清楚怎么改。
12
+ - 标签 12pt 中粗 `ink-secondary`,放在输入框上方;说明 11pt `ink-tertiary`,放在下方。
13
+
14
+ ```swift
15
+ VStack(alignment: .leading, spacing: 6) {
16
+ Text("邮箱").font(.caption.weight(.medium)).foregroundStyle(.inkSecondary)
17
+ TextField("name@example.com", text: $email)
18
+ .textFieldStyle(.roundedBorder) // Mac;iOS 用自定义样式实现上面的规格
19
+ .textContentType(.emailAddress)
20
+ .keyboardType(.emailAddress) // iOS
21
+ Text(error ?? "用于接收登录验证码。")
22
+ .font(.caption)
23
+ .foregroundStyle(error == nil ? .inkTertiary : .danger)
24
+ }
25
+ ```
26
+
27
+ iOS 设置页这类表单,直接在 `Form` 里用 `TextField`,交给系统的分组样式(见 ListGroup)。
28
+
29
+ **不要**:只用占位符代替标签;出错时只把边框变红、不给说明;把多行输入塞进单行框(多行用 `TextField(axis: .vertical)` 或 Composer)。
@@ -0,0 +1,28 @@
1
+ <!-- @dsCard group="Input" height=180 subtitle="单行输入" -->
2
+ <!doctype html>
3
+ <html lang="zh-CN">
4
+ <head><link rel="stylesheet" href="../../tokens.css"><link rel="stylesheet" href="../bundle.css"><script>(function(){function a(){var t=location.hash.slice(1),r=document.documentElement;if(t==="light"||t==="dark")r.setAttribute("data-theme",t);else r.removeAttribute("data-theme");}a();addEventListener("hashchange",a);})();</script><meta charset="utf-8"><title>TextField</title></head>
5
+ <body>
6
+ <div class="dn-stage" style="align-items:flex-start;gap:var(--space-5)">
7
+ <div class="dn-field">
8
+ <label for="f1">名称</label>
9
+ <input id="f1" class="dn-input" placeholder="例如:读书摘录">
10
+ <span class="dn-help">会显示在侧边栏里。</span>
11
+ </div>
12
+ <div class="dn-field">
13
+ <label for="f2">邮箱</label>
14
+ <input id="f2" class="dn-input is-focus" value="hello@paperlight.app">
15
+ <span class="dn-help">用于接收登录验证码。</span>
16
+ </div>
17
+ <div class="dn-field">
18
+ <label for="f3">验证码</label>
19
+ <input id="f3" class="dn-input is-error" value="12 34">
20
+ <span class="dn-help is-error">验证码是 6 位数字,请检查后重新输入。</span>
21
+ </div>
22
+ <div class="dn-field" style="width:300px">
23
+ <label for="f4">iOS · 44pt</label>
24
+ <input id="f4" class="dn-input dn-input-ios" placeholder="搜索笔记">
25
+ </div>
26
+ </div>
27
+ </body>
28
+ </html>
@@ -0,0 +1,189 @@
1
+ /* Deernova: web approximations of the SwiftUI components, used by the previews */
2
+ * { box-sizing: border-box; }
3
+ html, body { margin: 0; }
4
+ body { font-family: var(--font-sans); font-size: 13px; line-height: 18px; background: var(--canvas); color: var(--ink); -webkit-font-smoothing: antialiased; }
5
+
6
+ .dn-stage { padding: var(--space-4); display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
7
+ .dn-stack { display: flex; flex-direction: column; gap: var(--space-2); }
8
+ .dn-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
9
+ .dn-note { font-size: 11px; line-height: 13px; color: var(--ink-tertiary); }
10
+ .dn-icon { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
11
+
12
+ /* Button */
13
+ .dn-btn { appearance: none; display: inline-flex; align-items: center; justify-content: center; gap: 5px; height: var(--control-mac); padding: 0 var(--space-3); font: inherit; font-size: 13px; font-weight: 500; line-height: 1; white-space: nowrap; border-radius: var(--radius-sm); border: var(--stroke-hairline) solid var(--line); background: var(--surface-raised); color: var(--ink); box-shadow: var(--shadow-control); cursor: pointer; }
14
+ .dn-btn:hover { background: var(--surface); }
15
+ .dn-btn:focus-visible, .dn-btn.is-focus { outline: var(--stroke-focus) solid var(--focus-ring); outline-offset: 2px; }
16
+ .dn-btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
17
+ .dn-btn-primary:hover { background: var(--accent); opacity: 0.88; }
18
+ .dn-btn-plain { background: transparent; border-color: transparent; box-shadow: none; color: var(--ink-secondary); }
19
+ .dn-btn-plain:hover { background: var(--fill-hover); color: var(--ink); }
20
+ .dn-btn-danger { background: var(--danger-soft); border-color: transparent; box-shadow: none; color: var(--danger); }
21
+ .dn-btn-danger:hover { background: var(--danger-soft); filter: brightness(0.97); }
22
+ .dn-btn-sm { height: var(--control-mac-sm); padding: 0 var(--space-2); font-size: 11px; border-radius: var(--radius-xs); }
23
+ .dn-btn-lg { height: var(--control-mac-lg); padding: 0 var(--space-4); }
24
+ .dn-btn-ios { height: var(--button-ios); padding: 0 var(--space-4); font-size: 15px; font-weight: 600; border-radius: var(--radius-full); }
25
+ .dn-btn-ios-sm { height: var(--button-ios-sm); padding: 0 var(--space-3); font-size: 13px; font-weight: 600; border-radius: var(--radius-full); }
26
+ .dn-btn-ios-lg { height: var(--control-ios-lg); width: 100%; padding: 0 var(--space-5); font-size: 16px; font-weight: 600; border-radius: var(--radius-full); }
27
+ .dn-btn[disabled] { opacity: 0.35; cursor: default; filter: none; }
28
+ .dn-btn .dn-icon { width: 13px; height: 13px; }
29
+
30
+ .dn-iconbtn { appearance: none; width: var(--control-mac); height: var(--control-mac); padding: 0; border-radius: var(--radius-sm); border: 0; background: transparent; color: var(--ink-secondary); display: inline-grid; place-items: center; cursor: pointer; flex: none; }
31
+ .dn-iconbtn:hover { background: var(--fill-hover); color: var(--ink); }
32
+ .dn-iconbtn:focus-visible { outline: var(--stroke-focus) solid var(--focus-ring); outline-offset: 1px; }
33
+
34
+ /* Glass: web approximation of .glassEffect() */
35
+ .dn-backdrop { position: relative; overflow: hidden; background: var(--surface); }
36
+ .dn-glass { background: var(--glass-fill); -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4); border: var(--stroke-hairline) solid var(--glass-stroke); box-shadow: var(--shadow-glass); border-radius: var(--radius-full); }
37
+ .dn-glass-btn { appearance: none; width: var(--control-ios); height: var(--control-ios); padding: 0; display: inline-grid; place-items: center; color: var(--ink); cursor: pointer; font: inherit; flex: none; }
38
+ .dn-glass-btn .dn-icon { width: 19px; height: 19px; }
39
+ .dn-glass-prominent { background: var(--accent); color: var(--on-accent); border-color: transparent; }
40
+ .dn-glass-group { display: inline-flex; align-items: center; gap: 2px; padding: 3px; }
41
+ .dn-glass-group .dn-glass-btn { background: transparent; border: 0; box-shadow: none; width: 36px; height: 36px; border-radius: var(--radius-full); color: var(--ink-secondary); }
42
+ .dn-glass-group .dn-glass-btn.is-selected { background: var(--fill-selected); color: var(--ink); }
43
+ .dn-glass-pill { height: 40px; padding: 0 var(--space-4); display: inline-flex; align-items: center; gap: var(--space-2); font-size: 14px; font-weight: 500; color: var(--ink); }
44
+
45
+ /* Segmented */
46
+ .dn-seg { display: inline-flex; padding: 2px; gap: 2px; background: var(--fill-selected); border-radius: var(--radius-sm); }
47
+ .dn-seg button { appearance: none; border: 0; font: inherit; font-size: 12px; font-weight: 500; height: var(--control-mac-sm); padding: 0 var(--space-3); border-radius: var(--radius-xs); background: transparent; color: var(--ink-secondary); cursor: pointer; }
48
+ .dn-seg button[aria-pressed="true"] { background: var(--surface-raised); color: var(--ink); box-shadow: var(--shadow-control); }
49
+ .dn-seg-ios { padding: 2px; border-radius: var(--radius-full); }
50
+ .dn-seg-ios button { height: 30px; padding: 0 var(--space-4); font-size: 14px; border-radius: var(--radius-full); }
51
+
52
+ /* Text field */
53
+ .dn-field { display: flex; flex-direction: column; gap: 4px; width: 240px; max-width: 100%; }
54
+ .dn-field label { font-size: 12px; line-height: 16px; font-weight: 500; color: var(--ink-secondary); }
55
+ .dn-input { height: var(--control-mac); padding: 0 var(--space-2); font: inherit; font-size: 13px; color: var(--ink); background: var(--surface-raised); border: var(--stroke-control) solid var(--line-control); border-radius: var(--radius-sm); outline: none; width: 100%; }
56
+ .dn-input::placeholder { color: var(--ink-tertiary); }
57
+ .dn-input:focus, .dn-input.is-focus { border-color: var(--focus-ring); box-shadow: 0 0 0 3px var(--accent-soft); }
58
+ .dn-input.is-error { border-color: var(--danger); }
59
+ .dn-input-ios { height: var(--control-ios); padding: 0 var(--space-3); font-size: 17px; border-radius: var(--radius-md); }
60
+ .dn-help { font-size: 11px; line-height: 13px; color: var(--ink-tertiary); }
61
+ .dn-help.is-error { color: var(--danger); }
62
+
63
+ /* Composer */
64
+ .dn-composer { width: 100%; max-width: 560px; background: var(--surface-raised); border: var(--stroke-hairline) solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-float); padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3); display: flex; flex-direction: column; gap: var(--space-1); }
65
+ .dn-composer textarea { border: 0; outline: none; resize: none; background: transparent; font: inherit; font-size: 13px; line-height: 18px; color: var(--ink); min-height: 36px; padding: 2px 0; width: 100%; }
66
+ .dn-composer textarea::placeholder { color: var(--ink-tertiary); }
67
+ .dn-composer:focus-within { border-color: var(--line-control); }
68
+ .dn-composer-bar { display: flex; align-items: center; gap: var(--space-1); margin-left: -4px; }
69
+ .dn-spacer { flex: 1; }
70
+ .dn-chip { display: inline-flex; align-items: center; gap: 3px; height: var(--control-mac-sm); padding: 0 var(--space-2); border-radius: var(--radius-full); font: inherit; font-size: 11px; color: var(--ink-secondary); background: transparent; border: var(--stroke-hairline) solid var(--line); cursor: pointer; white-space: nowrap; }
71
+ .dn-chip .dn-icon { width: 11px; height: 11px; }
72
+ .dn-send { appearance: none; width: var(--control-mac); height: var(--control-mac); padding: 0; border-radius: var(--radius-full); border: 0; display: grid; place-items: center; background: var(--accent); color: var(--on-accent); cursor: pointer; flex: none; }
73
+ .dn-send .dn-icon { width: 13px; height: 13px; stroke-width: 2.2; }
74
+ .dn-send[disabled] { background: var(--fill-selected); color: var(--ink-tertiary); cursor: default; }
75
+ .dn-attach { display: inline-flex; align-items: center; gap: 5px; height: var(--control-mac); padding: 0 var(--space-2); border-radius: var(--radius-sm); background: var(--surface-sunken); font-size: 12px; color: var(--ink-secondary); align-self: flex-start; }
76
+
77
+ /* Sidebar (macOS) */
78
+ .dn-sidebar { width: var(--sidebar-mac); background: var(--surface-sunken); border: var(--stroke-hairline) solid var(--line); border-radius: var(--radius-lg); padding: 6px; display: flex; flex-direction: column; gap: 1px; }
79
+ .dn-side-head { font-size: 11px; line-height: 13px; font-weight: 600; color: var(--ink-tertiary); padding: var(--space-3) var(--space-2) var(--space-1); }
80
+ .dn-side-item { display: flex; align-items: center; gap: 7px; height: var(--row-mac); padding: 0 var(--space-2); border-radius: var(--radius-sm); font-size: 13px; color: var(--ink); cursor: default; min-width: 0; }
81
+ .dn-side-item .dn-icon { width: 14px; height: 14px; color: var(--ink-secondary); }
82
+ .dn-side-item:hover { background: var(--fill-hover); }
83
+ .dn-side-item.is-selected { background: var(--fill-selected); font-weight: 500; }
84
+ .dn-side-item.is-selected .dn-icon { color: var(--ink); }
85
+ .dn-side-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
86
+ .dn-count { margin-left: auto; font-size: 11px; color: var(--ink-tertiary); font-variant-numeric: tabular-nums; }
87
+
88
+ /* List group (iOS inset grouped) */
89
+ .dn-listwrap { background: var(--canvas); padding: var(--space-4); width: 375px; max-width: 100%; display: flex; flex-direction: column; }
90
+ .dn-list-head { font-size: 13px; line-height: 17px; color: var(--ink-secondary); padding: 0 var(--space-4) 6px; }
91
+ .dn-list { background: var(--surface-raised); border-radius: var(--radius-lg); overflow: hidden; }
92
+ .dn-list-row { --sep-inset: var(--space-4); display: flex; align-items: center; gap: var(--space-3); min-height: var(--control-ios); padding: 0 var(--space-4); font-size: 17px; line-height: 22px; color: var(--ink); position: relative; }
93
+ .dn-list-row.has-icon { --sep-inset: 56px; }
94
+ .dn-list-row + .dn-list-row::before { content: ""; position: absolute; top: 0; left: var(--sep-inset); right: 0; border-top: var(--stroke-hairline) solid var(--line); }
95
+ .dn-list-icon { width: 28px; height: 28px; border-radius: var(--radius-sm); display: grid; place-items: center; background: var(--accent-soft); color: var(--ink); flex: none; }
96
+ .dn-list-icon .dn-icon { width: 16px; height: 16px; }
97
+ .dn-list-value { margin-left: auto; color: var(--ink-secondary); white-space: nowrap; }
98
+ .dn-chevron { color: var(--ink-tertiary); width: 13px; height: 13px; }
99
+ .dn-list-foot { font-size: 13px; line-height: 17px; color: var(--ink-tertiary); padding: 6px var(--space-4) 0; }
100
+ .dn-switch { margin-left: auto; width: 51px; height: 31px; border-radius: var(--radius-full); background: var(--success); position: relative; flex: none; }
101
+ .dn-switch::after { content: ""; position: absolute; top: 2px; right: 2px; width: 27px; height: 27px; border-radius: var(--radius-full); background: var(--knob); box-shadow: var(--shadow-control); }
102
+ .dn-switch.is-off { background: var(--fill-selected); }
103
+ .dn-switch.is-off::after { right: auto; left: 2px; }
104
+
105
+ /* Card */
106
+ .dn-card { background: var(--surface); border: var(--stroke-hairline) solid var(--line); border-radius: var(--radius-md); padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-1); width: 240px; max-width: 100%; }
107
+ .dn-card-title { font-family: var(--font-serif); font-size: 15px; line-height: 20px; font-weight: 600; color: var(--ink); margin: 0; }
108
+ .dn-card-body { font-size: 12px; line-height: 17px; color: var(--ink-secondary); margin: 0; }
109
+ .dn-card-meta { font-size: 11px; line-height: 13px; color: var(--ink-tertiary); display: flex; gap: 6px; align-items: center; margin-top: 2px; font-variant-numeric: tabular-nums; }
110
+ .dn-card.is-interactive { cursor: pointer; }
111
+ .dn-card.is-interactive:hover { border-color: var(--line-control); }
112
+ .dn-card.is-selected { border-color: var(--accent); box-shadow: inset 0 0 0 0.5px var(--accent); }
113
+
114
+ /* Tag */
115
+ .dn-tag { display: inline-flex; align-items: center; gap: 4px; height: 18px; padding: 0 6px; border-radius: var(--radius-xs); font-size: 11px; font-weight: 500; line-height: 1; white-space: nowrap; background: var(--fill-selected); color: var(--ink-secondary); }
116
+ .dn-tag-accent { background: var(--accent); color: var(--on-accent); }
117
+ .dn-tag-success { background: var(--success-soft); color: var(--success); }
118
+ .dn-tag-warning { background: var(--warning-soft); color: var(--warning); }
119
+ .dn-tag-danger { background: var(--danger-soft); color: var(--danger); }
120
+ .dn-tag-info { background: var(--info-soft); color: var(--info); }
121
+ .dn-dot { width: 5px; height: 5px; border-radius: var(--radius-full); background: currentColor; flex: none; }
122
+ .dn-tag-ios { height: 22px; padding: 0 var(--space-2); font-size: 12px; border-radius: var(--radius-full); }
123
+
124
+ /* Banner and toast */
125
+ .dn-banner { display: flex; gap: 10px; align-items: flex-start; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--surface-raised); border: var(--stroke-hairline) solid var(--line); width: 100%; max-width: 520px; }
126
+ .dn-banner > .dn-icon { width: 16px; height: 16px; margin-top: 1px; color: var(--ink-secondary); }
127
+ .dn-banner-text { flex: 1; min-width: 0; }
128
+ .dn-banner-title { font-size: 13px; line-height: 18px; font-weight: 600; color: var(--ink); margin: 0; }
129
+ .dn-banner-body { font-size: 12px; line-height: 17px; color: var(--ink-secondary); margin: 0; }
130
+ .dn-banner-success { background: var(--success-soft); border-color: transparent; }
131
+ .dn-banner-success > .dn-icon { color: var(--success); }
132
+ .dn-banner-warning { background: var(--warning-soft); border-color: transparent; }
133
+ .dn-banner-warning > .dn-icon { color: var(--warning); }
134
+ .dn-banner-danger { background: var(--danger-soft); border-color: transparent; }
135
+ .dn-banner-danger > .dn-icon { color: var(--danger); }
136
+ .dn-toast { display: inline-flex; align-items: center; gap: var(--space-2); height: 40px; padding: 0 var(--space-4) 0 var(--space-3); font-size: 14px; font-weight: 500; color: var(--ink); }
137
+ .dn-toast .dn-icon { width: 16px; height: 16px; color: var(--success); }
138
+
139
+ /* Message */
140
+ .dn-thread { display: flex; flex-direction: column; gap: var(--space-4); width: 100%; max-width: 600px; }
141
+ .dn-msg-user { align-self: flex-end; max-width: 80%; background: var(--surface-sunken); border-radius: var(--radius-lg); padding: 6px var(--space-3); font-size: 13px; line-height: 18px; color: var(--ink); }
142
+ .dn-msg-assistant { font-family: var(--font-serif); font-size: 14px; line-height: 22px; color: var(--ink); }
143
+ .dn-msg-assistant p { margin: 0 0 var(--space-2); }
144
+ .dn-msg-assistant p:last-of-type { margin-bottom: 0; }
145
+ .dn-msg-assistant strong { font-weight: 600; }
146
+ .dn-msg-assistant a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; text-decoration-color: var(--line-control); }
147
+ .dn-msg-actions { display: flex; gap: 2px; margin-top: var(--space-1); margin-left: -5px; }
148
+ .dn-msg-actions .dn-iconbtn { width: 22px; height: 22px; color: var(--ink-tertiary); }
149
+ .dn-msg-actions .dn-icon { width: 13px; height: 13px; }
150
+
151
+ /* Code block */
152
+ .dn-code { background: var(--surface-sunken); border: var(--stroke-hairline) solid var(--line); border-radius: var(--radius-md); overflow: hidden; width: 100%; max-width: 560px; }
153
+ .dn-code-head { display: flex; align-items: center; height: 28px; padding: 0 var(--space-1) 0 var(--space-3); border-bottom: var(--stroke-hairline) solid var(--line); font-family: var(--font-mono); font-size: 11px; color: var(--ink-tertiary); }
154
+ .dn-code-head .dn-btn { margin-left: auto; }
155
+ .dn-code pre { margin: 0; padding: var(--space-2) var(--space-3); overflow-x: auto; font-family: var(--font-mono); font-size: 12px; line-height: 17px; color: var(--ink); }
156
+ .tk-kw { color: var(--ink); font-weight: 600; }
157
+ .tk-str { color: var(--ink-secondary); }
158
+ .tk-num { color: var(--ink); }
159
+ .tk-com { color: var(--ink-tertiary); font-style: italic; }
160
+ .tk-type { color: var(--ink); }
161
+
162
+ /* Step row */
163
+ .dn-steps { display: flex; flex-direction: column; width: 100%; max-width: 560px; }
164
+ .dn-step { display: flex; align-items: center; gap: 7px; height: var(--control-mac); padding: 0 6px; border-radius: var(--radius-sm); font-size: 12px; color: var(--ink-secondary); cursor: default; min-width: 0; }
165
+ .dn-step:hover { background: var(--fill-hover); }
166
+ .dn-step .dn-icon { width: 14px; height: 14px; }
167
+ .dn-step-name { font-weight: 600; color: var(--ink); white-space: nowrap; }
168
+ .dn-step-text { font-family: var(--font-mono); font-size: 11px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
169
+ .dn-step-meta { margin-left: auto; padding-left: var(--space-2); font-size: 11px; color: var(--ink-tertiary); font-variant-numeric: tabular-nums; white-space: nowrap; }
170
+ .dn-step-ok .dn-glyph { color: var(--success); }
171
+ .dn-step-fail .dn-glyph { color: var(--danger); }
172
+ .dn-step .dn-chevron { color: var(--ink-tertiary); width: 11px; height: 11px; }
173
+ .dn-step-detail { margin: 2px 0 6px 27px; padding: 6px var(--space-2); background: var(--surface-sunken); border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: 11px; line-height: 16px; color: var(--ink-secondary); white-space: pre-wrap; }
174
+ .dn-spinner { width: 13px; height: 13px; border-radius: var(--radius-full); border: 2px solid var(--line); border-top-color: var(--ink); animation: dn-spin 0.9s linear infinite; flex: none; }
175
+ @keyframes dn-spin { to { transform: rotate(360deg); } }
176
+ @media (prefers-reduced-motion: reduce) { .dn-spinner { animation-duration: 2.4s; } }
177
+
178
+ /* Empty state */
179
+ .dn-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-1); padding: var(--space-6) var(--space-5); }
180
+ .dn-empty > .dn-icon { width: 28px; height: 28px; color: var(--ink-tertiary); stroke-width: 1.4; }
181
+ .dn-empty h2 { font-family: var(--font-serif); font-size: 22px; line-height: 28px; font-weight: 600; letter-spacing: -0.01em; margin: var(--space-2) 0 0; color: var(--ink); }
182
+ .dn-empty p { margin: 0 0 var(--space-3); max-width: 320px; color: var(--ink-secondary); font-size: 13px; line-height: 18px; }
183
+
184
+ /* Sheet (iOS) */
185
+ .dn-sheet { width: 359px; max-width: 100%; border-radius: var(--radius-xl); padding: var(--space-2) var(--space-5) var(--space-5); }
186
+ .dn-grabber { width: 36px; height: 5px; border-radius: var(--radius-full); background: var(--line-control); margin: 0 auto var(--space-3); }
187
+ .dn-sheet h3 { font-family: var(--font-serif); font-size: 20px; line-height: 25px; font-weight: 600; margin: 0 0 var(--space-1); color: var(--ink); }
188
+ .dn-sheet p { font-size: 15px; line-height: 20px; color: var(--ink-secondary); margin: 0 0 var(--space-4); }
189
+ .dn-sheet .dn-stack { gap: var(--space-1); }
@@ -0,0 +1,25 @@
1
+ {
2
+ "v": 3,
3
+ "assetGroups": {},
4
+ "blobs": {},
5
+ "createdOnFiles": {
6
+ "at": "2026-10-31T17:19:19Z",
7
+ "v": 1
8
+ },
9
+ "docs": {
10
+ "readme": "project/README.md",
11
+ "sections": []
12
+ },
13
+ "groups": [],
14
+ "lastChange": {
15
+ "by": "Claude",
16
+ "via": "Claude Code",
17
+ "at": "2026-11-01T13:33:31Z",
18
+ "note": "修正 Composer、TextField、MacWindow、Button 预览被裁掉底部的问题。"
19
+ },
20
+ "layout": "files",
21
+ "libraries": [],
22
+ "namespace": "Deernova",
23
+ "sections": {},
24
+ "title": "Deernova"
25
+ }