agentcss 0.0.0-stage → 0.11.3

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 (274) hide show
  1. package/01-tokens/README.md +236 -0
  2. package/01-tokens/behavior/dismissable.js +132 -0
  3. package/01-tokens/behavior/emit.js +76 -0
  4. package/01-tokens/behavior/focus-return.js +81 -0
  5. package/01-tokens/behavior/roving.js +152 -0
  6. package/01-tokens/behavior/typeahead.js +124 -0
  7. package/01-tokens/focus-ring-demo.html +133 -0
  8. package/01-tokens/focus-ring.css +102 -0
  9. package/01-tokens/page.css +244 -0
  10. package/01-tokens/polyfill.js +116 -0
  11. package/01-tokens/responsive-demo.html +171 -0
  12. package/01-tokens/scrollbar-demo.html +194 -0
  13. package/01-tokens/scrollbar.css +179 -0
  14. package/01-tokens/theme-toggle.js +103 -0
  15. package/01-tokens/tokens.css +972 -0
  16. package/01-tokens/typography.css +156 -0
  17. package/02-primitives/badge/README.md +71 -0
  18. package/02-primitives/badge/badge.css +141 -0
  19. package/02-primitives/badge/demo.html +101 -0
  20. package/02-primitives/button/README.md +99 -0
  21. package/02-primitives/button/button.css +353 -0
  22. package/02-primitives/button/demo.html +200 -0
  23. package/02-primitives/card/README.md +145 -0
  24. package/02-primitives/card/card.css +246 -0
  25. package/02-primitives/card/demo.html +170 -0
  26. package/02-primitives/choice/README.md +161 -0
  27. package/02-primitives/choice/choice.css +395 -0
  28. package/02-primitives/choice/demo.html +277 -0
  29. package/02-primitives/combobox/README.md +79 -0
  30. package/02-primitives/combobox/combobox.css +223 -0
  31. package/02-primitives/combobox/combobox.js +485 -0
  32. package/02-primitives/combobox/demo.html +109 -0
  33. package/02-primitives/date-range/README.md +100 -0
  34. package/02-primitives/date-range/date-range.css +206 -0
  35. package/02-primitives/date-range/date-range.js +301 -0
  36. package/02-primitives/date-range/demo.html +104 -0
  37. package/02-primitives/input/README.md +170 -0
  38. package/02-primitives/input/demo.html +246 -0
  39. package/02-primitives/input/input.css +239 -0
  40. package/02-primitives/popover/README.md +80 -0
  41. package/02-primitives/popover/demo.html +150 -0
  42. package/02-primitives/popover/popover.css +187 -0
  43. package/02-primitives/popover/popover.js +331 -0
  44. package/02-primitives/progress/README.md +82 -0
  45. package/02-primitives/progress/demo.html +154 -0
  46. package/02-primitives/progress/progress.css +172 -0
  47. package/02-primitives/select/README.md +95 -0
  48. package/02-primitives/select/demo.html +121 -0
  49. package/02-primitives/select/select.css +151 -0
  50. package/02-primitives/select/select.js +549 -0
  51. package/02-primitives/separator/README.md +63 -0
  52. package/02-primitives/separator/demo.html +84 -0
  53. package/02-primitives/separator/separator.css +73 -0
  54. package/02-primitives/skeleton/README.md +69 -0
  55. package/02-primitives/skeleton/demo.html +110 -0
  56. package/02-primitives/skeleton/skeleton.css +96 -0
  57. package/02-primitives/switch/README.md +65 -0
  58. package/02-primitives/switch/demo.html +115 -0
  59. package/02-primitives/switch/switch.css +370 -0
  60. package/03-patterns/accordion/README.md +121 -0
  61. package/03-patterns/accordion/accordion.css +453 -0
  62. package/03-patterns/accordion/accordion.js +369 -0
  63. package/03-patterns/accordion/demo.html +223 -0
  64. package/03-patterns/content/README.md +103 -0
  65. package/03-patterns/content/content.css +286 -0
  66. package/03-patterns/content/demo.html +88 -0
  67. package/03-patterns/drawer/README.md +79 -0
  68. package/03-patterns/drawer/demo.html +101 -0
  69. package/03-patterns/drawer/drawer.css +129 -0
  70. package/03-patterns/drawer/drawer.js +258 -0
  71. package/03-patterns/dropdown/README.md +78 -0
  72. package/03-patterns/dropdown/demo.html +101 -0
  73. package/03-patterns/dropdown/dropdown.css +135 -0
  74. package/03-patterns/dropdown/dropdown.js +451 -0
  75. package/03-patterns/form-validation/README.md +147 -0
  76. package/03-patterns/form-validation/demo.html +280 -0
  77. package/03-patterns/form-validation/form-validation.css +263 -0
  78. package/03-patterns/list/README.md +150 -0
  79. package/03-patterns/list/demo.html +225 -0
  80. package/03-patterns/list/flip.js +201 -0
  81. package/03-patterns/list/list.css +162 -0
  82. package/03-patterns/nav/README.md +225 -0
  83. package/03-patterns/nav/demo.html +131 -0
  84. package/03-patterns/nav/nav.css +314 -0
  85. package/03-patterns/nav/nav.js +430 -0
  86. package/03-patterns/nav/toc.js +111 -0
  87. package/03-patterns/overlay/README.md +196 -0
  88. package/03-patterns/overlay/demo.html +241 -0
  89. package/03-patterns/overlay/overlay.css +319 -0
  90. package/03-patterns/overlay/overlay.js +563 -0
  91. package/03-patterns/pagination/README.md +114 -0
  92. package/03-patterns/pagination/demo.html +165 -0
  93. package/03-patterns/pagination/pagination.css +195 -0
  94. package/03-patterns/pagination/pagination.js +395 -0
  95. package/03-patterns/reveal/README.md +91 -0
  96. package/03-patterns/reveal/demo.html +106 -0
  97. package/03-patterns/reveal/reveal.css +93 -0
  98. package/03-patterns/reveal/reveal.js +172 -0
  99. package/03-patterns/states/README.md +141 -0
  100. package/03-patterns/states/demo.html +240 -0
  101. package/03-patterns/states/states.css +252 -0
  102. package/03-patterns/tabs/README.md +84 -0
  103. package/03-patterns/tabs/demo.html +139 -0
  104. package/03-patterns/tabs/tabs.css +172 -0
  105. package/03-patterns/tabs/tabs.js +307 -0
  106. package/03-patterns/tooltip/README.md +96 -0
  107. package/03-patterns/tooltip/demo.html +78 -0
  108. package/03-patterns/tooltip/tooltip.css +89 -0
  109. package/03-patterns/tooltip/tooltip.js +288 -0
  110. package/03-patterns/tree/README.md +94 -0
  111. package/03-patterns/tree/demo.html +138 -0
  112. package/03-patterns/tree/tree.css +113 -0
  113. package/03-patterns/tree/tree.js +456 -0
  114. package/04-recipes/analysis-report/README.md +80 -0
  115. package/04-recipes/analysis-report/analysis-report.css +187 -0
  116. package/04-recipes/analysis-report/demo.html +274 -0
  117. package/04-recipes/data-showcase/README.md +45 -0
  118. package/04-recipes/data-showcase/demo.html +247 -0
  119. package/04-recipes/detail-page/README.md +93 -0
  120. package/04-recipes/detail-page/demo.html +55 -0
  121. package/04-recipes/detail-page/detail-page.css +190 -0
  122. package/04-recipes/detail-page/full.html +60 -0
  123. package/04-recipes/detail-page/null.html +60 -0
  124. package/04-recipes/detail-page/partial.html +60 -0
  125. package/04-recipes/detail-page/verify-skeleton.py +19 -0
  126. package/04-recipes/longform/README.md +93 -0
  127. package/04-recipes/longform/agc-memory.svg +4 -0
  128. package/04-recipes/longform/content.html +610 -0
  129. package/04-recipes/longform/content.md +51 -0
  130. package/04-recipes/longform/longform.html +627 -0
  131. package/04-recipes/report/README.md +176 -0
  132. package/04-recipes/report/demo.html +355 -0
  133. package/04-recipes/report/report.css +364 -0
  134. package/04-recipes/table/README.md +103 -0
  135. package/04-recipes/table/demo.html +455 -0
  136. package/04-recipes/table/table.css +372 -0
  137. package/04-recipes/tierA-tokens.css +189 -0
  138. package/09-assets/README.md +74 -0
  139. package/09-assets/bar/README.md +94 -0
  140. package/09-assets/bar/bar.css +166 -0
  141. package/09-assets/bar/bar.js +320 -0
  142. package/09-assets/bar/demo.html +176 -0
  143. package/09-assets/echarts-adapter/demo.html +192 -0
  144. package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
  145. package/09-assets/model-viewer/README.md +155 -0
  146. package/09-assets/model-viewer/demo.html +105 -0
  147. package/09-assets/model-viewer/model-viewer.css +143 -0
  148. package/09-assets/model-viewer/model-viewer.js +423 -0
  149. package/09-assets/scientific-plot/README.md +94 -0
  150. package/09-assets/scientific-plot/demo.html +252 -0
  151. package/09-assets/scientific-plot/scientific-plot.css +141 -0
  152. package/09-assets/scientific-plot/scientific-plot.js +610 -0
  153. package/09-assets/sparkline/README.md +153 -0
  154. package/09-assets/sparkline/demo.html +163 -0
  155. package/09-assets/sparkline/sparkline.css +158 -0
  156. package/09-assets/sparkline/sparkline.js +508 -0
  157. package/API.md +332 -0
  158. package/CHANGELOG.md +3138 -0
  159. package/CODE_OF_CONDUCT.md +64 -0
  160. package/CONTRIBUTING.md +89 -0
  161. package/ERRORS.md +1658 -0
  162. package/LICENSE +21 -0
  163. package/README.md +497 -2
  164. package/SECURITY.md +72 -0
  165. package/START-HERE.md +164 -0
  166. package/SUPPORT.md +109 -0
  167. package/adapters/presentation/README.md +113 -0
  168. package/adapters/presentation/check.js +101 -0
  169. package/adapters/presentation/deck.schema.json +74 -0
  170. package/adapters/presentation/to-doc.js +138 -0
  171. package/ai/START-HERE.md +104 -0
  172. package/ai/behaviors.json +380 -0
  173. package/ai/behaviors.schema.json +61 -0
  174. package/ai/capabilities.json +56 -0
  175. package/ai/cli.js +387 -0
  176. package/ai/components.json +1944 -0
  177. package/ai/components.meta.json +168 -0
  178. package/ai/components.schema.json +220 -0
  179. package/ai/contract.schema.json +147 -0
  180. package/ai/deprecations.json +55 -0
  181. package/ai/deprecations.schema.json +85 -0
  182. package/ai/motion-policy.json +22 -0
  183. package/ai/patch.js +323 -0
  184. package/ai/patch.schema.json +63 -0
  185. package/ai/profiles.json +92 -0
  186. package/ai/tokens.audience.json +55 -0
  187. package/ai/tokens.audience.schema.json +73 -0
  188. package/ai/tokens.json +762 -0
  189. package/ai/tokens.schema.json +58 -0
  190. package/ai/tokens.tree.json +752 -0
  191. package/ai/tokens.tree.schema.json +56 -0
  192. package/ai/validate.js +383 -0
  193. package/dist/01-tokens/behavior/dismissable.js +60 -0
  194. package/dist/01-tokens/behavior/emit.js +21 -0
  195. package/dist/01-tokens/behavior/focus-return.js +31 -0
  196. package/dist/01-tokens/behavior/roving.js +77 -0
  197. package/dist/01-tokens/behavior/typeahead.js +61 -0
  198. package/dist/01-tokens/focus-ring.css +1 -0
  199. package/dist/01-tokens/page.css +1 -0
  200. package/dist/01-tokens/polyfill.js +78 -0
  201. package/dist/01-tokens/scrollbar.css +1 -0
  202. package/dist/01-tokens/theme-toggle.js +61 -0
  203. package/dist/01-tokens/tokens.css +1 -0
  204. package/dist/01-tokens/typography.css +1 -0
  205. package/dist/02-primitives/badge/badge.css +1 -0
  206. package/dist/02-primitives/button/button.css +1 -0
  207. package/dist/02-primitives/card/card.css +1 -0
  208. package/dist/02-primitives/choice/choice.css +1 -0
  209. package/dist/02-primitives/combobox/combobox.css +1 -0
  210. package/dist/02-primitives/combobox/combobox.js +439 -0
  211. package/dist/02-primitives/date-range/date-range.css +1 -0
  212. package/dist/02-primitives/date-range/date-range.js +267 -0
  213. package/dist/02-primitives/input/input.css +1 -0
  214. package/dist/02-primitives/popover/popover.css +1 -0
  215. package/dist/02-primitives/popover/popover.js +257 -0
  216. package/dist/02-primitives/progress/progress.css +1 -0
  217. package/dist/02-primitives/select/select.css +1 -0
  218. package/dist/02-primitives/select/select.js +449 -0
  219. package/dist/02-primitives/separator/separator.css +1 -0
  220. package/dist/02-primitives/skeleton/skeleton.css +1 -0
  221. package/dist/02-primitives/switch/switch.css +1 -0
  222. package/dist/03-patterns/accordion/accordion.css +1 -0
  223. package/dist/03-patterns/accordion/accordion.js +219 -0
  224. package/dist/03-patterns/content/content.css +1 -0
  225. package/dist/03-patterns/drawer/drawer.css +1 -0
  226. package/dist/03-patterns/drawer/drawer.js +229 -0
  227. package/dist/03-patterns/dropdown/dropdown.css +1 -0
  228. package/dist/03-patterns/dropdown/dropdown.js +365 -0
  229. package/dist/03-patterns/form-validation/form-validation.css +1 -0
  230. package/dist/03-patterns/list/flip.js +117 -0
  231. package/dist/03-patterns/list/list.css +1 -0
  232. package/dist/03-patterns/nav/nav.css +1 -0
  233. package/dist/03-patterns/nav/nav.js +322 -0
  234. package/dist/03-patterns/nav/toc.js +76 -0
  235. package/dist/03-patterns/overlay/overlay.css +1 -0
  236. package/dist/03-patterns/overlay/overlay.js +398 -0
  237. package/dist/03-patterns/pagination/pagination.css +1 -0
  238. package/dist/03-patterns/pagination/pagination.js +273 -0
  239. package/dist/03-patterns/reveal/reveal.css +1 -0
  240. package/dist/03-patterns/reveal/reveal.js +138 -0
  241. package/dist/03-patterns/states/states.css +1 -0
  242. package/dist/03-patterns/tabs/tabs.css +1 -0
  243. package/dist/03-patterns/tabs/tabs.js +242 -0
  244. package/dist/03-patterns/tooltip/tooltip.css +1 -0
  245. package/dist/03-patterns/tooltip/tooltip.js +213 -0
  246. package/dist/03-patterns/tree/tree.css +1 -0
  247. package/dist/03-patterns/tree/tree.js +383 -0
  248. package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
  249. package/dist/04-recipes/detail-page/detail-page.css +1 -0
  250. package/dist/04-recipes/report/report.css +1 -0
  251. package/dist/04-recipes/table/table.css +1 -0
  252. package/dist/04-recipes/tierA-tokens.css +1 -0
  253. package/dist/09-assets/bar/bar.css +1 -0
  254. package/dist/09-assets/bar/bar.js +222 -0
  255. package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
  256. package/dist/09-assets/model-viewer/model-viewer.css +1 -0
  257. package/dist/09-assets/model-viewer/model-viewer.js +320 -0
  258. package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
  259. package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
  260. package/dist/09-assets/sparkline/sparkline.css +1 -0
  261. package/dist/09-assets/sparkline/sparkline.js +265 -0
  262. package/dist/COSTS.md +56 -0
  263. package/docs/AI-CONTRACT.md +197 -0
  264. package/docs/BACKLOG.md +127 -0
  265. package/docs/BENCHMARK.md +252 -0
  266. package/docs/GUIDANCE.md +154 -0
  267. package/docs/INVARIANT.md +372 -0
  268. package/docs/LAYER-BASELINE.md +158 -0
  269. package/docs/RELEASING.md +311 -0
  270. package/docs/RFC-THEME-SCOPE.md +141 -0
  271. package/docs/ROADMAP.md +182 -0
  272. package/index.html +82 -0
  273. package/package.json +107 -4
  274. package/types/index.d.ts +310 -0
