@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,170 @@
1
+ Deernova 是给 macOS 和 iOS 应用用的一套设计语言:只用黑、白、灰。纸面承载内容,液态玻璃(Liquid Glass)承载操作,强调靠明暗对比,不靠彩色。整体紧凑、安静、克制,像一件趁手的工具。
2
+
3
+ ## 原则
4
+
5
+ 1. **纸面与玻璃分层。** 文字、列表、卡片、代码这些内容,放在不透明的纸面上:`canvas`、`surface`、`surface-raised`、`surface-sunken`。工具栏、标签栏、浮动按钮、弹出层这些操作,浮在内容之上,用系统的 Liquid Glass。玻璃上不放内容,内容也不做成玻璃。
6
+ 2. **黑白灰,强调靠对比。** `accent` 就是墨色本身:浅色主题下主按钮是黑底白字,深色主题下是白底黑字。界面里唯一的彩色是状态色(成功、警告、错误、提示),只在表达状态时出现。
7
+ 3. **用线条代替阴影。** 区块之间用 `line` 细线分隔(`stroke-hairline`)。只有真正浮起来的东西(菜单、弹窗、浮动面板)才加阴影 `shadow-float`。
8
+ 4. **衬线用来"说",无衬线用来"做"。** 标题、空状态、长文阅读(文章、AI 回答)用衬线 `--font-serif`;按钮、标签、列表、表单这些界面文字,用系统无衬线 `--font-sans`。
9
+ 5. **紧凑。** Mac 正文 13pt、行高约 1.4 倍,控件 24pt、列表行 26pt;靠细线和少量留白分组,不靠大块空白。iOS 保留系统的 17pt 正文和 44pt 点击区域,但按钮看起来只有 36pt。
10
+ 6. **原生优先。** 系统已有的控件(Toggle、Picker、Menu、DatePicker、Alert)直接用,只通过 `tint` 和字体让它们融入。自定义组件只做系统没有的东西:Composer、Message、StepRow。
11
+
12
+ ## 文案
13
+
14
+ - 用"你"称呼用户。语气平实直接,不用感叹号,不用 emoji。
15
+ - 按钮以动词开头,说清点了会发生什么:「保存」「新建笔记」「删除 3 个文件」。不用「确定」「OK」。操作完成后的提示用完成态:「已保存」「已复制」。
16
+ - 错误提示要说明出了什么问题、怎么解决:「网络连接已断开,恢复后会自动重试。」不道歉,不含糊。
17
+ - 中文与英文、中文与数字之间加一个半角空格:「同步到 iCloud」「剩余 12 次」。数字和单位用半角。
18
+ - 标题、按钮、标签不加句号;完整的句子加句号。
19
+ - 空状态写法:标题说明现在的状态,正文告诉用户下一步做什么。例如「还没有笔记」/「写下第一条想法,它会同步到你所有的设备。」
20
+
21
+ ## 颜色
22
+
23
+ 所有颜色都是语义 token,分 Light 和 Dark 两套主题,两套都验算过对比度。灰阶全部是中性灰,不偏暖也不偏冷。
24
+
25
+ - **纸面层级**,从下到上:窗口底色 `canvas` → 内容区和卡片 `surface` → 输入框、Composer、弹出层 `surface-raised`。代码块、用户消息气泡、展开的详情用 `surface-sunken`。
26
+ - **文字**:正文用 `ink`,次要信息用 `ink-secondary`,占位符、时间戳、计数用 `ink-tertiary`。三者在四种纸面上都不低于 4.5:1。
27
+ - **线条**:分隔线和卡片描边用 `line`,属于装饰。输入框边框用 `line-control`,不低于 3:1,让人看得出这里可以输入。
28
+ - **强调**:`accent` 等于 `ink`,用于主按钮填充、选中指示、焦点环。主按钮上的文字用 `on-accent`,不要写死白色,深色主题下它是黑色。浅灰强调底用 `accent-soft`,上面的文字用 `ink`。链接用 `ink` 加下划线,不用彩色。
29
+ - **焦点**:`focus-ring` 等于 `accent`,2pt 实线,外偏移 2pt。
30
+ - **状态色**:`success`(青绿)、`warning`(赭黄)、`danger`(莓红)、`info`(蓝),各自配一个 `-soft` 浅底。这是界面里仅有的彩色,只用在状态上,不拿来装饰。状态必须同时带图标或文字,不能只靠颜色区分。`success` 特意偏青,和 `danger` 拉开距离,色弱用户也能分辨。开关打开时用 `success`,因为黑白开关在深色主题下看不清圆钮。
31
+ - **交互底色**:悬停用 `fill-hover`,选中用 `fill-selected`。它们是半透明的,叠在任何纸面上都成立。
32
+ - **仅限网页预览**:`glass-fill`、`glass-stroke`、`shadow-glass` 只是在网页里模拟玻璃效果。App 里一律用系统的 `.glassEffect()`,不要用这些值自己画玻璃。
33
+
34
+ 在 SwiftUI 里落地:在 Asset Catalog 里按 token 名建 Color Set,分别填入 Any 和 Dark 两套值,再写一个扩展来引用。扩展写在 `ShapeStyle` 上,这样 `.foregroundStyle(.inkSecondary)`、`.background(.surface, in: …)` 都能直接用点语法。组件说明里的代码都按这套命名书写:
35
+
36
+ ```swift
37
+ extension ShapeStyle where Self == Color {
38
+ static var canvas: Color { Color("canvas") }
39
+ static var surface: Color { Color("surface") }
40
+ static var surfaceRaised: Color { Color("surface-raised") }
41
+ static var surfaceSunken: Color { Color("surface-sunken") }
42
+ static var ink: Color { Color("ink") }
43
+ static var inkSecondary: Color { Color("ink-secondary") }
44
+ static var inkTertiary: Color { Color("ink-tertiary") }
45
+ static var line: Color { Color("line") }
46
+ static var brandAccent: Color { Color("accent") } // 等于 ink;避开系统的 .accentColor
47
+ // success、successSoft、warning、danger、fillSelected 等其余 token 同理
48
+ }
49
+
50
+ // 在 App 入口统一着色,系统控件会自动跟随(按钮、选中态变成黑 / 白)
51
+ WindowGroup {
52
+ RootView().tint(.brandAccent)
53
+ }
54
+ // 开关单独着色
55
+ Toggle("iCloud 同步", isOn: $sync).tint(.success)
56
+ ```
57
+
58
+ ## 字体
59
+
60
+ 全部使用系统字体,不打包字体文件:App 体积不增加,也自动支持动态字体(Dynamic Type)。
61
+
62
+ | 角色 | 西文 | 中文 | SwiftUI |
63
+ | --- | --- | --- | --- |
64
+ | 衬线:标题、长文 | New York | 苹方 | `.system(.title, design: .serif)` |
65
+ | 无衬线:界面 | SF Pro | 苹方 | `.body`、`.headline` 等 |
66
+ | 等宽:代码、数据 | SF Mono | 苹方 | `.system(.body, design: .monospaced)` |
67
+
68
+ - macOS 和 iOS 各有一套字号,见 Typography。Mac 正文 13pt、行高 18(`mac-body`),长文 14pt、行高 22(`mac-prose`);iOS 正文 17pt、行高 23(`ios-body`)。
69
+ - iOS 一律用文本样式(`.body`、`.headline`),不要写死字号,这样动态字体才会生效。需要衬线时用 `.system(.title2, design: .serif)` 这种写法,同样能随系统缩放。
70
+ - 界面文字行高约为字号的 1.4 倍;长文阅读放宽到 1.5–1.6 倍,中文读起来不挤。
71
+ - 如果想让中文标题也有衬线的气质,可以打包思源宋体(Source Han Serif,开源可商用)的子集,只用在大标题和营销页上。界面文字始终用苹方。
72
+ - 需要上下对齐的数字(计数、价格、时间)用等宽数字:`.monospacedDigit()`。
73
+
74
+ ## 间距与尺寸
75
+
76
+ - 采用 4pt 网格:`space-1`(4)、`space-2`(8)、`space-3`(12)、`space-4`(16)、`space-5`(20)、`space-6`(24)、`space-8`(32)、`space-10`(40)。日常布局基本只用到 `space-1` 到 `space-4`。
77
+ - **macOS 紧凑**:控件高 `control-mac`(24),侧边栏和列表行 `row-mac`(26),内容区边距 `space-4`,卡片内边距 `space-3`,消息之间 `space-4`,侧边栏宽 `sidebar-mac`(220)。
78
+ - **iOS**:可点区域至少 `control-ios`(44)。按钮的可见高度:默认 `button-ios`(36),小号 `button-ios-sm`(30),通栏主按钮 `control-ios-lg`(46)。页面左右边距 `space-4`,卡片之间 `space-2`,分组之间 `space-5`。
79
+ - 长文阅读的栏宽不超过 `content-max`(680),14pt 下大约每行 45 个汉字。
80
+ - 组与组之间的间距至少是组内间距的 2 倍。层次靠间距建立,不靠加更多的线和框。
81
+
82
+ ## 圆角
83
+
84
+ - `radius-xs`(4):标签、复选框。
85
+ - `radius-sm`(6):Mac 按钮、输入框、侧边栏选中块。
86
+ - `radius-md`(8):Mac 卡片、横幅、代码块、菜单。
87
+ - `radius-lg`(12):iOS 卡片、分组列表、Composer、消息气泡、Mac 侧边栏面板。
88
+ - `radius-xl`(24):iOS 底部弹窗、单行 Composer。
89
+ - `radius-full`:胶囊和圆形,用于玻璃按钮、iOS 主按钮、发送按钮。
90
+ - 嵌套时保持同心:内圆角 = 外圆角 − 内边距。iOS 26 / macOS 26 起可以直接用 `ConcentricRectangle()`,内层会自动和外层容器同心。
91
+
92
+ ## 线条
93
+
94
+ - `stroke-hairline`:1 个物理像素,在 Retina 屏上是 0.5pt,用于分隔线和卡片描边。SwiftUI 里写成 `1 / displayScale`,`displayScale` 从 `@Environment(\.displayScale)` 读取。
95
+ - `stroke-control`:1pt,用于输入框边框。
96
+ - `stroke-focus`:2pt,用于焦点环。
97
+ - 列表分隔线从文字起点开始,不贯穿到左边缘。
98
+
99
+ ## 层级与阴影
100
+
101
+ 从下到上分三层:
102
+
103
+ 1. 纸面:`canvas` 和 `surface`。
104
+ 2. 用细线分隔的内容块:没有阴影。
105
+ 3. 浮层:玻璃控件、菜单、弹窗,带 `shadow-float` 或系统玻璃自带的阴影。
106
+
107
+ 卡片不加阴影。
108
+
109
+ ## Liquid Glass
110
+
111
+ 目标系统设为 iOS 26+ / macOS 26+,直接用系统 API,不写兼容层。
112
+
113
+ **用玻璃的地方**(大部分由系统自动提供):
114
+
115
+ - 导航栏、工具栏、标签栏、Mac 侧边栏:使用标准的 `NavigationStack`、`NavigationSplitView`、`TabView`、`.toolbar`,系统会自动渲染成玻璃。
116
+ - 浮动操作按钮、浮动工具条:用 `.glassEffect()`。相邻的几个玻璃元素放进同一个 `GlassEffectContainer`,它们会互相融合,切换时也会跟着变形。
117
+ - 底部弹窗、弹出菜单、popover:系统自动处理。
118
+ - 玻璃层上的主操作用 `.buttonStyle(.glassProminent)` 加 `.tint(.brandAccent)`,次要操作用 `.buttonStyle(.glass)`。
119
+
120
+ **不用玻璃的地方**:卡片、列表行、消息、输入框、代码块,以及所有需要长时间阅读的内容。
121
+
122
+ **规则**:
123
+
124
+ - 玻璃上不叠玻璃。
125
+ - 玻璃上只放图标和很短的标签,不放段落。
126
+ - 只有主操作的玻璃才用实色(黑底白图标),一屏最多一个。
127
+ - iOS 上可点击的自定义玻璃加 `.interactive()`,按下时会有形变反馈。
128
+ - 让内容从工具栏下面滚过去,保留系统的滚动边缘效果。不要给工具栏加实色背景。
129
+ - iOS 标签栏在向下滚动时收起:`.tabBarMinimizeBehavior(.onScrollDown)`。
130
+ - Mac 上侧边栏旁边的大图,用 `.backgroundExtensionEffect()` 延伸到侧边栏下方。
131
+ - 用户开启「降低透明度」后,系统会自动把玻璃换成实色。自己写的半透明效果也要读取 `accessibilityReduceTransparency`,并做同样的处理。
132
+
133
+ ```swift
134
+ // 浮动工具条:两个玻璃按钮融合成一组
135
+ GlassEffectContainer(spacing: 12) {
136
+ HStack(spacing: 12) {
137
+ Button("新建", systemImage: "plus") { createNote() }
138
+ .buttonStyle(.glassProminent)
139
+ Button("搜索", systemImage: "magnifyingglass") { search() }
140
+ .buttonStyle(.glass)
141
+ }
142
+ }
143
+ .tint(.brandAccent)
144
+ ```
145
+
146
+ ## 动效
147
+
148
+ - 默认用弹簧动画:`.spring(response: 0.35, dampingFraction: 0.85)`。悬停、按压这类即时反馈用 0.12s,展开、切换用 0.2s,弹窗的动画交给系统。
149
+ - 动效用来说明因果:东西从哪里来、到哪里去。不做装饰性的循环动画。
150
+ - 用户开启「减弱动态效果」(`accessibilityReduceMotion`)后,位移和缩放动画换成淡入淡出。
151
+
152
+ ## 图标
153
+
154
+ - 只用 SF Symbols,和系统保持一致。不用 emoji 当图标。
155
+ - 图标粗细跟随旁边的文字。Mac 上图标 14pt,13pt 文字旁的图标用 `.medium`,看起来更清楚。
156
+ - 默认颜色 `ink-secondary`,选中态和主操作用 `ink`。图标不用彩色,状态图标除外。多层符号用 `.symbolRenderingMode(.hierarchical)`。
157
+ - 状态图标固定为:成功 `checkmark.circle.fill`,警告 `exclamationmark.triangle.fill`,错误 `xmark.octagon.fill`,提示 `info.circle.fill`。
158
+ - 目前还没有品牌标志,界面里先用文字名称。做好标志后,再新增一个 Logos 资产组。
159
+ - 组件预览里的图标是近似 SF Symbols 的线稿,App 里换成对应的 SF Symbols。
160
+
161
+ ## 无障碍
162
+
163
+ - 每个文字 token 在它说明里注明的纸面上不低于 4.5:1,两套主题都验算过。界面紧凑不等于字小:Mac 正文不低于 13pt,说明文字不低于 11pt。
164
+ - iOS 全面支持动态字体,在最大字号下也不截断文字:允许换行,横排放不下就改成竖排。
165
+ - iOS 上每个可点元素的点击区域至少 44×44pt,看起来可以更小(按钮 36pt、小按钮 30pt),差的部分用透明的内边距补足;Mac 上的图标按钮至少 24×24pt。
166
+ - 只靠颜色传达的信息,一律补上图标或文字。
167
+
168
+ ## 组件
169
+
170
+ 组件页里的预览是网页上的近似效果,用来对齐尺寸、颜色和层级。App 里用 SwiftUI 实现,每个组件的说明里都写了对应的 SwiftUI 写法,以及需要传入哪些内容。Layouts 分组里有一个 Mac 窗口示例和一个 iPhone 界面示例,展示各个组件组合在一起的样子。
@@ -0,0 +1,7 @@
1
+ # Apple platform implementation
2
+
3
+ The migrated guide targets iOS 26 / macOS 26 and includes SwiftUI examples. Check the project's actual SDK and deployment target before adopting newer APIs; the guide's target does not authorize changing the application's supported OS range. For older targets, discuss or implement a suitable native fallback within the task scope.
4
+
5
+ Map semantic colors to Asset Catalog Any/Dark sets and ShapeStyle color extensions. Use `brandAccent` to avoid confusing the system accentColor. Prefer NavigationStack, NavigationSplitView, TabView and native toolbar materials. Custom floating actions may use system glass where available; never recreate native glass from CSS values.
6
+
7
+ Use semantic text styles for Dynamic Type on iOS, 44 pt minimum hit areas, displayScale-aware hairlines, monospacedDigit for aligned values, SF Symbols for icons, and environment accessibility settings. Mac dense controls may use the documented 24 pt baseline. SwiftUI examples are implementation guidance, not a compiled native SDK; compile against the target SDK and test interactions and large text.
@@ -0,0 +1,13 @@
1
+ # Review criteria
2
+
3
+ - Hierarchy: opaque readable surfaces, semantic layering, shadows reserved for floating elements.
4
+ - Color: neutral accent; on-accent follows theme; status has text/icon; no decorative status colors.
5
+ - Contrast: measure foreground/background combinations. Normal text target 4.5:1; meaningful control boundaries 3:1. Do not assume an arbitrary pairing passes because individual tokens exist.
6
+ - Type: serif for editorial titles/prose; sans for interaction; tabular figures for comparable data. Preserve readable sizes and wrapping.
7
+ - Layout: 4-unit spacing, platform-appropriate density, concentric nested radii, no clipped essential content.
8
+ - Interaction: focus visibility, keyboard order, actionable labels, loading/error/disabled state semantics, adequate hit areas.
9
+ - Accessibility: test both themes, reduced motion/transparency, text scaling and non-color status cues.
10
+ - Copy: direct Chinese, verb-first action labels, spaces between Chinese and Latin/numbers, concrete recovery guidance.
11
+ - Integration: shared tokens and components, no duplicated literal palette or independent skill drift.
12
+
13
+ Report severity, location, user impact and a specific correction. Distinguish observed failures from unverified concerns. A review does not authorize publishing, broad restyling, or changing deployment targets.
@@ -0,0 +1,74 @@
1
+ ## color
2
+
3
+ - `canvas`: light `#f5f5f5`; dark `#161616`. 窗口底色、iOS 分组列表的底色。最底层的纸面。
4
+ - `surface`: light `#fafafa`; dark `#1c1c1c`. 内容区、卡片。比 canvas 略亮一层。
5
+ - `surface-raised`: light `#ffffff`; dark `#252525`. 输入框、Composer、iOS 分组列表、弹出层。最亮的纸面。
6
+ - `surface-sunken`: light `#ebebeb`; dark `#111111`. 代码块、用户消息气泡、展开的步骤详情。凹下去的纸面。
7
+ - `ink`: light `#171717`; dark `#ededed`. 正文与标题,用在四种纸面上(最低 13:1)。
8
+ - `ink-secondary`: light `#525252`; dark `#a3a3a3`. 次要文字、说明、列表的值、未选中图标,用在四种纸面上(最低 6:1)。
9
+ - `ink-tertiary`: light `#666666`; dark `#8c8c8c`. 占位符、时间戳、计数、分组标题,用在四种纸面上(最低 4.5:1)。
10
+ - `line`: light `#e3e3e3`; dark `#2f2f2f`. 分隔线、卡片描边、按钮描边。装饰性,不承载信息。
11
+ - `line-control`: light `#8a8a8a`; dark `#737373`. 输入框边框、拖拽条。在 canvas、surface、surface-raised 上不低于 3:1,让人一眼看出可输入。
12
+ - `accent`: light `var(--ink)`; dark `var(--ink)`. 强调:主按钮填充、选中指示、焦点环。就是墨色本身,浅色主题为黑、深色主题为白;强调靠明暗对比,不靠彩色。
13
+ - `accent-soft`: light `#e8e8e8`; dark `#2e2e2e`. 强调的浅底:强调标签、列表图标底、输入框聚焦光晕。上面的文字用 ink。
14
+ - `on-accent`: light `#ffffff`; dark `#161616`. accent 填充上的文字和图标:浅色主题白字,深色主题黑字。
15
+ - `focus-ring`: light `var(--accent)`; dark `var(--accent)`. 键盘焦点环:2pt 实线,外偏移 2pt。在所有纸面上不低于 13:1。
16
+ - `success`: light `#1f6b66`; dark `#6cc3b4`. 成功、已完成、已同步。界面里只有状态色是彩色,只在表达状态时出现。作为文字用在纸面和 success-soft 上。
17
+ - `success-soft`: light `#ddeeec`; dark `#183230`. 成功状态的浅底(标签、横幅)。
18
+ - `warning`: light `#8a5a0b`; dark `#e2b054`. 需要注意但不阻断:额度将用完、网络较慢。作为文字用在纸面和 warning-soft 上。
19
+ - `warning-soft`: light `#f5ead3`; dark `#3a2e17`. 警告状态的浅底。
20
+ - `danger`: light `#b0283f`; dark `#f07a8a`. 错误、失败、删除。永远同时配图标或文字。作为文字用在纸面和 danger-soft 上。
21
+ - `danger-soft`: light `#f7e1e4`; dark `#3d2027`. 错误状态的浅底、危险按钮的底色。
22
+ - `info`: light `#2c5f86`; dark `#82b4dc`. 中性提示。作为文字用在纸面和 info-soft 上。
23
+ - `info-soft`: light `#e1ebf3`; dark `#1d2c3a`. 提示状态的浅底。
24
+ - `fill-hover`: light `#0000000a`; dark `#ffffff0f`. 悬停底色,叠在任何纸面上(列表行、文字按钮、侧边栏项)。
25
+ - `fill-selected`: light `#00000012`; dark `#ffffff1a`. 选中底色(侧边栏当前项、分段控件底槽、中性标签底)。
26
+ - `knob`: light `#ffffff`; dark `#ffffff`. 开关的圆钮,两套主题都是白色,与系统一致。
27
+ - `scrim`: light `#00000052`; dark `#00000080`. 弹窗背后压暗内容的遮罩。
28
+ - `glass-fill`: light `#ffffffa6`; dark `#2a2a2aa6`. 仅用于网页预览模拟 Liquid Glass。App 里用系统 .glassEffect(),不要用这个值自己画玻璃。
29
+ - `glass-stroke`: light `#ffffffcc`; dark `#ffffff24`. 仅用于网页预览:玻璃边缘的高光描边。
30
+
31
+ ## shadow
32
+
33
+ - `shadow-control`: light `0 1px 1px rgba(0, 0, 0, 0.05)`; dark `0 1px 1px rgba(0, 0, 0, 0.30)`. 次按钮、分段控件的选中块:一点点厚度。
34
+ - `shadow-float`: light `0 1px 2px rgba(0, 0, 0, 0.05), 0 6px 20px rgba(0, 0, 0, 0.08)`; dark `0 1px 2px rgba(0, 0, 0, 0.40), 0 6px 20px rgba(0, 0, 0, 0.45)`. Composer、弹出菜单、弹窗、浮动面板。
35
+ - `shadow-glass`: light `0 4px 14px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.70)`; dark `0 4px 14px rgba(0, 0, 0, 0.40), inset 0 1px 0 rgba(255, 255, 255, 0.10)`. 仅用于网页预览模拟玻璃。App 里系统玻璃自带阴影。
36
+
37
+ ## spacing
38
+
39
+ - `space-1`: light `4px`; dark `4px`. 图标与文字之间、卡片内标题与摘要之间。
40
+ - `space-2`: light `8px`; dark `8px`. Mac 列表项内边距、横幅上下内边距、Composer 内边距。
41
+ - `space-3`: light `12px`; dark `12px`. Mac 按钮左右内边距、卡片内边距、横幅左右内边距。
42
+ - `space-4`: light `16px`; dark `16px`. Mac 内容区边距、对话中消息之间、iOS 页面左右边距。
43
+ - `space-5`: light `20px`; dark `20px`. iOS 分组之间、Mac 区块之间。
44
+ - `space-6`: light `24px`; dark `24px`. 空状态内边距、大区块之间。
45
+ - `space-8`: light `32px`; dark `32px`. 页面级留白。
46
+ - `space-10`: light `40px`; dark `40px`. 引导页、首屏的大留白。
47
+
48
+ ## radius
49
+
50
+ - `radius-xs`: light `4px`; dark `4px`. 标签、复选框、分段控件里的选中块(外层 radius-sm、内边距 2)。
51
+ - `radius-sm`: light `6px`; dark `6px`. Mac 按钮、输入框、侧边栏选中块、iOS 列表图标底。
52
+ - `radius-md`: light `8px`; dark `8px`. Mac 卡片、横幅、代码块、弹出菜单。
53
+ - `radius-lg`: light `12px`; dark `12px`. iOS 卡片、iOS 分组列表、Composer、用户消息气泡、Mac 侧边栏面板。
54
+ - `radius-xl`: light `24px`; dark `24px`. iOS 底部弹窗、iOS 单行 Composer。
55
+ - `radius-full`: light `999px`; dark `999px`. 胶囊与圆形:玻璃按钮、iOS 主按钮、发送按钮、状态圆点。
56
+
57
+ ## stroke
58
+
59
+ - `stroke-hairline`: light `0.5px`; dark `0.5px`. 分隔线、卡片描边:1 个物理像素。SwiftUI: 1 / displayScale。
60
+ - `stroke-control`: light `1px`; dark `1px`. 输入框边框。
61
+ - `stroke-focus`: light `2px`; dark `2px`. 焦点环。
62
+
63
+ ## size
64
+
65
+ - `control-mac-sm`: light `20px`; dark `20px`. Mac 小按钮、行内操作、分段控件。
66
+ - `control-mac`: light `24px`; dark `24px`. Mac 默认按钮、输入框、图标按钮、步骤行。
67
+ - `control-mac-lg`: light `28px`; dark `28px`. Mac 大按钮(引导页、空状态)。
68
+ - `row-mac`: light `26px`; dark `26px`. Mac 侧边栏项、列表行。
69
+ - `control-ios`: light `44px`; dark `44px`. iOS 最小可点区域(按钮看起来可以更小,点击区域仍补足到 44)、列表行、输入框、导航栏玻璃按钮。
70
+ - `button-ios-sm`: light `30px`; dark `30px`. iOS 小按钮的可见高度:卡片和列表里的「获取」「关注」这类行内操作。
71
+ - `button-ios`: light `36px`; dark `36px`. iOS 默认按钮的可见高度。
72
+ - `control-ios-lg`: light `46px`; dark `46px`. iOS 通栏主按钮(页面底部、弹窗里的唯一主操作)。
73
+ - `sidebar-mac`: light `220px`; dark `220px`. Mac 侧边栏默认宽度。
74
+ - `content-max`: light `680px`; dark `680px`. 长文阅读栏的最大宽度,14pt 下约每行 45 个汉字。
@@ -0,0 +1,11 @@
1
+ # Web implementation
2
+
3
+ Install matching versions of `@deernova/tokens` and `@deernova/ui`. Import tokens.css before components.css. The CSS component namespace is `dn-` (migrated from Paperlight's `pl-`). The UI package provides CSS and HTML examples, not React components or JavaScript behavior.
4
+
5
+ For framework-neutral implementations, copy the required CSS from `assets/design/`, and derive semantic markup from the relevant preview. Ensure buttons submit only intentionally, fields have labels, dialogs manage focus and Escape, and segmented controls expose their selected state. Preview-only static elements must receive real product behavior before shipping.
6
+
7
+ `data-theme="light"` or `data-theme="dark"` on the root overrides system theme; removing it follows the system. Persist preferences only if appropriate. Honor prefers-reduced-motion and prefers-reduced-transparency with stable and opaque fallbacks. Do not layer glass over reading content.
8
+
9
+ Use the source's 4 px spacing grid, thin separators and proportional radii. Documentation or marketing pages may have more generous type and spacing than dense application screens. Do not force the 13 pt Mac baseline onto mobile web. Touch targets should be at least 44 × 44 CSS px; previews may require internal scrolling, but real application layouts must reflow at narrow widths.
10
+
11
+ Verify 375 px and desktop widths, long Chinese/English text, 200% zoom, keyboard traversal, light/dark focus, primary-button contrast and empty/error states. Copy only needed images; retain provenance. No external font download is required.
@@ -0,0 +1,7 @@
1
+ const theme = document.querySelector('#theme');
2
+ try { theme.value = localStorage.getItem('deernova-theme') || 'system'; } catch {}
3
+ function applyTheme(){const value=theme.value; if(value==='system')document.documentElement.removeAttribute('data-theme');else document.documentElement.dataset.theme=value;document.querySelectorAll('iframe').forEach(f=>{f.src=f.src.split('#')[0]+(value==='system'?'':'#'+value);});try{localStorage.setItem('deernova-theme',value);}catch{}}
4
+ theme.addEventListener('change',applyTheme);applyTheme();
5
+ const search=document.querySelector('#search');search.addEventListener('input',()=>{const q=search.value.trim().toLowerCase();let n=0;document.querySelectorAll('.component').forEach(c=>{c.hidden=!c.dataset.search.toLowerCase().includes(q);if(!c.hidden)n++;});document.querySelector('#results').textContent=q?`找到 ${n} 个组件`:'';});search.addEventListener('keydown',e=>{if(e.key==='Enter')document.querySelector('#components').scrollIntoView();});
6
+ let timer;document.querySelectorAll('[data-copy]').forEach(b=>b.addEventListener('click',async()=>{const toast=document.querySelector('#toast');try{await navigator.clipboard.writeText(b.dataset.copy);toast.textContent='已复制 '+b.dataset.copy;}catch{toast.textContent='请手动复制:'+b.dataset.copy;}toast.classList.add('show');clearTimeout(timer);timer=setTimeout(()=>toast.classList.remove('show'),3000);}));
7
+ const observer=new IntersectionObserver(entries=>{for(const e of entries)if(e.isIntersecting){document.querySelectorAll('nav>a').forEach(a=>{const active=a.hash==='#'+e.target.id;a.classList.toggle('active',active);if(active)a.setAttribute('aria-current','location');else a.removeAttribute('aria-current');});}},{rootMargin:'-10% 0px -70% 0px'});document.querySelectorAll('main>section').forEach(s=>observer.observe(s));