agentcss 0.0.0-stage → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/01-tokens/README.md +236 -0
- package/01-tokens/behavior/dismissable.js +132 -0
- package/01-tokens/behavior/emit.js +76 -0
- package/01-tokens/behavior/focus-return.js +81 -0
- package/01-tokens/behavior/roving.js +152 -0
- package/01-tokens/behavior/typeahead.js +124 -0
- package/01-tokens/focus-ring-demo.html +133 -0
- package/01-tokens/focus-ring.css +102 -0
- package/01-tokens/page.css +244 -0
- package/01-tokens/polyfill.js +116 -0
- package/01-tokens/responsive-demo.html +171 -0
- package/01-tokens/scrollbar-demo.html +194 -0
- package/01-tokens/scrollbar.css +179 -0
- package/01-tokens/theme-toggle.js +103 -0
- package/01-tokens/tokens.css +972 -0
- package/01-tokens/typography.css +156 -0
- package/02-primitives/badge/README.md +71 -0
- package/02-primitives/badge/badge.css +141 -0
- package/02-primitives/badge/demo.html +101 -0
- package/02-primitives/button/README.md +99 -0
- package/02-primitives/button/button.css +353 -0
- package/02-primitives/button/demo.html +200 -0
- package/02-primitives/card/README.md +145 -0
- package/02-primitives/card/card.css +246 -0
- package/02-primitives/card/demo.html +170 -0
- package/02-primitives/choice/README.md +161 -0
- package/02-primitives/choice/choice.css +395 -0
- package/02-primitives/choice/demo.html +277 -0
- package/02-primitives/combobox/README.md +79 -0
- package/02-primitives/combobox/combobox.css +223 -0
- package/02-primitives/combobox/combobox.js +485 -0
- package/02-primitives/combobox/demo.html +109 -0
- package/02-primitives/date-range/README.md +100 -0
- package/02-primitives/date-range/date-range.css +206 -0
- package/02-primitives/date-range/date-range.js +301 -0
- package/02-primitives/date-range/demo.html +104 -0
- package/02-primitives/input/README.md +170 -0
- package/02-primitives/input/demo.html +246 -0
- package/02-primitives/input/input.css +239 -0
- package/02-primitives/popover/README.md +80 -0
- package/02-primitives/popover/demo.html +150 -0
- package/02-primitives/popover/popover.css +187 -0
- package/02-primitives/popover/popover.js +331 -0
- package/02-primitives/progress/README.md +82 -0
- package/02-primitives/progress/demo.html +154 -0
- package/02-primitives/progress/progress.css +172 -0
- package/02-primitives/select/README.md +95 -0
- package/02-primitives/select/demo.html +121 -0
- package/02-primitives/select/select.css +151 -0
- package/02-primitives/select/select.js +549 -0
- package/02-primitives/separator/README.md +63 -0
- package/02-primitives/separator/demo.html +84 -0
- package/02-primitives/separator/separator.css +73 -0
- package/02-primitives/skeleton/README.md +69 -0
- package/02-primitives/skeleton/demo.html +110 -0
- package/02-primitives/skeleton/skeleton.css +96 -0
- package/02-primitives/switch/README.md +65 -0
- package/02-primitives/switch/demo.html +115 -0
- package/02-primitives/switch/switch.css +370 -0
- package/03-patterns/accordion/README.md +121 -0
- package/03-patterns/accordion/accordion.css +453 -0
- package/03-patterns/accordion/accordion.js +369 -0
- package/03-patterns/accordion/demo.html +223 -0
- package/03-patterns/content/README.md +103 -0
- package/03-patterns/content/content.css +286 -0
- package/03-patterns/content/demo.html +88 -0
- package/03-patterns/drawer/README.md +79 -0
- package/03-patterns/drawer/demo.html +101 -0
- package/03-patterns/drawer/drawer.css +129 -0
- package/03-patterns/drawer/drawer.js +258 -0
- package/03-patterns/dropdown/README.md +78 -0
- package/03-patterns/dropdown/demo.html +101 -0
- package/03-patterns/dropdown/dropdown.css +135 -0
- package/03-patterns/dropdown/dropdown.js +451 -0
- package/03-patterns/form-validation/README.md +147 -0
- package/03-patterns/form-validation/demo.html +280 -0
- package/03-patterns/form-validation/form-validation.css +263 -0
- package/03-patterns/list/README.md +150 -0
- package/03-patterns/list/demo.html +225 -0
- package/03-patterns/list/flip.js +201 -0
- package/03-patterns/list/list.css +162 -0
- package/03-patterns/nav/README.md +225 -0
- package/03-patterns/nav/demo.html +131 -0
- package/03-patterns/nav/nav.css +314 -0
- package/03-patterns/nav/nav.js +430 -0
- package/03-patterns/nav/toc.js +111 -0
- package/03-patterns/overlay/README.md +196 -0
- package/03-patterns/overlay/demo.html +241 -0
- package/03-patterns/overlay/overlay.css +319 -0
- package/03-patterns/overlay/overlay.js +563 -0
- package/03-patterns/pagination/README.md +114 -0
- package/03-patterns/pagination/demo.html +165 -0
- package/03-patterns/pagination/pagination.css +195 -0
- package/03-patterns/pagination/pagination.js +395 -0
- package/03-patterns/reveal/README.md +91 -0
- package/03-patterns/reveal/demo.html +106 -0
- package/03-patterns/reveal/reveal.css +93 -0
- package/03-patterns/reveal/reveal.js +172 -0
- package/03-patterns/states/README.md +141 -0
- package/03-patterns/states/demo.html +240 -0
- package/03-patterns/states/states.css +252 -0
- package/03-patterns/tabs/README.md +84 -0
- package/03-patterns/tabs/demo.html +139 -0
- package/03-patterns/tabs/tabs.css +172 -0
- package/03-patterns/tabs/tabs.js +307 -0
- package/03-patterns/tooltip/README.md +96 -0
- package/03-patterns/tooltip/demo.html +78 -0
- package/03-patterns/tooltip/tooltip.css +89 -0
- package/03-patterns/tooltip/tooltip.js +288 -0
- package/03-patterns/tree/README.md +94 -0
- package/03-patterns/tree/demo.html +138 -0
- package/03-patterns/tree/tree.css +113 -0
- package/03-patterns/tree/tree.js +456 -0
- package/04-recipes/analysis-report/README.md +80 -0
- package/04-recipes/analysis-report/analysis-report.css +187 -0
- package/04-recipes/analysis-report/demo.html +274 -0
- package/04-recipes/data-showcase/README.md +45 -0
- package/04-recipes/data-showcase/demo.html +247 -0
- package/04-recipes/detail-page/README.md +93 -0
- package/04-recipes/detail-page/demo.html +55 -0
- package/04-recipes/detail-page/detail-page.css +190 -0
- package/04-recipes/detail-page/full.html +60 -0
- package/04-recipes/detail-page/null.html +60 -0
- package/04-recipes/detail-page/partial.html +60 -0
- package/04-recipes/detail-page/verify-skeleton.py +19 -0
- package/04-recipes/longform/README.md +93 -0
- package/04-recipes/longform/agc-memory.svg +4 -0
- package/04-recipes/longform/content.html +610 -0
- package/04-recipes/longform/content.md +51 -0
- package/04-recipes/longform/longform.html +627 -0
- package/04-recipes/report/README.md +176 -0
- package/04-recipes/report/demo.html +355 -0
- package/04-recipes/report/report.css +364 -0
- package/04-recipes/table/README.md +103 -0
- package/04-recipes/table/demo.html +455 -0
- package/04-recipes/table/table.css +372 -0
- package/04-recipes/tierA-tokens.css +189 -0
- package/09-assets/README.md +74 -0
- package/09-assets/bar/README.md +94 -0
- package/09-assets/bar/bar.css +166 -0
- package/09-assets/bar/bar.js +320 -0
- package/09-assets/bar/demo.html +176 -0
- package/09-assets/echarts-adapter/demo.html +192 -0
- package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
- package/09-assets/model-viewer/README.md +155 -0
- package/09-assets/model-viewer/demo.html +105 -0
- package/09-assets/model-viewer/model-viewer.css +143 -0
- package/09-assets/model-viewer/model-viewer.js +423 -0
- package/09-assets/scientific-plot/README.md +94 -0
- package/09-assets/scientific-plot/demo.html +252 -0
- package/09-assets/scientific-plot/scientific-plot.css +141 -0
- package/09-assets/scientific-plot/scientific-plot.js +610 -0
- package/09-assets/sparkline/README.md +153 -0
- package/09-assets/sparkline/demo.html +163 -0
- package/09-assets/sparkline/sparkline.css +158 -0
- package/09-assets/sparkline/sparkline.js +508 -0
- package/API.md +332 -0
- package/CHANGELOG.md +3116 -0
- package/CODE_OF_CONDUCT.md +64 -0
- package/CONTRIBUTING.md +89 -0
- package/ERRORS.md +1658 -0
- package/LICENSE +21 -0
- package/README.md +491 -2
- package/SECURITY.md +72 -0
- package/START-HERE.md +164 -0
- package/SUPPORT.md +109 -0
- package/adapters/presentation/README.md +113 -0
- package/adapters/presentation/check.js +101 -0
- package/adapters/presentation/deck.schema.json +74 -0
- package/adapters/presentation/to-doc.js +138 -0
- package/ai/START-HERE.md +104 -0
- package/ai/behaviors.json +380 -0
- package/ai/behaviors.schema.json +61 -0
- package/ai/capabilities.json +56 -0
- package/ai/cli.js +387 -0
- package/ai/components.json +1944 -0
- package/ai/components.meta.json +168 -0
- package/ai/components.schema.json +220 -0
- package/ai/contract.schema.json +147 -0
- package/ai/deprecations.json +55 -0
- package/ai/deprecations.schema.json +85 -0
- package/ai/motion-policy.json +22 -0
- package/ai/patch.js +323 -0
- package/ai/patch.schema.json +63 -0
- package/ai/profiles.json +92 -0
- package/ai/tokens.audience.json +55 -0
- package/ai/tokens.audience.schema.json +73 -0
- package/ai/tokens.json +762 -0
- package/ai/tokens.schema.json +58 -0
- package/ai/tokens.tree.json +752 -0
- package/ai/tokens.tree.schema.json +56 -0
- package/ai/validate.js +383 -0
- package/dist/01-tokens/behavior/dismissable.js +60 -0
- package/dist/01-tokens/behavior/emit.js +21 -0
- package/dist/01-tokens/behavior/focus-return.js +31 -0
- package/dist/01-tokens/behavior/roving.js +77 -0
- package/dist/01-tokens/behavior/typeahead.js +61 -0
- package/dist/01-tokens/focus-ring.css +1 -0
- package/dist/01-tokens/page.css +1 -0
- package/dist/01-tokens/polyfill.js +78 -0
- package/dist/01-tokens/scrollbar.css +1 -0
- package/dist/01-tokens/theme-toggle.js +61 -0
- package/dist/01-tokens/tokens.css +1 -0
- package/dist/01-tokens/typography.css +1 -0
- package/dist/02-primitives/badge/badge.css +1 -0
- package/dist/02-primitives/button/button.css +1 -0
- package/dist/02-primitives/card/card.css +1 -0
- package/dist/02-primitives/choice/choice.css +1 -0
- package/dist/02-primitives/combobox/combobox.css +1 -0
- package/dist/02-primitives/combobox/combobox.js +439 -0
- package/dist/02-primitives/date-range/date-range.css +1 -0
- package/dist/02-primitives/date-range/date-range.js +267 -0
- package/dist/02-primitives/input/input.css +1 -0
- package/dist/02-primitives/popover/popover.css +1 -0
- package/dist/02-primitives/popover/popover.js +257 -0
- package/dist/02-primitives/progress/progress.css +1 -0
- package/dist/02-primitives/select/select.css +1 -0
- package/dist/02-primitives/select/select.js +449 -0
- package/dist/02-primitives/separator/separator.css +1 -0
- package/dist/02-primitives/skeleton/skeleton.css +1 -0
- package/dist/02-primitives/switch/switch.css +1 -0
- package/dist/03-patterns/accordion/accordion.css +1 -0
- package/dist/03-patterns/accordion/accordion.js +219 -0
- package/dist/03-patterns/content/content.css +1 -0
- package/dist/03-patterns/drawer/drawer.css +1 -0
- package/dist/03-patterns/drawer/drawer.js +229 -0
- package/dist/03-patterns/dropdown/dropdown.css +1 -0
- package/dist/03-patterns/dropdown/dropdown.js +365 -0
- package/dist/03-patterns/form-validation/form-validation.css +1 -0
- package/dist/03-patterns/list/flip.js +117 -0
- package/dist/03-patterns/list/list.css +1 -0
- package/dist/03-patterns/nav/nav.css +1 -0
- package/dist/03-patterns/nav/nav.js +322 -0
- package/dist/03-patterns/nav/toc.js +76 -0
- package/dist/03-patterns/overlay/overlay.css +1 -0
- package/dist/03-patterns/overlay/overlay.js +398 -0
- package/dist/03-patterns/pagination/pagination.css +1 -0
- package/dist/03-patterns/pagination/pagination.js +273 -0
- package/dist/03-patterns/reveal/reveal.css +1 -0
- package/dist/03-patterns/reveal/reveal.js +138 -0
- package/dist/03-patterns/states/states.css +1 -0
- package/dist/03-patterns/tabs/tabs.css +1 -0
- package/dist/03-patterns/tabs/tabs.js +242 -0
- package/dist/03-patterns/tooltip/tooltip.css +1 -0
- package/dist/03-patterns/tooltip/tooltip.js +213 -0
- package/dist/03-patterns/tree/tree.css +1 -0
- package/dist/03-patterns/tree/tree.js +383 -0
- package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
- package/dist/04-recipes/detail-page/detail-page.css +1 -0
- package/dist/04-recipes/report/report.css +1 -0
- package/dist/04-recipes/table/table.css +1 -0
- package/dist/04-recipes/tierA-tokens.css +1 -0
- package/dist/09-assets/bar/bar.css +1 -0
- package/dist/09-assets/bar/bar.js +222 -0
- package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
- package/dist/09-assets/model-viewer/model-viewer.css +1 -0
- package/dist/09-assets/model-viewer/model-viewer.js +320 -0
- package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
- package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
- package/dist/09-assets/sparkline/sparkline.css +1 -0
- package/dist/09-assets/sparkline/sparkline.js +265 -0
- package/dist/COSTS.md +56 -0
- package/docs/AI-CONTRACT.md +197 -0
- package/docs/BACKLOG.md +127 -0
- package/docs/BENCHMARK.md +252 -0
- package/docs/GUIDANCE.md +154 -0
- package/docs/INVARIANT.md +372 -0
- package/docs/LAYER-BASELINE.md +158 -0
- package/docs/RELEASING.md +275 -0
- package/docs/RFC-THEME-SCOPE.md +141 -0
- package/docs/ROADMAP.md +182 -0
- package/index.html +82 -0
- package/package.json +107 -4
- package/types/index.d.ts +310 -0
package/START-HERE.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# 从这里开始
|
|
2
|
+
|
|
3
|
+
> **这个文件是给你用的,不是给我写的。**
|
|
4
|
+
> 目标:下次要用这个库,**照着下面抄,不用重新摸索**。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 三步
|
|
9
|
+
|
|
10
|
+
### 第 1 步:判断你在哪一档
|
|
11
|
+
|
|
12
|
+
| 你的情况 | 走哪条 | 需要多少 |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| **某项目 / 单文件页**(不能外链 CSS、不能构建)| **A** | 令牌 13.8 KB + 你要的那几个组件 |
|
|
15
|
+
| **普通静态站**(能引 CSS、不能构建)| **B** | `<link>` 引 tokens + components |
|
|
16
|
+
| **React / Vite 等** | **C** | 先读下面「C 档的额外说明」|
|
|
17
|
+
|
|
18
|
+
### 第 2 步:抄令牌(**必做,三档都要**)
|
|
19
|
+
|
|
20
|
+
| 档 | 抄什么 | 怎么抄 |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| **A** | `04-recipes/tierA-tokens.css` | 整份粘进 `<style>` |
|
|
23
|
+
| **B / C** | `01-tokens/tokens.css` + `01-tokens/typography.css` | 两个 `<link>` |
|
|
24
|
+
|
|
25
|
+
> ⚠️ **A 档那份是从 `tokens.css` 自动抽出来的**(`make-tiersnippet.py`),
|
|
26
|
+
> 所以两边不会不一致。**不要手抄** —— 手抄迟早漂移。
|
|
27
|
+
|
|
28
|
+
### 第 3 步:只抄你真正要用的组件
|
|
29
|
+
|
|
30
|
+
**不要整个库都搬。** 下面是实测的每个组件多大:
|
|
31
|
+
|
|
32
|
+
🔴 **带 `JS` 的组件要连 JS 一起抄** —— 那个 JS 是**行为契约**
|
|
33
|
+
(键盘、焦点、ARIA),**去掉它组件就"看起来能用其实不能用"**。
|
|
34
|
+
|
|
35
|
+
| 组件 | 文件 | 行数 | JS | 什么时候要 |
|
|
36
|
+
|---|---|---|---|---|
|
|
37
|
+
| 按钮 | `02-primitives/button/button.css` | 353 | — | 几乎总要 |
|
|
38
|
+
| 输入框 | `02-primitives/input/input.css` | 239 | — | 有表单就要 |
|
|
39
|
+
| 标签 / 徽章 | `02-primitives/badge/badge.css` | 141 | — | 有状态标记就要("已披露""停牌") |
|
|
40
|
+
| 卡片 | `02-primitives/card/card.css` | 246 | — | 有分组内容就要 |
|
|
41
|
+
| 单选 / 多选 | `02-primitives/choice/choice.css` | 395 | — | 单选 / 多选就要 |
|
|
42
|
+
| 下拉选择 | `02-primitives/select/select.css` | 151 | **必需 549** (`select.js`) | 原生 select 的外观或交互不够用就要 |
|
|
43
|
+
| 可搜索选择 | `02-primitives/combobox/combobox.css` | 223 | **必需 485** (`combobox.js`) | 选项多到要搜索,或要选多个并留成标签就要 |
|
|
44
|
+
| 开关 | `02-primitives/switch/switch.css` | 370 | — | 有"立即生效的设置"就要 |
|
|
45
|
+
| 分隔线 | `02-primitives/separator/separator.css` | 73 | — | 要分开内容块就要 |
|
|
46
|
+
| 加载骨架 | `02-primitives/skeleton/skeleton.css` | 96 | — | 数据还没到、先把版式占住就要 |
|
|
47
|
+
| 进度条 / 环 | `02-primitives/progress/progress.css` | 172 | — | 有耗时过程要给进度就要 |
|
|
48
|
+
| 浮层气泡 | `02-primitives/popover/popover.css` | 187 | **必需 331** (`popover.js`) | 要一段信息贴着触发元素浮出来就要 |
|
|
49
|
+
| 日期区间 | `02-primitives/date-range/date-range.css` | 206 | **必需 301** (`date-range.js`) | 要选起止日期就要 |
|
|
50
|
+
| 标签页 | `03-patterns/tabs/tabs.css` | 172 | **必需 307** (`tabs.js`) | 同层级内容切换就要 |
|
|
51
|
+
| 折叠面板(beta) | `03-patterns/accordion/accordion.css` | 453 | **必需 369** (`accordion.js`) | 长表单分段就要 |
|
|
52
|
+
| 动作菜单(beta) | `03-patterns/dropdown/dropdown.css` | 135 | **必需 451** (`dropdown.js`) | 要一组动作(新建 / 导出 / 删除)就要 |
|
|
53
|
+
| 文字提示 | `03-patterns/tooltip/tooltip.css` | 89 | **必需 288** (`tooltip.js`) | 图标按钮或缩写需要一句话解释就要 |
|
|
54
|
+
| 分页 | `03-patterns/pagination/pagination.css` | 195 | **必需 395** (`pagination.js`) | 数据多到要翻页就要 |
|
|
55
|
+
| 树形 | `03-patterns/tree/tree.css` | 113 | **必需 456** (`tree.js`) | 层级数据(文件 / 组织 / 分类)要展开就要 |
|
|
56
|
+
| 侧边抽屉(beta) | `03-patterns/drawer/drawer.css` | 129 | **必需 258** (`drawer.js`) | 要从侧边滑出面板就要 |
|
|
57
|
+
| 弹窗 / 吐司(beta) | `03-patterns/overlay/overlay.css` | 319 | **必需 563** (`overlay.js`) | 需要弹层(吐司 / 模态)就要 |
|
|
58
|
+
| 状态(空 / 加载 / 错 / 成功) | `03-patterns/states/states.css` | 252 | — | **凡是会异步取数就要** |
|
|
59
|
+
| 表单校验 | `03-patterns/form-validation/form-validation.css` | 263 | — | 提交前要校验就要 |
|
|
60
|
+
| 列表增删 | `03-patterns/list/list.css` | 162 | 可选 201 (`flip.js`,FLIP 增删动画,纯增强) | 列表会动态增删就要 |
|
|
61
|
+
| 导航 / 目录 | `03-patterns/nav/nav.css` | 314 | **必需 430** (`nav.js`) · 可选 111 (`toc.js`,自动生成目录,纯增强) | 顶部要导航,或长文要目录就要 |
|
|
62
|
+
| 长文排版 | `03-patterns/content/content.css` | 286 | — | 写文档 / 长文就要 |
|
|
63
|
+
| reveal | `03-patterns/reveal/reveal.css` | 93 | 可选 172 (`reveal.js`,入场动效,纯增强;没有它内容直接可见) | |
|
|
64
|
+
| analysis-report | `04-recipes/analysis-report/analysis-report.css` | 187 | — | |
|
|
65
|
+
| detail-page | `04-recipes/detail-page/detail-page.css` | 190 | — | |
|
|
66
|
+
| report | `04-recipes/report/report.css` | 364 | — | |
|
|
67
|
+
| table | `04-recipes/table/table.css` | 372 | — | |
|
|
68
|
+
| bar | `09-assets/bar/bar.css` | 166 | **必需 320** (`bar.js`) | |
|
|
69
|
+
| model-viewer | `09-assets/model-viewer/model-viewer.css` | 143 | **必需 423** (`model-viewer.js`) | |
|
|
70
|
+
| scientific-plot | `09-assets/scientific-plot/scientific-plot.css` | 141 | **必需 610** (`scientific-plot.js`) | |
|
|
71
|
+
| sparkline | `09-assets/sparkline/sparkline.css` | 158 | **必需 508** (`sparkline.js`) | |
|
|
72
|
+
|
|
73
|
+
### 🔴 这些组件的 JS 是**必需的**(不是增强)
|
|
74
|
+
|
|
75
|
+
它们的 JS 承担**行为契约**:键盘、ARIA、焦点。只抄 CSS 会得到"看起来能用其实不能用"的组件。
|
|
76
|
+
|
|
77
|
+
| 组件 | JS | JS 里实测承担的机制 |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| 下拉选择 | `select.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
80
|
+
| 可搜索选择 | `combobox.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
81
|
+
| 浮层气泡 | `popover.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
82
|
+
| 日期区间 | `date-range.js` | 键盘 — · ARIA ✓ · 焦点 ✓ |
|
|
83
|
+
| 标签页 | `tabs.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
84
|
+
| 折叠面板 | `accordion.js` | 键盘 ✓ · ARIA ✓ · 焦点 — |
|
|
85
|
+
| 动作菜单 | `dropdown.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
86
|
+
| 文字提示 | `tooltip.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
87
|
+
| 分页 | `pagination.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
88
|
+
| 树形 | `tree.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
89
|
+
| 侧边抽屉 | `drawer.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
90
|
+
| 弹窗 / 吐司 | `overlay.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
91
|
+
| 导航 / 目录 | `nav.js` | 键盘 ✓ · ARIA ✓ · 焦点 ✓ |
|
|
92
|
+
| bar | `bar.js` | 键盘 — · ARIA ✓ · 焦点 — |
|
|
93
|
+
| model-viewer | `model-viewer.js` | 键盘 — · ARIA — · 焦点 — |
|
|
94
|
+
| scientific-plot | `scientific-plot.js` | 键盘 — · ARIA ✓ · 焦点 — |
|
|
95
|
+
| sparkline | `sparkline.js` | 键盘 — · ARIA ✓ · 焦点 — |
|
|
96
|
+
|
|
97
|
+
**已经人工验证过后果的三条**(其余的按上表推断,不要凭印象写后果):
|
|
98
|
+
|
|
99
|
+
- 标签页只抄 CSS:方向键不切面板 · Tab 会逐个穿过所有 tab
|
|
100
|
+
- 折叠面板只抄 CSS:Enter / Space 不响应 · 面板的 `role="region"` 缺失
|
|
101
|
+
- 弹窗 / 吐司只抄 CSS:**没有焦点陷阱** · Esc 不关 · 读屏不播报
|
|
102
|
+
|
|
103
|
+
> `flip.js` / `toc.js` 是**可选增强**(动画、目录生成),
|
|
104
|
+
> 它们的 CSS 本身是纯 CSS —— 不抄那两个 JS,组件照样能用。
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### 现成页面(整页抄,不是零件)
|
|
108
|
+
|
|
109
|
+
| 示例 | 目录 | 它示范什么 |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `analysis-report/` | `04-recipes/analysis-report/` | 组合型研究报告:正文 + 辅助栏并排,窄屏退回单栏 |
|
|
112
|
+
| `data-showcase/` | `04-recipes/data-showcase/` | 四种数据表达方式对照:我到底该用哪个 |
|
|
113
|
+
| `detail-page/` | `04-recipes/detail-page/` | 实体详情页骨架:字段齐全 / 部分缺失 / 无数据,三态同构(DOM 不变) |
|
|
114
|
+
| `longform/` | `04-recipes/longform/` | 单栏长文排版与阅读节奏 |
|
|
115
|
+
| `report/` | `04-recipes/report/` | 报告版式系统 v1:共享基础 + 三种版式取舍(杂志 / 科研技术 / 金融研究) |
|
|
116
|
+
| `table/` | `04-recipes/table/` | 专业数据表格:列级格式与单位,三种用途预设 |
|
|
117
|
+
|
|
118
|
+
## 抄完先做这三件事
|
|
119
|
+
|
|
120
|
+
1. **看效果** —— 每个组件目录下有 `demo.html`,抄完对照着比
|
|
121
|
+
2. **跑一遍无障碍** —— 浏览器控制台里(或用 axe)确认对比度达标
|
|
122
|
+
3. **别改类名** —— 类名是 API(`.btn` `.btn--primary` `.field__input`),
|
|
123
|
+
改名等于换组件。**要改样式就改令牌**,全库会一起变
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## C 档(React / Vite)的额外说明
|
|
128
|
+
|
|
129
|
+
**目前没有构建配置。** 这个库是**零依赖、零构建**的纯 CSS + ES5 JS,
|
|
130
|
+
所以在 Vite 里直接 `import './tokens.css'` 就能用,不需要任何额外配置。
|
|
131
|
+
|
|
132
|
+
**如果你要的是 React 组件(`<Button />` 这样的),这个库现在没有** ——
|
|
133
|
+
它给的是 CSS 类,不是组件。**这不是缺陷,是范围**:
|
|
134
|
+
CSS 类跨框架通用,React 组件会绑死框架。
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 一句话记住
|
|
139
|
+
|
|
140
|
+
> **抄 `tierA-tokens.css`(A 档)或 `tokens.css`(B/C 档)→ 再抄你要的那几个 CSS → 保留类名。**
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 你可能还想找的(有 / 没有,一次说清)
|
|
145
|
+
|
|
146
|
+
> 🔴 这一节以前把徽章写成「没有」,而同一份文件的第 39 行就列着它 ——
|
|
147
|
+
> 自己跟自己打架,比"漏写一项"更误导人。
|
|
148
|
+
> 现在:**凡是上面组件表里有的,这里一律不再说没有。**
|
|
149
|
+
|
|
150
|
+
| 你可能想要 | 有没有 |
|
|
151
|
+
|---|---|
|
|
152
|
+
| 徽章 | ✅ 有 —— `02-primitives/badge/`,见上面组件表 |
|
|
153
|
+
| 数据表格 | ⚠️ 有现成页面,不是库级组件 —— 抄 `04-recipes/table/`(三种用途预设:财务 / 学术 / 统计)|
|
|
154
|
+
| 指标块 / KPI 卡 | ❌ 没有专门组件 —— 用 `card` + 排版令牌自己搭,几分钟的事 |
|
|
155
|
+
| 图标 | ❌ 本库不内置任何图标(`09-assets/` 下没有图标目录)—— 需要就自己内联 SVG,规格见 `09-assets/README.md` |
|
|
156
|
+
| React / Vue 组件 | ❌ 只有 CSS 类(原因见上面「C 档」)|
|
|
157
|
+
| 暗色模式 | ✅ 有,抄令牌就自带 |
|
|
158
|
+
| 中文排版(i18n)| ✅ 有度量令牌,四语言实测过 |
|
|
159
|
+
|
|
160
|
+
**没有就是没有。** 早知道比晚知道省时间。
|
|
161
|
+
|
|
162
|
+
> 每一行的「有 / 没有」都是对着目录与契约数出来的。
|
|
163
|
+
> 新增组件后请跑 `python 05-audit/fix-start-here.py` 重生成上面的表,
|
|
164
|
+
> 再人工对一遍这一节 —— 脚本只管表,管不了散文。
|
package/SUPPORT.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# 浏览器支持矩阵
|
|
2
|
+
|
|
3
|
+
> ⭐ 这份文件的作用是**诚实**。
|
|
4
|
+
> 定位里写了「移动 Web」,就必须说清楚**哪些是验证过的、哪些没有**。
|
|
5
|
+
> 没验证的不要写成支持的。
|
|
6
|
+
>
|
|
7
|
+
> 🔴 2026-10-09 修订说明(外部评审实测):
|
|
8
|
+
> 这一页以前写着「桌面 Firefox ✅ 已验证」和「自动化跑的是桌面 Firefox」——
|
|
9
|
+
> **两句都是假的**。当时的统一启动器只会找 Chromium,
|
|
10
|
+
> Firefox 从来没被启动过一次。
|
|
11
|
+
> ⇒ 这比"没验证"更糟:它给了一个**错误的**证据来源,
|
|
12
|
+
> 读者会以为"至少 Firefox 跑过了"。
|
|
13
|
+
> 现在引擎是真的切换了,并且每个作业都要**自己报 UA** 自证(见下)。
|
|
14
|
+
|
|
15
|
+
## 状态定义
|
|
16
|
+
|
|
17
|
+
| 标记 | 含义 |
|
|
18
|
+
|---|---|
|
|
19
|
+
| ✅ 已验证 | 有自动化检查覆盖,且**跑的就是这个引擎**(有 UA 证据) |
|
|
20
|
+
| ⚠️ 部分验证 | 只覆盖了部分功能或部分视口 |
|
|
21
|
+
| ❌ 未验证 | **没有在真实环境跑过** |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 自动化覆盖的环境
|
|
26
|
+
|
|
27
|
+
证据文件:`10-review/engine-evidence.json`(由 `05-audit/engine-gate.js` 生成,可复跑)。
|
|
28
|
+
|
|
29
|
+
| 平台 | 引擎 | 状态 | 覆盖内容 |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| 桌面 | Chromium | ✅ | 全部组件契约、暗色对比度、响应式三档、视觉回归 |
|
|
32
|
+
| 桌面 | WebKit | ✅ | nightly 矩阵的组件契约(select / combobox / date-range / overlay / tree / dropdown / popover / tooltip) |
|
|
33
|
+
| 桌面 | Firefox | ⚠️ | 矩阵里**已声明并自证**,但本机/CI 需要先 `npx playwright install firefox`;没装时门禁显式 SKIP,不假装通过 |
|
|
34
|
+
|
|
35
|
+
### 🔴 怎么知道"跑的真的是这个引擎"
|
|
36
|
+
|
|
37
|
+
光有 `matrix.engine` 不够 —— 它以前只用在 `npx playwright install` 那一步,
|
|
38
|
+
测试启动器根本没收到 ⇒ 三个作业跑的都是 Chromium。
|
|
39
|
+
所以现在有两道独立的证明:
|
|
40
|
+
|
|
41
|
+
1. **每个作业自证**:`FL_ENGINE=… node 05-audit/engine-probe.js`
|
|
42
|
+
站起来报一次自己的 UA,并校验 UA 属于声明的引擎族。
|
|
43
|
+
(⚠️ Chromium 的 UA 里**也含** `AppleWebKit` ⇒ 只判子串会把 Chromium 认成 WebKit,
|
|
44
|
+
判据必须同时排除 `Chrome/` 与 `HeadlessChrome`。)
|
|
45
|
+
2. **矩阵整体自证**:`05-audit/engine-gate.js` 逐个引擎启动,
|
|
46
|
+
要求跑起来的引擎之间 **UA 两两不同** ⇒ 证明不是"同一个浏览器跑了三遍"。
|
|
47
|
+
|
|
48
|
+
装不上某个引擎时是 **SKIP** 而不是"通过"
|
|
49
|
+
⇒ 缺浏览器是环境问题,但**不许**被当成"矩阵没问题"。
|
|
50
|
+
|
|
51
|
+
### 门禁数量
|
|
52
|
+
|
|
53
|
+
不写死数字 —— 它由 `doc-facts-gate.py` 从 `05-audit/check-all.sh` **按名单**算,
|
|
54
|
+
文档里写错会被判红。查当前数字:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
python3 05-audit/doc-facts-gate.py
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
⚠️ **不要用 `grep -c 'run "'` 去数**:那会给出 **99** 这种偏小的数。
|
|
61
|
+
原因是 `check-all.sh` 里有 `for g in …` 循环(里面的 `run "$g"` 是缩进的、名字是变量,
|
|
62
|
+
grep 一条都数不到),还有 `skip "…"`(这台机器跑不了的门禁,也是注册数的一部分)。
|
|
63
|
+
`doc-facts-gate.py` 会展开循环、把 `run` / `run_report` / `skip` 三种登记方式
|
|
64
|
+
按**名字去重**后计数 ⇒ **任何机器上都是同一个数**。
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 尚未验证的环境
|
|
69
|
+
|
|
70
|
+
| 平台 | 引擎 | 状态 | 说明 |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| iOS | WKWebView | ❌ | **未在真机或模拟器验证** |
|
|
73
|
+
| iOS | Safari | ❌ | 未在真机验证 |
|
|
74
|
+
| Android | Android WebView | ❌ | **未在真机验证** |
|
|
75
|
+
| Android | Chrome(移动版)| ⚠️ | 仅用**桌面**引擎模拟了移动视口,**非真机引擎** |
|
|
76
|
+
|
|
77
|
+
⚠️ 桌面 WebKit 自动化(上面那个 ✅)**不等于** iOS WKWebView:
|
|
78
|
+
真机上的软键盘、可视视口变化、安全区、`100vh`、页面回弹、VoiceOver
|
|
79
|
+
都没有被上面任何一项覆盖。
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 已知风险(未验证带来的)
|
|
84
|
+
|
|
85
|
+
1. **`:has()`** —— 已在 `theme-toggle` 里避免使用;其余用法需在 WebKit 上实测
|
|
86
|
+
2. **`backdrop-filter`** —— Firefox 与旧 WebKit 行为不一致,用了 `@supports` 兜底
|
|
87
|
+
3. **`conic-gradient`**(环形进度)—— Safari 15.4+ 才支持
|
|
88
|
+
4. **滚动条样式** —— `::-webkit-scrollbar` 与 Firefox 的 `scrollbar-width` 是两套语法,组件里都写了
|
|
89
|
+
5. **iOS 输入框的 `font-size < 16px` 会触发缩放** —— 输入类组件已避免
|
|
90
|
+
|
|
91
|
+
## 已知限制(已验证存在,不是"待验证")
|
|
92
|
+
|
|
93
|
+
| 限制 | 说明 |
|
|
94
|
+
|---|---|
|
|
95
|
+
| **popover 没有碰撞翻转** | 浮层按声明的方向挂出(`end` 方向 = 锚点右侧),**不会**因为贴边而自动翻到另一侧。⇒ 锚点靠近视口右缘时 `end` 方向会溢出。使用者需要自己选方向,或把锚点放在有余量的位置。 |
|
|
96
|
+
| **没有 codemod / 运行时废弃告警** | 废弃流程(`ai/deprecations.json`)只是**版本号承诺**:到期允许移除,但不会在运行时警告你还在用。要真拦截得自己在 CI 加 lint。 |
|
|
97
|
+
| **弹层锁滚动只补流式内容** | 锁滚动时补偿加在 `body` 的 `padding-right` 上,`position: fixed` 的元素相对视口定位、管不到 ⇒ 页面里若有吸底条,需要自己用 `--overlay-scrollbar-width` 补(见 `03-patterns/overlay/README.md`)。这是当前方案的**已知取舍**,不是还没做。 |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 打算怎么补
|
|
102
|
+
|
|
103
|
+
优先级从高到低:
|
|
104
|
+
|
|
105
|
+
1. **Android WebView 真机**(用户量最大)
|
|
106
|
+
2. **iOS WKWebView**(`100vh` / 滚动 / 输入框是重灾区)
|
|
107
|
+
3. popover 的碰撞翻转(上面"已知限制"第 1 条)
|
|
108
|
+
|
|
109
|
+
⚠️ 在补齐之前,请勿把「移动 WebView 支持」当作已验证的能力对外承诺。
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Presentation Adapter(呈现适配层)
|
|
2
|
+
|
|
3
|
+
> **这一层刻意在核心库之外。**
|
|
4
|
+
> 核心(`01-tokens` ~ `04-recipes`、`ai/`)里**没有**任何 slide / deck / page 的概念。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 一、为什么 PPT 语义不进核心
|
|
9
|
+
|
|
10
|
+
一次真实事故:用本库做 14 页 PPT,AI 反复局部修改后整体崩坏,
|
|
11
|
+
人工修 1.5 小时仍未收口。
|
|
12
|
+
|
|
13
|
+
复盘时最容易得出的结论是「核心库要懂 PPT」——**这个结论是错的**。
|
|
14
|
+
|
|
15
|
+
理由:
|
|
16
|
+
|
|
17
|
+
| 如果进核心 | 后果 |
|
|
18
|
+
|---|---|
|
|
19
|
+
| 核心要知道"一页是什么" | 核心就从「组件库」变成「演示文稿引擎」 |
|
|
20
|
+
| 核心要知道"一页能放几个元素" | 这个数字每换一种呈现形态(报告 / 海报 / 长图)就不一样 |
|
|
21
|
+
| 核心要处理"翻页" | 翻页跟组件没有任何关系 |
|
|
22
|
+
|
|
23
|
+
⇒ **呈现形态是会变的,组件是不变的。把易变的和不变的绑在一起,两边都动不了。**
|
|
24
|
+
|
|
25
|
+
真正该做的是:**让核心提供一个稳定底座,让呈现语义挂在外层。**
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 二、怎么挂:用 `extensions`
|
|
30
|
+
|
|
31
|
+
核心契约 `ai/contract.schema.json` 给每个节点和整个文档留了 `extensions`:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"id": "title-1",
|
|
36
|
+
"kind": "text",
|
|
37
|
+
"text": "季度复盘",
|
|
38
|
+
"extensions": {
|
|
39
|
+
"presentation": { "slide": 1, "role": "title" }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
关键性质:
|
|
45
|
+
|
|
46
|
+
- **核心校验器看到 `extensions` 就忽略**,既不报错也不读取。
|
|
47
|
+
⇒ 核心不需要知道 PPT 存在。
|
|
48
|
+
- **本适配器读取 `extensions.presentation`**,做呈现特有的检查。
|
|
49
|
+
- ⇒ 两边通过**数据**耦合,不通过**代码**耦合。
|
|
50
|
+
|
|
51
|
+
这不是"为了优雅",是为了**前向兼容**:
|
|
52
|
+
|
|
53
|
+
> 一个旧版核心遇到 `extensions.presentation` 不会判文档非法;
|
|
54
|
+
> 一个新版本核心也不会因为多了一种呈现形态就要改自己的 schema。
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 三、用法
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# deck → 核心契约文档(丢掉呈现语义,剩下纯组件结构)
|
|
62
|
+
node adapters/presentation/to-doc.js deck.json -o doc.json
|
|
63
|
+
|
|
64
|
+
# 用核心校验器校验(它会忽略 extensions)
|
|
65
|
+
node ai/cli.js check doc.json --profile=standard
|
|
66
|
+
|
|
67
|
+
# 呈现特有的检查(每页元素数、标题层级、字号下限)
|
|
68
|
+
node adapters/presentation/check.js deck.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 四、这一层负责什么,不负责什么
|
|
74
|
+
|
|
75
|
+
| 负责 | 不负责 |
|
|
76
|
+
|---|---|
|
|
77
|
+
| slide / deck 的语义 | 组件长什么样(核心的事) |
|
|
78
|
+
| 每页元素数量、层级结构 | 颜色令牌(核心的事) |
|
|
79
|
+
| 呈现形态特有的约束 | 无障碍(核心的事,且**任何形态下都要成立**) |
|
|
80
|
+
| — | **"改一处全局,N 页是否跟着变"**(那是页面骨架的事:`01-tokens/page.css` + `shell` / `skel-lever` 两道门禁) |
|
|
81
|
+
|
|
82
|
+
⚠️ **无障碍不因呈现形态而打折。** 一页 PPT 也是给人看的,
|
|
83
|
+
对比度、焦点可见、键盘可达在任何形态下都要成立 —— 这是核心的事,
|
|
84
|
+
本层不能为了"好看"把它绕过去。
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 五、这些检查有人跑吗
|
|
89
|
+
|
|
90
|
+
🔴 曾经没有。`check.js` 的五条判据从写下到 0.4.2 之前,**一次都没被执行过** ——
|
|
91
|
+
README 说有,实际没人跑。这是最隐蔽的一种假绿:它连"通过"报告都不产出。
|
|
92
|
+
|
|
93
|
+
现在有 `05-audit/presentation-gate.py`(已接入 `check-all.sh`):
|
|
94
|
+
|
|
95
|
+
| 判据 | 怎么验 |
|
|
96
|
+
|---|---|
|
|
97
|
+
| 合规 deck 必须过 | `fixtures/deck-ok.json` ⇒ check.js exit 0 |
|
|
98
|
+
| 违规 deck 必须红 | `fixtures/deck-bad.json` ⇒ exit ≠ 0 |
|
|
99
|
+
| **五条判据各命中一次** | 少一条就红 ⇒ 判据被删/被改文案会立刻暴露 |
|
|
100
|
+
| 两个真值源不漂移 | `check.js` 的 `MAX_PER_SLIDE` 必须等于 `deck.schema.json` 的 `nodes.maxItems` |
|
|
101
|
+
| 门禁自己也会失效 | `--selftest`:把上限放宽到 999、去掉 `.slide-` 正则、把 schema 改成 8 ⇒ 门禁必须认出判据已失效 |
|
|
102
|
+
|
|
103
|
+
自测:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
python 05-audit/presentation-gate.py # 正常跑
|
|
107
|
+
python 05-audit/presentation-gate.py --selftest # 反向控制
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 六、如果以后要加别的形态
|
|
111
|
+
|
|
112
|
+
照这个目录再加一个 `adapters/<形态>/`,同样用 `extensions.<形态>` 承载。
|
|
113
|
+
**核心不需要改一行代码** —— 这就是它被分出来的全部意义。
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* check.js — 呈现形态特有的检查(**不属于核心门禁**)
|
|
4
|
+
*
|
|
5
|
+
* ============================================================================
|
|
6
|
+
* 🔴 为什么这些检查不在核心里
|
|
7
|
+
* ----------------------------------------------------------------------------
|
|
8
|
+
* 下面每一条判据都只对一个**呈现形态**成立:
|
|
9
|
+
* · 单页元素上限 12 —— 换成报告形态这个数就不对
|
|
10
|
+
* · 版面必须已登记 —— 换成海报形态版面集合完全不同
|
|
11
|
+
* · 每页必须有标题 —— 换成封面页就不该有
|
|
12
|
+
*
|
|
13
|
+
⇒ 把它们写进核心 = 核心要跟着每一种形态改一次。
|
|
14
|
+
核心应该只管**任何形态下都成立**的事(对比度、焦点、键盘、令牌)。
|
|
15
|
+
*
|
|
16
|
+
* ============================================================================
|
|
17
|
+
* 判据
|
|
18
|
+
* ----------------------------------------------------------------------------
|
|
19
|
+
* ① 版面必须已登记(deck.schema.json 的 layouts.registered)
|
|
20
|
+
* ② 单页元素数 <= 12(超过必然溢出)
|
|
21
|
+
* ③ 非封面页必须有 role=title 的节点
|
|
22
|
+
* ④ 标题层级不跳级(有 subtitle 就必须先有 title)
|
|
23
|
+
* ⑤ 不得出现"页面级 override"式表达(.slide-N xxx)—— 那是事故形态
|
|
24
|
+
* ============================================================================
|
|
25
|
+
*/
|
|
26
|
+
'use strict';
|
|
27
|
+
|
|
28
|
+
var fs = require('fs');
|
|
29
|
+
var path = require('path');
|
|
30
|
+
|
|
31
|
+
var HERE = __dirname;
|
|
32
|
+
var MAX_PER_SLIDE = 12;
|
|
33
|
+
|
|
34
|
+
function main() {
|
|
35
|
+
var file = process.argv[2];
|
|
36
|
+
if (!file) {
|
|
37
|
+
process.stderr.write('用法:check.js <deck.json>\n');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
var deck = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
41
|
+
var schema = JSON.parse(fs.readFileSync(path.join(HERE, 'deck.schema.json'), 'utf8'));
|
|
42
|
+
var registered = schema.layouts.registered;
|
|
43
|
+
|
|
44
|
+
var errs = [];
|
|
45
|
+
var warns = [];
|
|
46
|
+
|
|
47
|
+
(deck.slides || []).forEach(function (slide, i) {
|
|
48
|
+
var at = '第 ' + (i + 1) + ' 页';
|
|
49
|
+
var sid = slide.id || (i + 1);
|
|
50
|
+
|
|
51
|
+
// ① 版面已登记
|
|
52
|
+
if (slide.layout && registered.indexOf(slide.layout) < 0) {
|
|
53
|
+
errs.push(at + ':版面 ' + slide.layout + ' 未登记(已登记:' +
|
|
54
|
+
registered.join(' / ') + ')');
|
|
55
|
+
}
|
|
56
|
+
if (!slide.layout) {
|
|
57
|
+
warns.push(at + ':没有指定版面');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
var nodes = slide.nodes || [];
|
|
61
|
+
// ② 单页元素上限
|
|
62
|
+
if (nodes.length > MAX_PER_SLIDE) {
|
|
63
|
+
errs.push(at + ':' + nodes.length + ' 个元素,超过上限 ' + MAX_PER_SLIDE +
|
|
64
|
+
' ⇒ 必然溢出,溢出后只能靠加特异性去救,那是事故的开始');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ③ 非封面/分隔页必须有标题
|
|
68
|
+
var roles = nodes.map(function (n) { return n.role; });
|
|
69
|
+
var isCover = slide.layout === 'title' || slide.layout === 'section-break';
|
|
70
|
+
if (!isCover && roles.indexOf('title') < 0 && !slide.title) {
|
|
71
|
+
errs.push(at + ':没有标题(既没有 slide.title,也没有 role=title 的节点)');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ④ 层级不跳级
|
|
75
|
+
if (roles.indexOf('subtitle') >= 0 && roles.indexOf('title') < 0 && !slide.title) {
|
|
76
|
+
errs.push(at + ':有 subtitle 但没有 title ⇒ 层级跳级');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ⑤ 页面级 override 式表达
|
|
80
|
+
var dump = JSON.stringify(slide);
|
|
81
|
+
if (/\.slide-/.test(dump) || /\.page-\d/.test(dump)) {
|
|
82
|
+
errs.push(at + ':出现了页面级选择器(.slide-N / .page-N)' +
|
|
83
|
+
' ⇒ 这正是事故的形态,请改组件而不是改页面');
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (warns.length) {
|
|
88
|
+
process.stdout.write(' ⚠️ 提示:\n');
|
|
89
|
+
warns.forEach(function (w) { process.stdout.write(' ' + w + '\n'); });
|
|
90
|
+
}
|
|
91
|
+
if (errs.length) {
|
|
92
|
+
process.stdout.write(' [FAIL] 呈现检查:\n');
|
|
93
|
+
errs.forEach(function (e) { process.stdout.write(' ' + e + '\n'); });
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
process.stdout.write(' [OK] 呈现检查通过(' + (deck.slides || []).length + ' 页)\n');
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (require.main === module) main();
|
|
101
|
+
module.exports = { MAX_PER_SLIDE: MAX_PER_SLIDE };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://frontend-lib.dev/adapters/presentation/deck.schema.json",
|
|
4
|
+
"title": "Presentation 形态:deck / slide 语义",
|
|
5
|
+
"$comment": [
|
|
6
|
+
"🔴 这份 schema **不属于核心契约**。",
|
|
7
|
+
" 核心(ai/contract.schema.json)里没有任何 slide / deck / page 的概念,",
|
|
8
|
+
" 这是故意的 —— 呈现形态会变,组件不变,绑在一起两边都动不了。",
|
|
9
|
+
"",
|
|
10
|
+
"本层把 slide/deck 语义挂在核心节点的 extensions.presentation 上:",
|
|
11
|
+
" · 核心校验器看到 extensions 就忽略 ⇒ 核心不需要知道 PPT 存在",
|
|
12
|
+
" · 本层读取它 ⇒ 做呈现特有的检查",
|
|
13
|
+
"⇒ 通过**数据**耦合,不通过**代码**耦合。"
|
|
14
|
+
],
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["schemaVersion", "slides"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"schemaVersion": { "type": "string" },
|
|
19
|
+
"title": { "type": "string" },
|
|
20
|
+
"slides": {
|
|
21
|
+
"type": "array",
|
|
22
|
+
"minItems": 1,
|
|
23
|
+
"items": { "$ref": "#/definitions/slide" }
|
|
24
|
+
},
|
|
25
|
+
"extensions": { "type": "object" }
|
|
26
|
+
},
|
|
27
|
+
"definitions": {
|
|
28
|
+
"slide": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"required": ["id", "nodes"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"id": { "type": "string" },
|
|
33
|
+
"layout": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"$comment": "版面名。**只允许用已登记的版面** —— 自由发挥的版面无法被检查。"
|
|
36
|
+
},
|
|
37
|
+
"title": { "type": "string" },
|
|
38
|
+
"nodes": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"maxItems": 12,
|
|
41
|
+
"$comment": [
|
|
42
|
+
"单页元素上限。🔴 这不是审美建议,是可判的约束:",
|
|
43
|
+
"超过这个数,任何版面都放不下 ⇒ 必然会溢出 ⇒ 溢出后只能靠加特异性去救,",
|
|
44
|
+
"那就是事故的开始。"
|
|
45
|
+
],
|
|
46
|
+
"items": { "$ref": "#/definitions/slideNode" }
|
|
47
|
+
},
|
|
48
|
+
"extensions": { "type": "object" }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"slideNode": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"required": ["id", "kind"],
|
|
54
|
+
"properties": {
|
|
55
|
+
"id": { "type": "string" },
|
|
56
|
+
"kind": { "type": "string" },
|
|
57
|
+
"text": { "type": "string" },
|
|
58
|
+
"props": { "type": "object" },
|
|
59
|
+
"children": { "type": "array", "items": { "type": "string" } },
|
|
60
|
+
"role": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"enum": ["title", "subtitle", "body", "caption", "media", "footer"],
|
|
63
|
+
"$comment": "在页内的语义角色。决定字号与层级,不决定具体色值(那是核心令牌的事)。"
|
|
64
|
+
},
|
|
65
|
+
"extensions": { "type": "object" }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"layouts": {
|
|
70
|
+
"$comment": "已登记版面(白名单)。需要新版面 ⇒ 先登记,再使用。",
|
|
71
|
+
"registered": ["title", "title-body", "two-col", "quote",
|
|
72
|
+
"media-caption", "bullets", "section-break", "closing"]
|
|
73
|
+
}
|
|
74
|
+
}
|