@@ -0,0 +1,185 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ function cssVar(name, fallback) {
5
+ if (typeof window.getComputedStyle !== 'function') return fallback;
6
+ var v = getComputedStyle(document.documentElement).getPropertyValue(name);
7
+ return (v && v.trim()) || fallback;
8
+ }
9
+
10
+ function palette() {
11
+ return {
12
+ text: cssVar('--text-primary', '#15181c'),
13
+ textSub: cssVar('--text-secondary', '#5b6472'),
14
+ textTertiary: cssVar('--text-tertiary', '#8a94a3'),
15
+ surface: cssVar('--surface', '#ffffff'),
16
+ paper: cssVar('--paper', '#f6f7f8'),
17
+ border: cssVar('--border-decor', '#e2e5e9'),
18
+ borderStrong: cssVar('--border-control', '#868b94'),
19
+ danger: cssVar('--danger', '#c0392b'),
20
+ success: cssVar('--success', '#2e7d52'),
21
+ warn: cssVar('--warning', '#b8860b'),
22
+ info: cssVar('--info', '#2b7a9e'),
23
+ accent: cssVar('--accent', '#1b4d8f'),
24
+ };
25
+ }
26
+
27
+ function seriesColors(n, p) {
28
+ var ramp = [p.accent, p.danger, p.success, p.warn, p.info];
29
+ if (n > ramp.length) return null;
30
+ return ramp.slice(0, n);
31
+ }
32
+
33
+ function theme(name, p) {
34
+ p = p || palette();
35
+ var isDark = document.documentElement.getAttribute('data-theme-current') === 'dark'
36
+ || cssVar('--paper', '#fff') !== '#f6f7f8';
37
+
38
+ return {
39
+ color: [p.accent, p.danger, p.success, p.warn, p.info],
40
+ backgroundColor: 'transparent',
41
+ textStyle: {
42
+ color: p.text,
43
+ fontFamily: cssVar('--sans', 'system-ui, sans-serif'),
44
+ },
45
+ title: {
46
+ textStyle: { color: p.text, fontWeight: 600 },
47
+ subtextStyle: { color: p.textSub },
48
+ },
49
+ legend: { textStyle: { color: p.textSub } },
50
+ tooltip: {
51
+ backgroundColor: isDark ? '#1c2024' : '#ffffff',
52
+ borderColor: p.border,
53
+ borderWidth: 1,
54
+ textStyle: { color: p.text, fontSize: 12 },
55
+
56
+ extraCssText: isDark
57
+ ? 'box-shadow:0 2px 8px rgba(0,0,0,.5);'
58
+ : 'box-shadow:0 2px 8px rgba(0,0,0,.1);',
59
+ },
60
+ categoryAxis: axisCommon(p, isDark),
61
+ valueAxis: axisCommon(p, isDark),
62
+ logAxis: axisCommon(p, isDark),
63
+ timeAxis: axisCommon(p, isDark),
64
+ };
65
+ }
66
+
67
+ function axisCommon(p, isDark) {
68
+ return {
69
+ axisLine: { lineStyle: { color: p.border } },
70
+ axisTick: { show: false },
71
+ axisLabel: { color: p.textSub, fontSize: 11 },
72
+ splitLine: { lineStyle: { color: p.border, type: 'dashed' } },
73
+
74
+ splitNumber: 4,
75
+ };
76
+ }
77
+
78
+ function defaults(option) {
79
+ var p = palette();
80
+ var o = option || {};
81
+
82
+ o.textStyle = merge(o.textStyle, {
83
+ fontFamily: cssVar('--mono', 'ui-monospace, monospace'),
84
+ });
85
+
86
+ o.grid = merge(o.grid, { left: 56, right: 24, top: 32, bottom: 32, containLabel: false });
87
+
88
+ o.series = (o.series || []).map(function (s) {
89
+ if (s.type === 'line') {
90
+ return merge(s, {
91
+ smooth: false,
92
+ showSymbol: (s.data || []).length <= 7,
93
+ symbolSize: 5,
94
+ lineStyle: merge(s.lineStyle, { width: 2 }),
95
+ });
96
+ }
97
+ if (s.type === 'bar') {
98
+ return merge(s, {
99
+ barMaxWidth: 28,
100
+
101
+ });
102
+ }
103
+ if (s.type === 'area') {
104
+ return merge(s, {
105
+ areaStyle: merge(s.areaStyle, { opacity: 0.14 }),
106
+ });
107
+ }
108
+ return s;
109
+ });
110
+
111
+ var isBar = o.series.some(function (s) { return s.type === 'bar'; });
112
+ if (isBar && o.yAxis) {
113
+ var y = Array.isArray(o.yAxis) ? o.yAxis[0] : o.yAxis;
114
+ if (y && y.min === undefined) y.min = 0;
115
+ }
116
+
117
+ if (o.series.length > 5) {
118
+ if (typeof console !== 'undefined' && console.warn) {
119
+ console.warn('[frontend-lib] 系列数 ' + o.series.length +
120
+ ' 超过 5 —— 请改图表类型或分屏,见 charter 10。配色循环会让颜色撞车。');
121
+ }
122
+ }
123
+
124
+ return o;
125
+ }
126
+
127
+ function currentThemeName() {
128
+ return 'fe-' +
129
+ (document.documentElement.getAttribute('data-theme-current') || 'light');
130
+ }
131
+
132
+ function create(dom, opt) {
133
+ if (typeof window.echarts === 'undefined') {
134
+ if (typeof console !== 'undefined' && console.warn) {
135
+ console.warn('[frontend-lib] 未检测到 ECharts —— ' +
136
+ '请在主项目里自行引入(前端库本身零依赖)。');
137
+ }
138
+ return null;
139
+ }
140
+ var name = currentThemeName();
141
+
142
+ if (typeof window.echarts.registerTheme === 'function') {
143
+ window.echarts.registerTheme(name, theme(name));
144
+ }
145
+ var inst = window.echarts.init(dom, name);
146
+ inst.__feDom = dom;
147
+ inst.__feOpts = opt || {};
148
+ inst.__feTheme = name;
149
+ inst.setOption(defaults(inst.__feOpts));
150
+ return inst;
151
+ }
152
+
153
+ function merge(a, b) {
154
+ var o = {}, k;
155
+ if (a) for (k in a) if (a.hasOwnProperty(k)) o[k] = a[k];
156
+ if (b) for (k in b) if (b.hasOwnProperty(k)) o[k] = b[k];
157
+ return o;
158
+ }
159
+
160
+ var ChartAdapter = {
161
+ cssVar: cssVar,
162
+ palette: palette,
163
+ seriesColors: seriesColors,
164
+ theme: theme,
165
+ defaults: defaults,
166
+ create: create,
167
+
168
+ refresh: function (inst) {
169
+ if (!inst) return;
170
+ var name = currentThemeName();
171
+ if (typeof window.echarts !== 'undefined' && window.echarts.registerTheme) {
172
+ window.echarts.registerTheme(name, theme(name));
173
+ }
174
+
175
+ if (inst.__feDom) {
176
+ var opt = inst.__feOpts;
177
+ inst.dispose();
178
+ return create(inst.__feDom, opt);
179
+ }
180
+ inst.setOption(defaults(inst.__feOpts), name);
181
+ return inst;
182
+ },
183
+ };
184
+ if (typeof window !== 'undefined') window.ChartAdapter = ChartAdapter;
185
+ })();
@@ -0,0 +1 @@
1
+ .mv {position:relative;display:block;width:100%;box-sizing:border-box;border:1px solid var(--border-decor);border-radius:var(--r-md);background:var(--surface);overflow:hidden;}.mv__stage {display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-2);min-height:180px;padding:var(--sp-5) var(--sp-4);background:var(--surface-sunken);text-align:center;}.mv__stage--err {border-inline-start:3px solid var(--danger);}.mv__ph {font-size:var(--fs-sm);color:var(--text-tertiary);letter-spacing:0.08em;text-transform:uppercase;}.mv__status, .mv__err {margin:0;font-size:var(--fs-sm);color:var(--text-secondary);line-height:1.6;}.mv__err {color:var(--danger);}.mv__btn {display:block;width:calc(100% - var(--sp-6));margin:var(--sp-3) var(--sp-3) 0;min-height:44px;padding:var(--sp-2) var(--sp-4);font:inherit;font-size:var(--fs-sm);font-weight:500;color:var(--text-on-accent);background:var(--accent);border:0;border-radius:var(--r-sm);cursor:pointer;-webkit-tap-highlight-color:transparent;transition:background var(--dur-fast) var(--ease-out);}.mv__btn:hover:not(:disabled) {background:var(--accent-hover);}.mv__btn:disabled {opacity:0.5;cursor:not-allowed;}.mv__btn:focus-visible {outline:2px solid var(--accent);outline-offset:2px;}.mv__hint {margin:0;padding:0 var(--sp-3) var(--sp-3);font-size:var(--fs-xs);color:var(--text-tertiary);line-height:1.6;}.mv__hint code {font-family:var(--mono);font-size:1em;color:var(--text-secondary);}.mv canvas {display:block;width:100% !important;height:auto !important;touch-action:none;background:transparent;}.mv__cap {margin:0;padding:var(--sp-2) var(--sp-3);font-size:var(--fs-xs);color:var(--text-secondary);background:var(--surface);border-top:1px solid var(--border-decor);line-height:1.6;}.mv__cap b {font-family:var(--mono);font-weight:600;color:var(--text-primary);font-variant-numeric:tabular-nums;}@media (prefers-reduced-motion:reduce) {.mv__btn {transition:none;}}@media print {.mv__btn, .mv__hint {display:none;}}@media (hover:hover) and (pointer:fine) {.mv__btn:hover:not(:disabled) {background:var(--accent-hover);}}
@@ -0,0 +1,320 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ function el(tag, cls, text) {
5
+ var n = document.createElement(tag);
6
+ if (cls) n.className = cls;
7
+ if (text !== undefined && text !== null) n.textContent = text;
8
+ return n;
9
+ }
10
+
11
+ function hasWebGL() {
12
+ try {
13
+ var c = document.createElement('canvas');
14
+ return !!(c.getContext('webgl2') || c.getContext('webgl') ||
15
+ c.getContext('experimental-webgl'));
16
+ } catch (e) { return false; }
17
+ }
18
+
19
+ function loadScript(src) {
20
+ return new Promise(function (resolve, reject) {
21
+ if (!src) { resolve(); return; }
22
+ var s = document.createElement('script');
23
+ s.src = src;
24
+ s.async = false;
25
+ s.onload = function () { resolve(); };
26
+ s.onerror = function () {
27
+ reject(new Error('脚本加载失败:' + src));
28
+ };
29
+ document.head.appendChild(s);
30
+ });
31
+ }
32
+
33
+ function fmtKB(bytes) {
34
+ return Math.round(bytes / 1024) + ' KB';
35
+ }
36
+
37
+ function Viewer(node) {
38
+ this.node = node;
39
+
40
+ var q = (location.search || '').replace(/^\?/, '');
41
+ function qp(k, dflt) {
42
+ var m = new RegExp('(?:^|&)' + k + '=([^&]*)').exec(q);
43
+ return m ? decodeURIComponent(m[1]) : dflt;
44
+ }
45
+ this.qOverride = !!q;
46
+ this.src = qp('mv', node.getAttribute('data-mv') || '');
47
+ this.h = parseInt(node.getAttribute('data-mv-height') || '320', 10);
48
+ this.threeSrc = qp('three', node.getAttribute('data-mv-three') || '');
49
+ this.gltfSrc = qp('gltf', node.getAttribute('data-mv-gltf') || '');
50
+ this.orbitSrc = qp('orbit', node.getAttribute('data-mv-orbit') || '');
51
+ this.instances = {};
52
+ this.state = 'idle';
53
+ this.build();
54
+ }
55
+
56
+ Viewer.prototype.build = function () {
57
+ var self = this;
58
+ var n = this.node;
59
+ n.classList.add('mv');
60
+
61
+ this.ui = el('div', 'mv__ui');
62
+ this.ui.appendChild(this.makeIdle());
63
+ n.appendChild(this.ui);
64
+
65
+ this.btn = el('button', 'mv__btn', '加载 3D 模型');
66
+ this.btn.type = 'button';
67
+ this.btn.addEventListener('click', function () { self.load(); });
68
+ this.ui.appendChild(this.btn);
69
+
70
+ this.hint = el('p', 'mv__hint');
71
+ this.hint.innerHTML = '模型 <code>' + (this.src.split('/').pop() || '—') +
72
+ '</code> 会<b>点击后才下载</b>,首屏不占流量。';
73
+ this.ui.appendChild(this.hint);
74
+
75
+ if (!hasWebGL()) {
76
+ this.fail('这台设备的浏览器不支持 WebGL,无法显示 3D 模型。');
77
+ this.btn.disabled = true;
78
+ }
79
+ };
80
+
81
+ Viewer.prototype.makeIdle = function () {
82
+ var box = el('div', 'mv__stage');
83
+ box.appendChild(el('div', 'mv__ph', '3D 模型'));
84
+ return box;
85
+ };
86
+
87
+ Viewer.prototype.fail = function (msg) {
88
+ if (this.timer) { clearTimeout(this.timer); this.timer = null; }
89
+ this.state = 'error';
90
+ this.ui.innerHTML = '';
91
+ var s = el('div', 'mv__stage mv__stage--err');
92
+ s.appendChild(el('div', 'mv__ph', '3D 模型'));
93
+ var p = el('p', 'mv__err', msg);
94
+ s.appendChild(p);
95
+ this.ui.appendChild(s);
96
+ if (this.btn) this.ui.appendChild(this.btn);
97
+ if (this.btn) {
98
+ this.btn.disabled = false;
99
+ this.btn.textContent = '重试';
100
+ }
101
+ };
102
+
103
+ Viewer.prototype.status = function (msg) {
104
+ if (this.statusNode) { this.statusNode.textContent = msg; }
105
+ };
106
+
107
+ Viewer.prototype.load = function () {
108
+ var self = this;
109
+ if (this.state === 'loading' || this.state === 'ok') return;
110
+ this.state = 'loading';
111
+
112
+ this.ui.innerHTML = '';
113
+ var stage = el('div', 'mv__stage');
114
+ this.statusNode = el('p', 'mv__status', '正在准备…');
115
+ stage.appendChild(this.statusNode);
116
+ this.ui.appendChild(stage);
117
+
118
+ var t0 = (window.performance && performance.now) ? performance.now() : Date.now();
119
+ this.status('正在准备 3D 引擎…');
120
+ this.boot(null, t0, 0);
121
+
122
+ var self0 = this;
123
+ this.timer = setTimeout(function () {
124
+ if (self0.state === 'loading') {
125
+ self0.fail('加载超时(20 秒)。请检查:' +
126
+ '① 模型路径是否正确:'+ self0.src +
127
+ '② 服务器是否能返回该文件(404 时也应给明确提示)');
128
+ }
129
+ }, 20000);
130
+ };
131
+
132
+ Viewer.prototype.boot = function (buf, t0, bytes) {
133
+ var self = this;
134
+
135
+ loadScript(this.threeSrc)
136
+ .then(function () { return loadScript(self.gltfSrc); })
137
+ .then(function () { return loadScript(self.orbitSrc); })
138
+ .then(function () { self.initScene(buf, t0, bytes); })
139
+ .catch(function (err) {
140
+ self.fail('3D 引擎加载失败:' + (err && err.message ? err.message : err) +
141
+ '。请检查 three.js / GLTFLoader.js / OrbitControls.js 的路径。');
142
+ });
143
+ };
144
+
145
+ Viewer.prototype.initScene = function (buf, t0, bytes) {
146
+ var self = this;
147
+ if (typeof window.THREE === 'undefined') {
148
+ this.fail('three.js 没有正确加载(THREE 未定义)。请检查 data-mv-three 的路径。');
149
+ return;
150
+ }
151
+
152
+ var W = this.node.clientWidth || 320;
153
+ var H = this.h;
154
+
155
+ var scene = new THREE.Scene();
156
+ var camera = new THREE.PerspectiveCamera(45, W / H, 0.1, 100);
157
+ camera.position.set(0, 0.6, 2.4);
158
+
159
+ var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
160
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
161
+ renderer.setSize(W, H);
162
+ renderer.setClearColor(0x000000, 0);
163
+ this.ui.innerHTML = '';
164
+ this.node.appendChild(renderer.domElement);
165
+ this.statusNode = null;
166
+
167
+ scene.add(new THREE.AmbientLight(0xffffff, 0.45));
168
+ var key = new THREE.DirectionalLight(0xffffff, 0.9);
169
+ key.position.set(1, 1.6, 1.4);
170
+ scene.add(key);
171
+ var rim = new THREE.DirectionalLight(0xffffff, 0.35);
172
+ rim.position.set(-1.2, 0.4, -1);
173
+ scene.add(rim);
174
+
175
+ var OrbitCtor = (window.THREE && window.THREE.OrbitControls) || window.OrbitControls;
176
+ var controls = null;
177
+ if (OrbitCtor) {
178
+ controls = new OrbitCtor(camera, renderer.domElement);
179
+ controls.enableDamping = true;
180
+ controls.dampingFactor = 0.08;
181
+ controls.enablePan = false;
182
+ controls.minDistance = 1.1;
183
+ controls.maxDistance = 4.5;
184
+ controls.target.set(0, 0.35, 0);
185
+ }
186
+
187
+ var GLCtor = (window.THREE && window.THREE.GLTFLoader) || window.GLTFLoader;
188
+ if (!GLCtor) {
189
+ this.fail('GLTFLoader 没有正确加载(THREE.GLTFLoader 未定义)。请检查 data-mv-gltf 的路径。');
190
+ return;
191
+ }
192
+
193
+ var loader = new GLCtor();
194
+
195
+ var self1 = this;
196
+ var xhr = new XMLHttpRequest();
197
+ xhr.responseType = 'arraybuffer';
198
+ xhr.open('GET', this.src, true);
199
+ xhr.onprogress = function (e) {
200
+ if (e.lengthComputable && e.total) {
201
+ self1.lastBytes = e.total;
202
+ self1.status('正在下载模型 ' + Math.round(e.loaded / e.total * 100) + '%');
203
+ }
204
+ };
205
+ xhr.onload = function () {
206
+ if (xhr.status >= 400) {
207
+ self1.fail('模型不存在(HTTP ' + xhr.status + '):' + self1.src);
208
+ return;
209
+ }
210
+ var buf = xhr.response;
211
+
212
+ if (!buf || buf.byteLength < 12) {
213
+ self1.fail('模型文件是空的或损坏了:' + self1.src);
214
+ return;
215
+ }
216
+
217
+ var b0 = new Uint8Array(buf, 0, 4);
218
+ var head = String.fromCharCode(b0[0], b0[1], b0[2], b0[3]);
219
+ if (head !== 'glTF') {
220
+ self1.fail('这不是 glb 文件(缺少 glTF 标识,收到的是「' + head + '」)。' +
221
+ '服务器可能返回了 HTML 错误页。');
222
+ return;
223
+ }
224
+ doLoad(buf);
225
+ };
226
+ xhr.onerror = function () { self1.fail('无法访问模型:' + self1.src); };
227
+ xhr.send();
228
+
229
+ function doLoad(buf) {
230
+ loader.parse(buf, '', function (gltf) {
231
+ var model = gltf.scene;
232
+
233
+ var box = new THREE.Box3().setFromObject(model);
234
+ var size = box.getSize(new THREE.Vector3());
235
+ var center = box.getCenter(new THREE.Vector3());
236
+ model.position.sub(center);
237
+ var maxDim = Math.max(size.x, size.y, size.z) || 1;
238
+ model.scale.setScalar(1.6 / maxDim);
239
+ box.setFromObject(model);
240
+ var c2 = box.getCenter(new THREE.Vector3());
241
+ model.position.sub(new THREE.Vector3(c2.x, box.min.y + (box.max.y - box.min.y) * 0.45, c2.z));
242
+ scene.add(model);
243
+
244
+ if (self.timer) { clearTimeout(self.timer); self.timer = null; }
245
+ self.state = 'ok';
246
+ self.instances = { scene: scene, camera: camera, renderer: renderer,
247
+ model: model, controls: controls };
248
+
249
+ var last = 0;
250
+ function loop(t) {
251
+ self.raf = requestAnimationFrame(loop);
252
+
253
+ if (document.hidden) return;
254
+ if (controls) controls.update();
255
+ renderer.render(scene, camera);
256
+ last = t;
257
+ }
258
+ self.raf = requestAnimationFrame(loop);
259
+
260
+ self.ui.innerHTML = '';
261
+ var cap = el('p', 'mv__cap');
262
+ var dt = Math.round(((window.performance && performance.now) ? performance.now() : Date.now()) - t0);
263
+ cap.innerHTML = '模型 <b>' + fmtKB(bytes || self.lastBytes || 0) + '</b> · 引擎就绪耗时 <b>' + dt + 'ms</b>' +
264
+ (controls ? ' · 拖动可旋转,滚轮/双指可缩放' : ' · 未加载控制器,无法拖动');
265
+ self.node.appendChild(cap);
266
+ },
267
+
268
+ function (evt) {
269
+ if (evt && evt.lengthComputable && evt.total) {
270
+ self.lastBytes = evt.total;
271
+ self.status('正在下载模型 ' + Math.round(evt.loaded / evt.total * 100) + '%');
272
+ }
273
+ },
274
+
275
+ function (err) {
276
+ var msg = (err && err.message) ? err.message : (err || '未知错误');
277
+
278
+ if (msg.indexOf('fetch') > -1 || msg.indexOf('Failed') > -1) {
279
+ self.fail('模型加载失败:服务器的 Content-Security-Policy 缺少 blob:,' +
280
+ '内嵌贴图被浏览器拦下了。需要在 CSP 的 img-src 与 connect-src 里加上 blob:。');
281
+ } else {
282
+ self.fail('模型加载失败:' + msg + '。请确认 ' + self.src + ' 已部署且可访问。');
283
+ }
284
+ });
285
+ }
286
+ };
287
+
288
+ var ModelViewer = {
289
+
290
+ update: function (root) {
291
+ var list = (root || document).querySelectorAll('[data-mv]');
292
+ for (var i = 0; i < list.length; i++) {
293
+ if (list[i].__mv) continue;
294
+ list[i].__mv = new Viewer(list[i]);
295
+ }
296
+ },
297
+
298
+ refresh: function (root) {
299
+ var list = (root || document).querySelectorAll('[data-mv]');
300
+ for (var i = 0; i < list.length; i++) {
301
+ var v = list[i].__mv;
302
+ if (!v || v.state !== 'ok') continue;
303
+ if (v.raf) cancelAnimationFrame(v.raf);
304
+ if (v.instances && v.instances.renderer) {
305
+ try { v.instances.renderer.dispose(); } catch (e) {}
306
+ }
307
+ list[i].innerHTML = '';
308
+ list[i].__mv = new Viewer(list[i]);
309
+ }
310
+ },
311
+ };
312
+
313
+ if (typeof window !== 'undefined') window.ModelViewer = ModelViewer;
314
+
315
+ if (document.readyState === 'loading') {
316
+ document.addEventListener('DOMContentLoaded', function () { ModelViewer.update(); });
317
+ } else {
318
+ ModelViewer.update();
319
+ }
320
+ })();
@@ -0,0 +1 @@
1
+ .splot {display:block;max-width:100%;height:auto;font-family:var(--sans);}.splot__s0 {--splot-c:var(--accent);}.splot__s1 {--splot-c:var(--danger);}.splot__s2 {--splot-c:var(--success);}.splot__s3 {--splot-c:var(--warning);}.splot__s4 {--splot-c:var(--info);}.splot__grid {stroke:var(--border-decor);stroke-width:1;}.splot__axis {stroke:var(--border-decor-str);stroke-width:1;}.splot__tick {stroke:var(--border-decor-str);stroke-width:1;}.splot__tick-label {fill:var(--text-tertiary);font-size:var(--fs-xs);font-variant-numeric:tabular-nums;}.splot__axis-label {fill:var(--text-secondary);font-size:var(--fs-xs);font-weight:500;}.splot__line {fill:none;stroke:var(--splot-c, var(--accent));stroke-width:2;stroke-linejoin:round;stroke-linecap:round;}.splot__pt {fill:var(--splot-c, var(--accent));stroke:var(--surface);stroke-width:1;}.splot__err {stroke:var(--splot-c, var(--accent));stroke-width:1.5;stroke-linecap:round;}.splot__band {fill:var(--splot-c, var(--accent));fill-opacity:.14;stroke:none;}.splot__legend {display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4, 1rem);margin:var(--sp-2) 0 0;padding:0;list-style:none;font-size:var(--fs-xs);color:var(--text-secondary);}.splot__legend-item {display:inline-flex;align-items:center;gap:var(--sp-1);}.splot__legend-mark {flex:0 0 auto;overflow:visible;}.splot__legend-mark line {stroke:var(--splot-c, var(--accent));}.splot__ref {stroke:var(--text-tertiary);stroke-width:1;stroke-dasharray:4 4;}.splot__ref-label {fill:var(--text-tertiary);font-size:var(--fs-xs);}.splot__anno-dot {fill:var(--text-primary);}.splot__anno {fill:var(--text-primary);font-size:var(--fs-xs);font-weight:600;}.splot__note {fill:var(--warning);font-size:var(--fs-xs);}@media (prefers-contrast:more) {.splot__axis, .splot__tick {stroke:var(--text-primary);}.splot__line {stroke-width:3;}}@media print {.splot__grid {stroke:var(--border-decor);}.splot__band {fill-opacity:.22;}}