cardbuddy 0.9.0 → 0.10.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 (32) hide show
  1. package/README.md +17 -2
  2. package/dist/cli.js +3 -0
  3. package/dist/config.js +7 -0
  4. package/dist/portGuard.js +293 -0
  5. package/dist/preview-editor/assets/index-C_UKS0NF.css +1 -0
  6. package/dist/preview-editor/assets/index-D1iIJ4sl.js +81 -0
  7. package/dist/preview-editor/index.html +2 -2
  8. package/dist/server-core/assetProxy.js +3 -22
  9. package/dist/server-core/buildDataFromSchema.js +36 -4
  10. package/dist/server-core/cardListCache.js +0 -17
  11. package/dist/server-core/index.js +3 -5
  12. package/dist/server-core/logStream.js +1 -6
  13. package/dist/standalone.js +24 -8
  14. package/dist/vendored/App.vue +187 -77
  15. package/dist/vendored/components/ComponentPalette.vue +1 -1
  16. package/dist/vendored/components/DebugPanel.vue +737 -91
  17. package/dist/vendored/components/NumberStepper.vue +125 -0
  18. package/dist/vendored/components/ProgressSlider.vue +9 -1
  19. package/dist/vendored/components/StructureTree.vue +2 -2
  20. package/dist/vendored/runtime/clipboard-node.js +0 -5
  21. package/dist/vendored/styles/app.css +707 -252
  22. package/dist/vendored/styles/card-gallery.css +3 -3
  23. package/dist/vendored/styles/card-select.css +13 -6
  24. package/dist/vendored/styles/dropdown.css +1 -2
  25. package/dist/vendored/styles/json-tree.css +3 -3
  26. package/dist/vendored/styles/node-inspector.css +7 -294
  27. package/dist/vendored/styles/setters.css +48 -49
  28. package/dist/vendored/styles/structure-tree.css +6 -11
  29. package/package.json +1 -1
  30. package/dist/preview-editor/assets/index-CrcrVs4F.css +0 -1
  31. package/dist/preview-editor/assets/index-DnpHHKWl.js +0 -80
  32. package/dist/vendored/assets/logo.png +0 -0
@@ -115,7 +115,13 @@
115
115
  --code-fn: #d2a8ff;
116
116
  --code-var: #ffa657;
117
117
  --code-binding: #56d4dd;
118
- --code-warn: #f59e0b;
118
+ /* === 变量类型标签配色(--type-*):变量列表类型 chip 专用 === */
119
+ /* 暗色沿用代码高亮调色板,与代码区同类型字面量同色呼应 */
120
+ --type-string: var(--code-str);
121
+ --type-number: var(--code-num);
122
+ --type-boolean: var(--code-kw);
123
+ --type-array: var(--code-fn);
124
+ --type-object: var(--code-prop);
119
125
  /* === CardBuddy UI 尺寸与节奏规范手册 §四(单一来源,尺寸/节奏不随主题变)== */
120
126
  /* 间距 8 pt 网格 */
121
127
  --space-0: 0;
@@ -158,6 +164,11 @@
158
164
  --icon-lg: 20px;
159
165
  --icon-xl: 24px;
160
166
  --stroke: 1.75;
167
+ /* 发丝线粗细:页面里所有「分割线 / 单边分隔描边」的统一尺寸(dpr 自适应见下方媒体查询)。
168
+ 普通屏 1px;dpr ≥ 2 时收到 0.5px(= 1 个物理像素),线条更锐利不发虚。
169
+ 控件四边描边(border: 1px solid …)不算分割线,仍固定 1px 以保持控件视觉重量;
170
+ 卡片内容组件(.ce_divider 等自动生成样式)与画布参考线(.ce-guide--*)同样不跟随。 */
171
+ --hairline: 1px;
161
172
  /* 阴影形状(颜色交给配色手册) */
162
173
  --shadow-1: 0 1px 2px var(--shadow-card);
163
174
  --shadow-2: 0 4px 12px var(--shadow-card);
@@ -177,74 +188,93 @@
177
188
  --z-toast-app: 2100;
178
189
  }
179
190
 
191
+ /* dpr ≥ 2 → 发丝线收到半像素。(min-resolution: 2dppx) 与 devicePixelRatio >= 2 等价,
192
+ 浏览器缩放、拖到不同密度屏幕时由浏览器自动重算,无需 JS 介入也不会有首帧闪动;
193
+ -webkit-min-device-pixel-ratio 兜住不认 resolution 的旧 Safari。 */
194
+ @media (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) {
195
+ :root {
196
+ --hairline: 0.5px;
197
+ }
198
+ }
199
+
180
200
  /* 浅色主题:以白色为基色调,复用同名变量整体切换。仅覆盖配色变量,布局不变。 */
181
201
  :root[data-theme='light'] {
182
- --bg-app: #f4f5f7;
202
+ /* 中性阶梯统一走 Slate 蓝灰族(与《深浅主题配色规范手册》§〇.3 对齐):
203
+ stage 最沉 → app → panel(白) → input/hover/soft 逐级提亮,避免旧值「中性脏灰 + 蓝灰边框」
204
+ 两个灰族混用导致的发灰发脏;控件填充收到近白,白面板上不再糊灰块。 */
205
+ --bg-app: #f4f6fa;
183
206
  --bg-bar: #ffffff;
184
207
  --bg-panel: #ffffff;
185
- --bg-stage: #e9ecf1;
186
- --bg-input: #eef1f5;
187
- --bg-hover: #e3e7ee;
188
- --bg-active: #d6dbe4;
189
- --bg-pop: rgba(255, 255, 255, 0.97);
190
- --bg-soft: #e7ebf2;
191
- --border: #d8dce3;
192
- --border-strong: #c2c8d2;
193
- --text: #1f2329;
194
- --text-dim: #5b6472;
195
- --text-faint: #8a93a3;
208
+ --bg-stage: #e9edf4;
209
+ --bg-input: #f6f8fb;
210
+ --bg-hover: #f1f4f9;
211
+ --bg-active: #e4e9f2;
212
+ --bg-pop: rgba(255, 255, 255, 0.98);
213
+ --bg-soft: #eef2f8;
214
+ --border: #e2e8f0;
215
+ --border-strong: #cbd5e1;
216
+ --text: #1e293b;
217
+ --text-dim: #475569;
218
+ /* faint 收到 slate-500/600 之间:白底 5.4:1、stage 底 4.6:1,11px 元信息不发虚也不糊
219
+ (旧 #8a93a3 白底仅 ~3.1:1) */
220
+ --text-faint: #5f6b7d;
196
221
  --accent: #4F6BF2;
197
222
  --accent-2: #3D57D9;
198
- --accent-soft: rgba(79, 107, 242, 0.12);
199
- --accent-border: rgba(79, 107, 242, 0.4);
223
+ --accent-soft: rgba(79, 107, 242, 0.1);
224
+ --accent-border: rgba(79, 107, 242, 0.35);
200
225
  --accent-hover: #3D57D9;
201
226
  --danger: #EF4444;
202
- --danger-soft: rgba(239, 68, 68, 0.12);
227
+ --danger-soft: rgba(239, 68, 68, 0.1);
203
228
  --danger-hover: #DC2626;
204
229
  --warn: #F59E0B;
205
- --warn-soft: rgba(245, 158, 11, 0.14);
230
+ --warn-soft: rgba(245, 158, 11, 0.12);
206
231
  --warn-border: rgba(245, 158, 11, 0.4);
207
232
  --warn-hover: #D97706;
208
233
  --on-warn: #0F1115;
209
234
  --ok: #10B981;
210
- --ok-soft: rgba(16, 185, 129, 0.14);
235
+ --ok-soft: rgba(16, 185, 129, 0.12);
211
236
  --ok-border: rgba(16, 185, 129, 0.4);
212
- --ok-strong: #166534;
213
- --ok-solid: #166534;
237
+ /* 语义深色变体与各自基色同族:绿=emerald-700、琥珀=amber-700、红=red-700,
238
+ 不再混用 GitHub green / brick red 等外来色相(白底对比均 ≥ 4.5:1) */
239
+ --ok-strong: #047857;
240
+ --ok-solid: #047857;
214
241
  --on-ok: #ffffff;
215
242
  --info: #4F6BF2;
216
- --info-soft: rgba(79, 107, 242, 0.12);
217
- --info-border: rgba(79, 107, 242, 0.4);
243
+ --info-soft: rgba(79, 107, 242, 0.1);
244
+ --info-border: rgba(79, 107, 242, 0.35);
218
245
  --on-accent: #ffffff;
219
246
  --radius: 8px;
220
247
  --radius-sm: 6px;
221
- --shadow-pop: rgba(15, 23, 42, 0.16);
222
- --shadow-card: rgba(15, 23, 42, 0.16);
223
- --shadow-drawer: rgba(15, 23, 42, 0.14);
224
- --shadow-toast: rgba(15, 23, 42, 0.12);
225
- --scrim: rgba(15, 23, 42, 0.35);
226
- --scrim-soft: rgba(15, 23, 42, 0.28);
248
+ /* 阴影收到手册量级(card 0.08~0.12):旧 0.16 配 8~24px 模糊会在白底上糊出一圈灰雾 */
249
+ --shadow-pop: rgba(15, 23, 42, 0.14);
250
+ --shadow-card: rgba(15, 23, 42, 0.1);
251
+ --shadow-drawer: rgba(15, 23, 42, 0.12);
252
+ --shadow-toast: rgba(15, 23, 42, 0.1);
253
+ --scrim: rgba(15, 23, 42, 0.4);
254
+ --scrim-soft: rgba(15, 23, 42, 0.3);
227
255
  --scrim-faint: rgba(15, 23, 42, 0.22);
228
- --bar-grad: linear-gradient(180deg, #ffffff, #f3f5f8);
229
- --splitter: #5b6cff;
230
- --splitter-grip: rgba(0, 0, 0, 0.16);
231
- --overlay-tint: rgba(0, 0, 0, 0.03);
232
- --overlay-tint-strong: rgba(0, 0, 0, 0.1);
233
- --err-item-fg: #c0392b;
234
- --api-item-fg: #2f4fb0;
235
- --api-item-border: rgba(91, 108, 255, 0.25);
236
- --api-item-bg: rgba(91, 108, 255, 0.06);
237
- --copy-ok: #1a7f37;
238
- --tag-ok-fg: #1a7f37;
239
- --tag-ok-bg: rgba(26, 127, 55, 0.1);
240
- --tag-warn-fg: #b58105;
241
- --tag-warn-bg: rgba(181, 129, 5, 0.1);
242
- --log-warn-fg: #9a6a00;
243
- --log-warn-bg: rgba(181, 129, 5, 0.1);
244
- --log-warn-border: rgba(181, 129, 5, 0.3);
245
- --scroll-thumb: rgba(0, 0, 0, 0.2);
246
- --scroll-thumb-hover: rgba(0, 0, 0, 0.32);
247
- --scroll-thumb-idle: rgba(0, 0, 0, 0.1);
256
+ --bar-grad: linear-gradient(180deg, #ffffff, #f6f8fc);
257
+ /* 高亮 / 描边类半透明统一挂到主色 #4F6BF2(79,107,242)上,替换旧的电光蓝 #5b6cff(91,108,255),
258
+ 与按钮 / 选中态同一色相,浅色下不再跳色 */
259
+ --splitter: #4F6BF2;
260
+ --splitter-grip: rgba(15, 23, 42, 0.18);
261
+ --overlay-tint: rgba(15, 23, 42, 0.03);
262
+ --overlay-tint-strong: rgba(15, 23, 42, 0.08);
263
+ --err-item-fg: #b91c1c;
264
+ --api-item-fg: #3d57d9;
265
+ --api-item-border: rgba(79, 107, 242, 0.22);
266
+ --api-item-bg: rgba(79, 107, 242, 0.06);
267
+ --copy-ok: #047857;
268
+ --tag-ok-fg: #047857;
269
+ --tag-ok-bg: rgba(16, 185, 129, 0.1);
270
+ --tag-warn-fg: #b45309;
271
+ --tag-warn-bg: rgba(245, 158, 11, 0.1);
272
+ --log-warn-fg: #b45309;
273
+ --log-warn-bg: rgba(245, 158, 11, 0.1);
274
+ --log-warn-border: rgba(245, 158, 11, 0.35);
275
+ --scroll-thumb: rgba(15, 23, 42, 0.16);
276
+ --scroll-thumb-hover: rgba(15, 23, 42, 0.28);
277
+ --scroll-thumb-idle: rgba(15, 23, 42, 0.08);
248
278
  /* 语法高亮配色:浅色主题参考 GitHub Light / VSCode Light+,保证白底上的可读性 */
249
279
  --jt-key: #953800;
250
280
  --jt-string: #0a3069;
@@ -252,15 +282,15 @@
252
282
  --jt-boolean: #cf222e;
253
283
  --jt-null: #57606a;
254
284
  --jt-faint: #6b7280;
255
- --jt-ring: rgba(91, 108, 255, 0.3);
285
+ --jt-ring: rgba(79, 107, 242, 0.28);
256
286
  --jt-del-fg: #cf222e;
257
287
  --jt-del-bg: rgba(207, 34, 46, 0.12);
258
- --jt-add-bg: rgba(91, 108, 255, 0.12);
259
- --st-label: #24292f;
288
+ --jt-add-bg: rgba(79, 107, 242, 0.1);
289
+ --st-label: #1e293b;
260
290
  --st-id: #64748b;
261
291
  --st-badge-bg: #4F6BF2;
262
292
  --st-badge-fg: #ffffff;
263
- --st-hl-bg: rgba(79, 107, 242, 0.16);
293
+ --st-hl-bg: rgba(79, 107, 242, 0.14);
264
294
  --code-comment: #6e7781;
265
295
  --code-punc: #6e7781;
266
296
  --code-prop: #953800;
@@ -270,7 +300,13 @@
270
300
  --code-fn: #8250df;
271
301
  --code-var: #953800;
272
302
  --code-binding: #0d9488;
273
- --code-warn: #b58105;
303
+ /* 类型 chip 专用色在亮色下单独校正(不影响代码高亮 --code-*):
304
+ - string:--code-str 藏青与 --code-num 蓝同属蓝调易混,改走绿系;
305
+ - boolean / array:--code-kw 红、--code-fn 紫在 10px 小字上对比不足 AA(4.5:1),各压深一档;
306
+ - number / object 亮色下已达标,继续复用 --code-*。 */
307
+ --type-string: #116329;
308
+ --type-boolean: #a40e26;
309
+ --type-array: #6639ba;
274
310
  }
275
311
 
276
312
  * {
@@ -366,7 +402,7 @@ body {
366
402
  padding: 0 16px;
367
403
  height: 48px;
368
404
  background: var(--bar-grad);
369
- border-bottom: 1px solid var(--border);
405
+ border-bottom: var(--hairline) solid var(--border);
370
406
  flex: 0 0 auto;
371
407
  }
372
408
  .app__logo {
@@ -421,7 +457,11 @@ body {
421
457
  }
422
458
  .app__btn--icon {
423
459
  height: var(--ctrl-md);
424
- padding: 0 8px;
460
+ /* 纯图标按钮(无文字)视觉取正方:宽随 aspect-ratio 跟高度走、图标居中,
461
+ 不再出现 33×28 这类扁矩形;顶栏覆写高度为 --ctrl-sm 后仍自动保持正方 */
462
+ aspect-ratio: 1;
463
+ padding: 0;
464
+ justify-content: center;
425
465
  }
426
466
  /* 开关型图标按钮的「开启」态(如右侧接口调用面板开关):用主题色标示当前已展开 */
427
467
  .app__btn--active {
@@ -533,43 +573,11 @@ body {
533
573
  background: var(--accent);
534
574
  color: var(--on-accent);
535
575
  border-color: var(--accent);
536
- /* box-shadow: 0 0 0 2px var(--accent-soft); */
537
576
  }
538
577
  .app__btn--history-save.is-dirty:not(:disabled):hover {
539
578
  background: var(--accent-2);
540
579
  border-color: var(--accent-2);
541
580
  }
542
- /* 发布按钮(写回 FinMall 前的发布动作),与本地保存/远端分组区分 */
543
- .app__btn--publish {
544
- display: inline-flex;
545
- align-items: center;
546
- gap: 5px;
547
- height: var(--ctrl-md);
548
- padding: 0 12px;
549
- color: var(--info);
550
- border-color: var(--info-border);
551
- background: var(--info-soft);
552
- }
553
- .app__btn--publish:hover:not(:disabled) {
554
- background: var(--info);
555
- color: var(--on-accent);
556
- border-color: var(--info);
557
- }
558
- .app__btn--publish:disabled {
559
- opacity: 0.5;
560
- cursor: default;
561
- }
562
- /* 已保存但读回校验不符:橙色警示,提示「交易成功但内容未落库」 */
563
- .app__btn--publish.app__btn--warn {
564
- color: var(--warn);
565
- border-color: var(--warn-border);
566
- background: var(--warn-soft);
567
- }
568
- .app__btn--publish.app__btn--warn:hover:not(:disabled) {
569
- background: var(--warn);
570
- color: var(--on-accent);
571
- border-color: var(--warn);
572
- }
573
581
  .app__bar-actions {
574
582
  margin-left: auto; /* 把这一组推到顶栏最右侧 */
575
583
  display: flex;
@@ -610,54 +618,90 @@ body {
610
618
  color: var(--danger);
611
619
  border-color: var(--danger);
612
620
  }
613
- .app__btn--sm {
614
- padding: 4px 10px;
615
- font-size: 12px;
621
+ /* 设置浮层:与全应用轻量浮层同一语言——--bg-panel 实底、发丝线分栏头、--radius-lg 圆角、
622
+ --shadow-3 投影;锚定顶栏「连接」按钮下方,进出场复用统一 pop 弹性动画(缩放原点右上)。 */
623
+ .app__dev-svc-mask {
624
+ position: fixed;
625
+ inset: 0;
626
+ z-index: var(--z-overlay);
616
627
  }
617
628
  .app__dev-svc-panel {
618
629
  position: absolute;
619
630
  top: calc(100% + 8px);
620
631
  right: 0;
621
- z-index: var(--z-overlay-low);
622
- width: 320px;
623
- padding: 16px;
624
- background: var(--bg-soft, #20242b);
625
- border: 1px solid var(--border, #2b3038);
626
- border-radius: var(--radius-xl);
627
- box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);
628
- color: var(--text, #e6e9ef);
632
+ z-index: var(--z-pop);
633
+ width: 300px;
634
+ background: var(--bg-panel);
635
+ border: 1px solid var(--border-strong);
636
+ border-radius: var(--radius-lg);
637
+ box-shadow: var(--shadow-3);
638
+ color: var(--text);
629
639
  text-align: left;
640
+ overflow: hidden;
641
+ transform-origin: top right;
642
+ }
643
+ .app__dev-svc-head {
644
+ display: flex;
645
+ align-items: center;
646
+ justify-content: space-between;
647
+ gap: 8px;
648
+ padding: 7px 8px 7px 12px;
649
+ border-bottom: var(--hairline) solid var(--border);
630
650
  }
631
651
  .app__dev-svc-title {
632
- font-size: 13px;
652
+ font-size: 12px;
633
653
  font-weight: 600;
634
- margin-bottom: 10px;
654
+ color: var(--text);
655
+ }
656
+ /* 头部关闭按钮:与节点面板 / 组件面板关闭按钮同规格(22px 弱按钮) */
657
+ .app__dev-svc-close {
658
+ width: 22px;
659
+ height: 22px;
660
+ display: inline-flex;
661
+ align-items: center;
662
+ justify-content: center;
663
+ background: none;
664
+ border: none;
665
+ border-radius: 6px;
666
+ color: var(--text-faint);
667
+ font-size: 14px;
668
+ line-height: 1;
669
+ cursor: pointer;
670
+ transition: background 0.15s, color 0.15s;
671
+ }
672
+ .app__dev-svc-close::before {
673
+ content: '✕';
674
+ }
675
+ .app__dev-svc-close:hover {
676
+ background: var(--bg-hover);
677
+ color: var(--text);
678
+ }
679
+ .app__dev-svc-body {
680
+ display: flex;
681
+ flex-direction: column;
682
+ gap: 12px;
683
+ padding: 12px;
635
684
  }
636
685
  .app__dev-svc-row {
637
686
  display: flex;
638
687
  align-items: center;
639
688
  justify-content: space-between;
640
- gap: 4px;
641
- margin-bottom: 10px;
642
- font-size: 12px;
643
- color: var(--text-dim, #9aa3b2);
689
+ gap: 8px;
690
+ font-size: 11px;
691
+ color: var(--text-dim);
644
692
  }
645
693
  .app__dev-svc-row--col {
646
694
  flex-direction: column;
647
695
  align-items: stretch;
696
+ gap: 6px;
648
697
  }
649
- .app__dev-svc-row--col > span {
650
- margin-bottom: 4px;
651
- }
652
- /* 与节点编辑面板 setter(setters.css .st-input / .st-textarea)保持完全一致:
653
- --bg-input 底色、--border 边框、5px 圆角、focus 切 --accent-border 边框 + --accent-soft 光环。 */
698
+ /* 输入框与节点属性面板输入家族同规格:28px 高、--bg-input 底、focus 主色描边 + 光环 */
654
699
  .app__dev-svc-row input[type='text'],
655
- .app__dev-svc-row input[type='password'],
656
- .app__dev-svc-row textarea {
700
+ .app__dev-svc-row input[type='password'] {
657
701
  width: 100%;
658
702
  min-width: 0;
659
- height: var(--ctrl-md);
660
- padding: 0 12px;
703
+ height: var(--ctrl-sm);
704
+ padding: 0 10px;
661
705
  background: var(--bg-input);
662
706
  border: 1px solid var(--border);
663
707
  border-radius: var(--radius-sm);
@@ -667,45 +711,38 @@ body {
667
711
  outline: none;
668
712
  transition: border-color 0.15s, box-shadow 0.15s;
669
713
  }
670
- .app__dev-svc-row textarea {
671
- height: auto;
672
- min-height: 84px;
673
- padding: 6px 8px;
674
- line-height: 1.5;
675
- resize: none;
676
- }
677
714
  .app__dev-svc-row input[type='text']:focus,
678
- .app__dev-svc-row input[type='password']:focus,
679
- .app__dev-svc-row textarea:focus {
715
+ .app__dev-svc-row input[type='password']:focus {
680
716
  border-color: var(--accent-border);
681
717
  box-shadow: 0 0 0 2px var(--accent-soft);
682
718
  }
683
- .app__dev-svc-row input::placeholder,
684
- .app__dev-svc-row textarea::placeholder {
719
+ .app__dev-svc-row input::placeholder {
685
720
  color: var(--text-faint);
686
721
  }
687
722
  .app__dev-svc-row .switch {
688
723
  flex: 0 0 auto;
689
724
  }
725
+ /* 未生效提示:琥珀色软底注记块,替代裸文字,警告语义一眼可辨 */
726
+ .app__dev-svc-hint {
727
+ margin: 0;
728
+ padding: 6px 8px;
729
+ border-radius: var(--radius-sm);
730
+ background: var(--warn-soft);
731
+ color: var(--warn);
732
+ font-size: 11px;
733
+ line-height: 1.55;
734
+ }
690
735
  .app__dev-svc-actions {
691
736
  display: flex;
692
737
  gap: 8px;
693
- margin-top: 4px;
694
738
  justify-content: flex-end;
695
739
  }
696
- .app__dev-svc-hint {
697
- margin: 8px 0 0;
698
- font-size: 11px;
699
- line-height: 1.5;
700
- color: var(--warn, #e0a23a);
701
- }
702
740
  /* 部署态未配置本地服务:顶部提示条 */
703
741
  .app__nosvc-banner {
704
742
  padding: 8px 14px;
705
743
  font-size: 13px;
706
744
  color: var(--warn, #e0a23a);
707
745
  background: var(--warn-soft, rgba(224, 162, 58, 0.12));
708
- /* border-bottom: 1px solid var(--warn-border, rgba(224, 162, 58, 0.35)); */
709
746
  }
710
747
  /* 「已断开」提示条:红色(连接彻底失败 / 服务已停止),区别于未配置的琥珀色 */
711
748
  .app__nosvc-banner--disconnected {
@@ -877,6 +914,45 @@ body {
877
914
  0%, 100% { opacity: 1; }
878
915
  50% { opacity: 0.3; }
879
916
  }
917
+ /* 校验通过:徽标局部庆祝动画 */
918
+ .app__badge.is-celebrating { animation: app-badge-pop 0.5s ease; }
919
+ @keyframes app-badge-pop {
920
+ 0% { transform: scale(1); }
921
+ 35% { transform: scale(1.18); }
922
+ 100% { transform: scale(1); }
923
+ }
924
+ .app__confetti {
925
+ position: fixed;
926
+ pointer-events: none;
927
+ z-index: 9999;
928
+ }
929
+ .app__confetti-bit {
930
+ position: absolute;
931
+ left: 0;
932
+ top: 0;
933
+ border-radius: 0;
934
+ /* 玻璃刻面:一角亮白高光 → 主色 → 暗刻面,半透明;clip-path 裁出尖锐碎片 */
935
+ background: linear-gradient(135deg,
936
+ rgba(255, 255, 255, 0.95) 0%,
937
+ var(--c, #52c41a) 42%,
938
+ color-mix(in srgb, var(--c, #52c41a) 62%, #000) 100%);
939
+ clip-path: var(--clip, polygon(50% 0%, 0% 100%, 100% 100%));
940
+ opacity: var(--o, 0.9);
941
+ transform: translate(-50%, -50%);
942
+ animation: app-confetti-fly 0.7s ease-out forwards;
943
+ /* 细微暗边,让半透明玻璃在浅色顶栏上也立得住 */
944
+ filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.18));
945
+ }
946
+ @keyframes app-confetti-fly {
947
+ 0% {
948
+ opacity: var(--o, 0.9);
949
+ transform: translate(calc(-50% + var(--sx, 0px)), calc(-50% + var(--sy, 0px))) rotate(0deg) scale(0.4);
950
+ }
951
+ 100% {
952
+ opacity: 0;
953
+ transform: translate(calc(-50% + var(--sx, 0px) + var(--tx)), calc(-50% + var(--sy, 0px) + var(--ty))) rotate(var(--rot)) scale(1);
954
+ }
955
+ }
880
956
  .app__icon {
881
957
  width: 15px;
882
958
  height: 15px;
@@ -906,6 +982,7 @@ body {
906
982
  flex-direction: column;
907
983
  min-width: 0;
908
984
  min-height: 0;
985
+ border-left: var(--hairline) solid var(--border);
909
986
  }
910
987
  .workside__bar {
911
988
  flex: 0 0 auto;
@@ -951,7 +1028,7 @@ body {
951
1028
  justify-content: center;
952
1029
  overflow: hidden;
953
1030
  }
954
- /* 画布层:直接按实际列宽/列高布局(width/height 100% 填满外框),不再使用 transform 缩放;内部 device-bar 固定高、phone-viewport 弹性填充 */
1031
+ /* 画布层:直接按实际列宽/列高布局(width/height 100% 填满外框),不再使用 transform 缩放;内部 canvas-bar 固定高、phone-viewport 弹性填充 */
955
1032
  .phone__scaler {
956
1033
  position: relative;
957
1034
  width: 100%;
@@ -1002,70 +1079,125 @@ body {
1002
1079
  cursor: col-resize !important;
1003
1080
  }
1004
1081
 
1005
- /* 设备工具条(类 Chrome DevTools 设备模式顶部预留的细条):
1006
- 与手机框等宽、紧贴其上,通过下拉选择画布背景 */
1007
- .device-bar {
1082
+ /* 画布工具条:原 device-bar(顶 28px)与 preview-statusbar(底 28px)合并为一条 32px——
1083
+ 把 28px 竖向空间还给手机视口,也消除「顶条 bg-bar / 底条透明」两种底色并存的割裂感。
1084
+ 视觉语法与全局状态栏同源:透明底融入舞台(--bg-stage),仅一条发丝线收边;
1085
+ 控件为 ghost chip(hover / 展开出 --bg-hover),读数等宽 + tabular-nums 不跳宽。
1086
+ 左组 = 改变画布(背景 / 宽度预设),右组 = 画布现状与动作(尺寸读数 / 刷新)。 */
1087
+ .canvas-bar {
1008
1088
  flex: 0 0 auto;
1009
1089
  width: 100%;
1010
- height: 28px;
1090
+ height: 32px;
1011
1091
  display: flex;
1012
1092
  align-items: center;
1013
- gap: 8px;
1014
- padding: 0 12px;
1015
- background: var(--bg-bar);
1016
- border-bottom: 1px solid var(--border);
1093
+ gap: 4px;
1094
+ padding: 0 8px;
1095
+ border-bottom: var(--hairline) solid var(--border);
1017
1096
  }
1018
- /* 背景下拉框由 Dropdown 组件统一渲染(.dd 体系),无边框模式见 dropdown.css 的 .dd--borderless */
1019
- .device-bar__spacer {
1097
+ .canvas-bar__spacer {
1020
1098
  flex: 1 1 auto;
1021
1099
  }
1022
- .device-bar__info {
1100
+ /* chip:两个 Dropdown 的 slot 触发器统一外观(24px 高 / 5px 圆角 / hover 出底) */
1101
+ .canvas-bar__chip {
1102
+ display: inline-flex;
1103
+ align-items: center;
1104
+ gap: 6px;
1105
+ height: 24px;
1106
+ padding: 0 8px;
1107
+ border-radius: 5px;
1108
+ color: var(--text-dim);
1109
+ font-size: 11.5px;
1110
+ white-space: nowrap;
1111
+ cursor: pointer;
1112
+ transition: background 0.15s, color 0.15s;
1113
+ }
1114
+ .canvas-bar__chip:hover,
1115
+ .dd--open > .dd__trigger--slot .canvas-bar__chip {
1116
+ background: var(--bg-hover);
1117
+ color: var(--text);
1118
+ }
1119
+ .canvas-bar__chev {
1120
+ width: 10px;
1121
+ height: 10px;
1122
+ color: var(--text-faint);
1123
+ }
1124
+ .canvas-bar__icn {
1125
+ flex: 0 0 auto;
1126
+ width: 13px;
1127
+ height: 13px;
1128
+ color: var(--text-faint);
1129
+ }
1130
+ /* 背景小样:与 .phone__screen--bg-* 同色,触发器上直接可见当前模式,不必展开下拉 */
1131
+ .canvas-bar__swatch {
1132
+ flex: 0 0 auto;
1133
+ width: 10px;
1134
+ height: 10px;
1135
+ border-radius: 3px;
1136
+ border: 1px solid var(--border-strong);
1137
+ }
1138
+ .canvas-bar__swatch--white {
1139
+ background: #ffffff;
1140
+ }
1141
+ .canvas-bar__swatch--gray {
1142
+ background: #f0f0f0;
1143
+ }
1144
+ /* 近黑而非纯 #000:留出一点灰阶,深色卡片边缘与阴影仍能分辨 */
1145
+ .canvas-bar__swatch--black {
1146
+ background: #1c1c1e;
1147
+ }
1148
+ .canvas-bar__swatch--checker {
1149
+ background-color: #ffffff;
1150
+ background-image:
1151
+ linear-gradient(45deg, #cfcfcf 25%, transparent 25%, transparent 75%, #cfcfcf 75%),
1152
+ linear-gradient(45deg, #cfcfcf 25%, transparent 25%, transparent 75%, #cfcfcf 75%);
1153
+ background-size: 6px 6px;
1154
+ background-position: 0 0, 3px 3px;
1155
+ }
1156
+ /* 尺寸读数:等宽 + tabular-nums,拖拽分隔条改宽时数字不跳宽 */
1157
+ .canvas-bar__size {
1158
+ padding: 0 4px;
1159
+ font-family: 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace;
1160
+ font-size: 11px;
1161
+ font-variant-numeric: tabular-nums;
1023
1162
  color: var(--text-faint);
1024
- font-size: 12px;
1025
1163
  white-space: nowrap;
1026
1164
  }
1027
- /* 底部状态条刷新按钮:仅图标、与左侧尺寸文本上下对齐(同高 28px / 居中) */
1028
- .statusbar__refresh {
1165
+ .canvas-bar__iconbtn {
1029
1166
  flex: 0 0 auto;
1030
1167
  display: inline-flex;
1031
1168
  align-items: center;
1032
1169
  justify-content: center;
1170
+ width: 24px;
1171
+ height: 24px;
1033
1172
  padding: 0;
1034
1173
  background: transparent;
1035
1174
  color: var(--text-faint);
1036
1175
  border: none;
1037
- border-radius: 6px;
1176
+ border-radius: 5px;
1038
1177
  cursor: pointer;
1039
- transition: background 0.15s, color 0.15s, transform 0.05s;
1178
+ transition: background 0.15s, color 0.15s;
1040
1179
  }
1041
- .statusbar__refresh:hover:not(:disabled) {
1180
+ .canvas-bar__iconbtn:hover:not(:disabled) {
1181
+ background: var(--bg-hover);
1042
1182
  color: var(--accent);
1043
1183
  }
1044
- .statusbar__refresh:active:not(:disabled) {
1045
- transform: translateY(1px);
1046
- }
1047
- .statusbar__refresh:disabled {
1184
+ .canvas-bar__iconbtn:disabled {
1048
1185
  opacity: 0.4;
1049
1186
  cursor: default;
1050
1187
  }
1051
- .device-bar__label {
1052
- color: var(--text-faint);
1053
- font-size: 12px;
1054
- white-space: nowrap;
1188
+ /* 刷新中图标自转:把「点了没反应」的空白等待变成可见反馈 */
1189
+ .canvas-bar__iconbtn.is-loading svg {
1190
+ animation: canvas-bar-spin 0.8s linear infinite;
1055
1191
  }
1056
- /* 预览区底部状态条:画布尺寸读数 + 刷新按钮。
1057
- 底色透明(融入手机框 --bg-stage),不再作为独立暗面板——消除其与全局 .statusbar
1058
- (bg-bar)因所处父容器底色不同而产生的“颜色细微差异”观感;仅保留 1px 分隔线作页脚边界。 */
1059
- .preview-statusbar {
1060
- flex: 0 0 auto;
1061
- width: 100%;
1062
- height: 28px;
1063
- display: flex;
1064
- align-items: center;
1065
- gap: 12px;
1066
- padding: 0 12px;
1067
- background: transparent;
1068
- border-top: 1px solid var(--border);
1192
+ @keyframes canvas-bar-spin {
1193
+ to {
1194
+ transform: rotate(360deg);
1195
+ }
1196
+ }
1197
+ /* 窄列(预览列 < 300px,含 188 预设):收起尺寸读数与 chip 文案只留图标,保证单行不挤 */
1198
+ .canvas-bar--tight .canvas-bar__size,
1199
+ .canvas-bar--tight .canvas-bar__txt {
1200
+ display: none;
1069
1201
  }
1070
1202
  /* 预览区底部状态条:本地开发服务连接状态(连接图标 + 状态文案)。
1071
1203
  配色复用顶栏「连接」按钮的语义色类(app__btn--connected / --reconnecting / --disconnected / --warn),
@@ -1087,13 +1219,22 @@ body {
1087
1219
  border: none;
1088
1220
  padding: 0 10px;
1089
1221
  }
1090
- .statusbar .app__btn--connected { color: var(--ok); }
1091
1222
  .statusbar .app__btn--reconnecting { color: var(--warn); }
1092
1223
  .statusbar .app__btn--disconnected { color: var(--danger); }
1093
1224
  .statusbar .app__btn--warn { color: var(--warn); }
1225
+ /* 连接成功回落状态栏默认色(铁律:仅 warn / danger 着语义色);顶栏「连接」按钮的绿色不受影响。
1226
+ hover 同statusbar 读数语言:极淡底色 + 提亮文字,不引入 ok 语义色。 */
1227
+ .statusbar .app__btn--connected {
1228
+ color: var(--text-dim);
1229
+ }
1230
+ .statusbar .app__btn--connected:hover:not(:disabled) {
1231
+ background: var(--bg-hover);
1232
+ color: var(--text);
1233
+ border-color: transparent;
1234
+ }
1094
1235
  /* 连接指示器现为可点按钮(开合底部「服务日志」面板):保持状态栏读数观感
1095
- (无边框 / 无圆角 / 语义色由 app__btn--* 提供),hover 仅加极淡底色提示可点,
1096
- 展开态用 accent 底线标识(与 .statusbar__item--prob.is-open 同一语言,不抢语义色)。 */
1236
+ (无边框 / 无圆角、不设选中态),hover 仅加极淡底色提示可点。
1237
+ 配色同状态栏铁律:仅重连(warn)/ 断开(danger)/ 未配置(warn)着语义色,连接成功用默认色。 */
1097
1238
  button.statusbar__conn {
1098
1239
  cursor: pointer;
1099
1240
  font: inherit;
@@ -1101,10 +1242,6 @@ button.statusbar__conn {
1101
1242
  .statusbar__conn:hover {
1102
1243
  background: var(--bg-hover);
1103
1244
  }
1104
- .statusbar__conn.is-open {
1105
- background: var(--bg-hover);
1106
- box-shadow: inset 0 -2px 0 0 var(--accent);
1107
- }
1108
1245
 
1109
1246
  /* 颜色选择器(@ckpack/vue-color Sketch)预设区顶部分隔线:与系统边框色保持一致,
1110
1247
  覆盖组件默认的 1px solid #eee(深色主题下刺眼)。组件样式为全局注入且非 scoped,
@@ -1151,6 +1288,9 @@ button.statusbar__conn {
1151
1288
  .phone__screen--bg-gray {
1152
1289
  background: #f0f0f0;
1153
1290
  }
1291
+ .phone__screen--bg-black {
1292
+ background: #1c1c1e;
1293
+ }
1154
1294
  .phone__screen::-webkit-scrollbar {
1155
1295
  display: none; /* WebKit:隐藏滚动条(仍可滚动) */
1156
1296
  }
@@ -1203,7 +1343,6 @@ button.statusbar__conn {
1203
1343
  /* 中栏最小宽度:不得小于三分之一屏幕宽度(与中右分隔条 startApiDrag 的夹取一致) */
1204
1344
  min-width: 33.333vw;
1205
1345
  background: var(--bg-panel);
1206
- border-left: 1px solid var(--border);
1207
1346
  }
1208
1347
 
1209
1348
  /* 右侧常驻「接口调用」面板:默认 360px 宽,可经中右分隔条拖拽调节(最小 320px,
@@ -1217,7 +1356,7 @@ button.statusbar__conn {
1217
1356
  flex-direction: column;
1218
1357
  min-height: 0;
1219
1358
  background: var(--bg-panel);
1220
- border-left: 1px solid var(--border);
1359
+ border-left: var(--hairline) solid var(--border);
1221
1360
  }
1222
1361
  .apipanel__head {
1223
1362
  flex: 0 0 auto;
@@ -1227,7 +1366,7 @@ button.statusbar__conn {
1227
1366
  /* 与调试面板 tab 条同高(12px 上下 padding + 13px 字号 ≈ 42px),保证三条栏顶线对齐 */
1228
1367
  height: 40px;
1229
1368
  padding: 0 12px;
1230
- border-bottom: 1px solid var(--border);
1369
+ border-bottom: var(--hairline) solid var(--border);
1231
1370
  }
1232
1371
  .apipanel__title {
1233
1372
  font-size: 13px;
@@ -1306,7 +1445,7 @@ button.statusbar__conn {
1306
1445
  }
1307
1446
  .debug__tabs {
1308
1447
  display: flex;
1309
- border-bottom: 1px solid var(--border);
1448
+ border-bottom: var(--hairline) solid var(--border);
1310
1449
  }
1311
1450
  .debug__tab {
1312
1451
  flex: 1;
@@ -1317,7 +1456,6 @@ button.statusbar__conn {
1317
1456
  color: var(--text-dim);
1318
1457
  font-size: 13px;
1319
1458
  cursor: pointer;
1320
- /* border-bottom: 2px solid transparent; */
1321
1459
  transition: color 0.15s;
1322
1460
  position: relative;
1323
1461
  }
@@ -1326,7 +1464,6 @@ button.statusbar__conn {
1326
1464
  }
1327
1465
  .debug__tab--active {
1328
1466
  color: var(--accent);
1329
- /* border-bottom-color: var(--accent); */
1330
1467
 
1331
1468
  &::after {
1332
1469
  content: '';
@@ -1352,7 +1489,6 @@ button.statusbar__conn {
1352
1489
  position: relative;
1353
1490
  flex: 1 1 auto;
1354
1491
  overflow: auto;
1355
- /* padding: 12px 16px; */
1356
1492
  }
1357
1493
  .debug__meta {
1358
1494
  margin: 0;
@@ -1411,7 +1547,7 @@ button.statusbar__conn {
1411
1547
  margin: auto -12px 0;
1412
1548
  padding: 10px 12px;
1413
1549
  background: var(--bg-panel);
1414
- border-top: 1px solid var(--border);
1550
+ border-top: var(--hairline) solid var(--border);
1415
1551
  color: var(--text-faint);
1416
1552
  font-size: 12px;
1417
1553
  line-height: 1.6;
@@ -1432,7 +1568,7 @@ button.statusbar__conn {
1432
1568
  /* hidden 避免面板自身出现滚动条(滚动交给 .statepanel__tree) */
1433
1569
  overflow: hidden;
1434
1570
  background: var(--bg-panel);
1435
- border-top: 1px solid var(--border-strong);
1571
+ border-top: var(--hairline) solid var(--border-strong);
1436
1572
  }
1437
1573
  .statepanel__head {
1438
1574
  flex: 0 0 auto;
@@ -1441,7 +1577,7 @@ button.statusbar__conn {
1441
1577
  gap: 8px;
1442
1578
  height: var(--ctrl-lg);
1443
1579
  padding: 0 12px;
1444
- border-bottom: 1px solid var(--border);
1580
+ border-bottom: var(--hairline) solid var(--border);
1445
1581
  font-size: 13px;
1446
1582
  color: var(--text);
1447
1583
  }
@@ -1514,11 +1650,6 @@ button.statusbar__conn {
1514
1650
  padding: 8px 12px 10px;
1515
1651
  }
1516
1652
 
1517
- /* 状态栏「运行态」指示器:复用问题/事件指示器的统一语言(无边框/无圆角/无 hover 背景块)。
1518
- 展开时仅文字着 accent 色,与 is-log 一致,作为「面板已打开」的轻量提示。 */
1519
- .statusbar__item--prob.is-open {
1520
- color: var(--accent);
1521
- }
1522
1653
  .debug__tag {
1523
1654
  display: inline-block;
1524
1655
  padding: 1px 8px;
@@ -1563,7 +1694,7 @@ button.statusbar__conn {
1563
1694
  border-radius: 0;
1564
1695
  /* 左侧红条标示错误归属;行底透明避免整片红块,hover 才整行染 danger 色 */
1565
1696
  border-left: 2px solid var(--danger);
1566
- border-bottom: 1px solid var(--border);
1697
+ border-bottom: var(--hairline) solid var(--border);
1567
1698
  background: transparent;
1568
1699
  color: var(--err-item-fg);
1569
1700
  font-size: 11px;
@@ -1609,12 +1740,6 @@ button.statusbar__conn {
1609
1740
  font-weight: 600;
1610
1741
  opacity: 0.85;
1611
1742
  }
1612
- .debug__pre {
1613
- margin: 4px 0 0;
1614
- white-space: pre-wrap;
1615
- font-size: 11px;
1616
- color: var(--text-dim);
1617
- }
1618
1743
 
1619
1744
  /* 接口调用条目:方法名 + 最右侧复制图标 */
1620
1745
  .debug__api-row {
@@ -1712,40 +1837,28 @@ button.statusbar__conn {
1712
1837
  }
1713
1838
  .apt__children {
1714
1839
  padding-left: 16px;
1715
- border-left: 1px solid var(--border);
1840
+ border-left: var(--hairline) solid var(--border);
1716
1841
  margin-left: 4px;
1717
1842
  }
1718
1843
  .apt__close {
1719
1844
  padding: 1px 4px 1px 20px;
1720
1845
  color: var(--text-faint);
1721
1846
  }
1722
- .debug__scope {
1723
- margin: 0;
1724
- font-size: 11px;
1725
- line-height: 1.5;
1726
- white-space: pre-wrap;
1727
- color: var(--text-dim);
1728
- }
1729
1847
 
1730
- /* 数据绑定:JSON 树 + 底部操作按钮
1848
+ /* 变量 mock 二级视图 / 运行态:JSON 内容区 + 底部操作按钮
1731
1849
  容器铺满调试面板主体(绝对定位贴合 body 内边距区域),内部用 flex 列布局,
1732
1850
  JSON 树占据剩余空间并可独立滚动,底部操作按钮始终钉在底部——
1733
1851
  数据较少时不再上浮,数据较多时树内部滚动而按钮不随之移动。 */
1734
1852
  .debug__scope-wrap {
1735
1853
  position: absolute;
1736
1854
  /* right:0 让 JSON 树滚动条紧贴面板最右边(与其他 tab 用 body padding 作
1737
- 16px 滚动框不同,本 tab 滚动交给内部 .debug__scope-tree,需要贴边);
1855
+ 16px 滚动框不同,本 tab 滚动交给内部 .debug__scope-raw,需要贴边);
1738
1856
  left:16px 与 body 的 16px 内边距对齐,让树内容左缘与其他 tab 一致。 */
1739
1857
  inset: 0;
1740
1858
  display: flex;
1741
1859
  flex-direction: column;
1742
1860
  min-height: 0;
1743
1861
  }
1744
- .debug__scope-tree {
1745
- flex: 1 1 auto;
1746
- min-height: 0;
1747
- overflow: auto;
1748
- }
1749
1862
  .debug__scope-foot {
1750
1863
  position: absolute;
1751
1864
  bottom: 10px;
@@ -1759,7 +1872,8 @@ button.statusbar__conn {
1759
1872
  background: var(--bg-bar);
1760
1873
  border: 1px solid var(--border);
1761
1874
  border-radius: 10px;
1762
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
1875
+ /* 阴影走 token:深色 0.28 不变,浅色收到 0.10,白底上不再糊一团灰雾 */
1876
+ box-shadow: 0 6px 18px var(--shadow-toast);
1763
1877
  }
1764
1878
  .debug__copied {
1765
1879
  margin: 0 4px 0 8px;
@@ -1805,13 +1919,13 @@ button.statusbar__conn {
1805
1919
  }
1806
1920
  /* 按钮分组间的竖向分隔线 */
1807
1921
  .debug__sep {
1808
- width: 1px;
1922
+ width: var(--hairline);
1809
1923
  height: 16px;
1810
1924
  margin: 0 2px;
1811
1925
  background: var(--border-strong);
1812
1926
  }
1813
1927
 
1814
- /* 数据绑定 Raw 模式:直接复用 .debug__scope-wrap 的绝对定位盒(inset 已占满 body 内容区),
1928
+ /* 变量 mock 的 Raw JSON 编辑器:直接复用 .debug__scope-wrap 的绝对定位盒(inset 已占满 body 内容区),
1815
1929
  不再额外设 height:100%——否则 top/inset 的 bottom 与 height 冲突,盒子会比内容区高 10px,
1816
1930
  底部「应用/取消」按钮被挤出可视区、需滚动才见。这里仅保留 flex 列布局语义:
1817
1931
  编辑器占剩余空间并内部滚动,底部操作按钮始终钉在底部。 */
@@ -1833,8 +1947,6 @@ button.statusbar__conn {
1833
1947
  padding: 12px 14px;
1834
1948
  background: var(--bg-input);
1835
1949
  color: var(--text);
1836
- /* border: 1px solid var(--border-strong); */
1837
- /* border-radius: 8px; */
1838
1950
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1839
1951
  font-size: 12px;
1840
1952
  line-height: 1.6;
@@ -1843,34 +1955,383 @@ button.statusbar__conn {
1843
1955
  overflow: auto;
1844
1956
  outline: none;
1845
1957
  }
1846
- /* .debug__raw-editor:focus {
1847
- border-color: var(--accent-border);
1848
- } */
1849
- /* CodeJar 托管的原始 JSON 编辑器:Prism(json) 语法高亮配色(与 SetCode 暗色面板一致) */
1958
+ /* CodeJar 托管的 JSON 编辑器(mock Raw 视图 + 变量弹窗默认值代码区):
1959
+ Prism(json) 语法高亮配色(与 SetCode 暗色面板一致) */
1850
1960
  .debug__raw-editor .token.property,
1851
1961
  .debug__raw-editor .token.tag,
1852
1962
  .debug__raw-editor .token.boolean,
1853
1963
  .debug__raw-editor .token.number,
1854
1964
  .debug__raw-editor .token.constant,
1855
- .debug__raw-editor .token.symbol { color: var(--code-prop); }
1965
+ .debug__raw-editor .token.symbol,
1966
+ .vars-dlg__code .token.property,
1967
+ .vars-dlg__code .token.tag,
1968
+ .vars-dlg__code .token.boolean,
1969
+ .vars-dlg__code .token.number,
1970
+ .vars-dlg__code .token.constant,
1971
+ .vars-dlg__code .token.symbol { color: var(--code-prop); }
1856
1972
  .debug__raw-editor .token.selector,
1857
1973
  .debug__raw-editor .token.attr-name,
1858
1974
  .debug__raw-editor .token.string,
1859
1975
  .debug__raw-editor .token.char,
1860
- .debug__raw-editor .token.builtin { color: var(--code-str); }
1976
+ .debug__raw-editor .token.builtin,
1977
+ .vars-dlg__code .token.selector,
1978
+ .vars-dlg__code .token.attr-name,
1979
+ .vars-dlg__code .token.string,
1980
+ .vars-dlg__code .token.char,
1981
+ .vars-dlg__code .token.builtin { color: var(--code-str); }
1861
1982
  .debug__raw-editor .token.operator,
1862
1983
  .debug__raw-editor .token.entity,
1863
- .debug__raw-editor .token.url { color: var(--code-num); }
1864
- .debug__raw-editor .token.punctuation { color: var(--code-punc); }
1984
+ .debug__raw-editor .token.url,
1985
+ .vars-dlg__code .token.operator,
1986
+ .vars-dlg__code .token.entity,
1987
+ .vars-dlg__code .token.url { color: var(--code-num); }
1988
+ .debug__raw-editor .token.punctuation,
1989
+ .vars-dlg__code .token.punctuation { color: var(--code-punc); }
1865
1990
  .debug__raw-editor .token.keyword,
1866
- .debug__raw-editor .token.null { color: var(--code-kw); }
1991
+ .debug__raw-editor .token.null,
1992
+ .vars-dlg__code .token.keyword,
1993
+ .vars-dlg__code .token.null { color: var(--code-kw); }
1867
1994
  .debug__raw-editor .token.function,
1868
- .debug__raw-editor .token.class-name { color: var(--code-fn); }
1869
- .debug__raw-err {
1995
+ .debug__raw-editor .token.class-name,
1996
+ .vars-dlg__code .token.function,
1997
+ .vars-dlg__code .token.class-name { color: var(--code-fn); }
1998
+ /* mock 编辑器报错提示条:与顶部提示条(.app__nosvc-banner)同语言 ——
1999
+ 语义色软底通栏 + 图标 + 关闭钮;置于编辑器顶部,不挤占编辑区滚动 */
2000
+ .raw-err-bar {
1870
2001
  flex: 0 0 auto;
1871
- margin: 6px 0 0;
2002
+ display: flex;
2003
+ align-items: center;
2004
+ gap: 6px;
2005
+ /* 比顶部提示条小一号:面板内嵌条,不抢编辑区视觉 */
2006
+ padding: 4px 10px;
2007
+ color: var(--danger, #ef4444);
2008
+ background: var(--danger-soft, rgba(239, 68, 68, 0.12));
2009
+ font-size: 11px;
2010
+ line-height: 1.5;
2011
+ }
2012
+ .raw-err-bar__icn {
2013
+ flex: 0 0 12px;
2014
+ width: 12px;
2015
+ height: 12px;
2016
+ }
2017
+ .raw-err-bar__msg {
2018
+ flex: 1 1 auto;
2019
+ min-width: 0;
2020
+ }
2021
+ .raw-err-bar__close {
2022
+ flex: 0 0 auto;
2023
+ width: 18px;
2024
+ height: 18px;
2025
+ display: inline-flex;
2026
+ align-items: center;
2027
+ justify-content: center;
2028
+ padding: 0;
2029
+ border: none;
2030
+ border-radius: 4px;
2031
+ background: none;
2032
+ color: inherit;
2033
+ opacity: 0.7;
2034
+ font-size: 11px;
2035
+ line-height: 1;
2036
+ cursor: pointer;
2037
+ transition: opacity 0.12s;
2038
+ }
2039
+ .raw-err-bar__close:hover {
2040
+ opacity: 1;
2041
+ }
2042
+
2043
+ /* ===== 变量管理(原「绑定数据」tab)=====
2044
+ 列表视图管理 schema.dictionary.inputParams;mock 编辑收进二级视图。
2045
+ 行内信息密度优先:key 等宽 + 类型芯片 + mock 徽标 + 中文名/描述弱化,操作 hover 浮现。 */
2046
+ .vars {
2047
+ height: 100%;
2048
+ min-height: 0;
2049
+ display: flex;
2050
+ flex-direction: column;
2051
+ /* 右下角悬浮操作组的定位锚 */
2052
+ position: relative;
2053
+ }
2054
+ .vars__list {
2055
+ flex: 1 1 auto;
2056
+ min-height: 0;
2057
+ margin: 0;
2058
+ /* 底部留出悬浮操作组的高度,末行不被遮 */
2059
+ padding: 8px 8px 52px;
2060
+ list-style: none;
2061
+ overflow-y: auto;
2062
+ display: flex;
2063
+ flex-direction: column;
2064
+ gap: 2px;
2065
+ }
2066
+ .vars__row {
2067
+ display: flex;
2068
+ align-items: center;
2069
+ gap: 6px;
2070
+ padding: 4px 6px;
2071
+ border-radius: 6px;
2072
+ transition: background 0.12s;
2073
+ /* 双击编辑:禁止双击选中文本造成视觉噪声 */
2074
+ user-select: none;
2075
+ }
2076
+ .vars__row:hover {
2077
+ background: var(--bg-hover);
2078
+ }
2079
+ .vars__key {
2080
+ flex: 0 0 auto;
2081
+ max-width: 46%;
2082
+ overflow: hidden;
2083
+ text-overflow: ellipsis;
2084
+ white-space: nowrap;
2085
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
2086
+ font-size: 12px;
2087
+ color: var(--text);
2088
+ }
2089
+ .vars__type {
2090
+ flex: 0 0 auto;
2091
+ padding: 1px 6px;
2092
+ border-radius: var(--radius-pill);
2093
+ background: var(--bg-active);
2094
+ color: var(--text-dim);
2095
+ font-size: 10px;
2096
+ line-height: 1.5;
2097
+ }
2098
+ /* 类型标签按类型分浅色:色相取自 --type-*(暗色等同代码高亮调色板,亮色单独校正
2099
+ string 为绿系,避免与 number 蓝调撞色);软底用 color-mix 取低透明度,文字保持
2100
+ 高对比可读。五色:string 绿 / number 蓝 / boolean 红 / array 紫 / object 橙。 */
2101
+ .vars__type--string {
2102
+ color: var(--type-string);
2103
+ background: color-mix(in srgb, var(--type-string) 14%, transparent);
2104
+ }
2105
+ .vars__type--number {
2106
+ color: var(--type-number);
2107
+ background: color-mix(in srgb, var(--type-number) 14%, transparent);
2108
+ }
2109
+ .vars__type--boolean {
2110
+ color: var(--type-boolean);
2111
+ background: color-mix(in srgb, var(--type-boolean) 14%, transparent);
2112
+ }
2113
+ .vars__type--array {
2114
+ color: var(--type-array);
2115
+ background: color-mix(in srgb, var(--type-array) 14%, transparent);
2116
+ }
2117
+ .vars__type--object {
2118
+ color: var(--type-object);
2119
+ background: color-mix(in srgb, var(--type-object) 14%, transparent);
2120
+ }
2121
+ /* mock 徽标:与运营平台变量列表的 m 标记同语义(已配置 mock 默认值) */
2122
+ .vars__mock {
2123
+ flex: 0 0 auto;
2124
+ width: 14px;
2125
+ height: 14px;
2126
+ display: inline-flex;
2127
+ align-items: center;
2128
+ justify-content: center;
2129
+ border-radius: 50%;
2130
+ background: var(--warn-soft);
2131
+ color: var(--warn);
2132
+ font-size: 9px;
2133
+ line-height: 1;
2134
+ }
2135
+ .vars__name {
2136
+ flex: 1 1 auto;
2137
+ min-width: 0;
2138
+ overflow: hidden;
2139
+ text-overflow: ellipsis;
2140
+ white-space: nowrap;
2141
+ color: var(--text-faint);
2142
+ font-size: 11px;
2143
+ }
2144
+ /* 行内操作:常占位、仅淡入淡出 —— 用 display 切换会挤动 key/name 造成 hover 跳动 */
2145
+ .vars__ops {
2146
+ flex: 0 0 auto;
2147
+ display: inline-flex;
2148
+ gap: 2px;
2149
+ opacity: 0;
2150
+ transition: opacity 0.12s;
2151
+ }
2152
+ .vars__row:hover .vars__ops,
2153
+ .vars__row:focus-within .vars__ops {
2154
+ opacity: 1;
2155
+ }
2156
+ .vars__op {
2157
+ width: 20px;
2158
+ height: 20px;
2159
+ display: inline-flex;
2160
+ align-items: center;
2161
+ justify-content: center;
2162
+ padding: 0;
2163
+ background: none;
2164
+ border: none;
2165
+ border-radius: 4px;
2166
+ color: var(--text-faint);
2167
+ cursor: pointer;
2168
+ transition: background 0.12s, color 0.12s;
2169
+ }
2170
+ .vars__op svg {
2171
+ width: 13px;
2172
+ height: 13px;
2173
+ display: block;
2174
+ }
2175
+ .vars__op:hover {
2176
+ background: var(--bg-active);
2177
+ color: var(--text);
2178
+ }
2179
+ .vars__op--del:hover {
2180
+ background: var(--danger-soft);
2181
+ color: var(--danger);
2182
+ }
2183
+ /* 无默认值时禁用(复制钮):压淡并保持无 hover 反馈,避免误点无响应 */
2184
+ .vars__op:disabled,
2185
+ .vars__op:disabled:hover {
2186
+ background: none;
2187
+ color: var(--text-faint);
2188
+ opacity: 0.35;
2189
+ cursor: default;
2190
+ }
2191
+ /* 复制成功的 ✓ 沿用 .debug__copy-ok 配色,按行内 13px 图标尺度收一号 */
2192
+ .vars__op .debug__copy-ok {
1872
2193
  font-size: 12px;
2194
+ }
2195
+ /* 右下角悬浮操作组:卡片容器 + 投影,与 mock 视图 .debug__scope-foot 同语言 */
2196
+ .vars__fabs {
2197
+ position: absolute;
2198
+ right: 10px;
2199
+ bottom: 10px;
2200
+ display: flex;
2201
+ align-items: center;
2202
+ gap: 8px;
2203
+ padding: 6px;
2204
+ background: var(--bg-bar);
2205
+ border: 1px solid var(--border);
2206
+ border-radius: 10px;
2207
+ box-shadow: 0 6px 18px var(--shadow-toast);
2208
+ }
2209
+ /* mock 二级视图头:返回 + 标题,发丝线分隔 */
2210
+ .vars__mockhead {
2211
+ flex: 0 0 auto;
2212
+ display: flex;
2213
+ align-items: center;
2214
+ gap: 8px;
2215
+ padding: 5px 10px;
2216
+ border-bottom: var(--hairline) solid var(--border);
2217
+ }
2218
+ .vars__back {
2219
+ flex: 0 0 auto;
2220
+ display: inline-flex;
2221
+ align-items: center;
2222
+ gap: 4px;
2223
+ height: 24px;
2224
+ padding: 0 9px 0 7px;
2225
+ background: var(--bg-bar);
2226
+ border: 1px solid var(--border-strong);
2227
+ border-radius: 6px;
2228
+ color: var(--text);
2229
+ font-size: 12px;
2230
+ font-weight: 500;
2231
+ cursor: pointer;
2232
+ transition: background 0.15s, color 0.15s, border-color 0.15s;
2233
+ }
2234
+ /* hover 走软 accent 三件套(与结构树徽标 / 桥接按钮激活态同语言),让「可点返回」一眼可辨 */
2235
+ .vars__back:hover {
2236
+ background: var(--accent-soft);
2237
+ border-color: var(--accent-border);
2238
+ color: var(--accent);
2239
+ }
2240
+ .vars__back svg {
2241
+ width: 12px;
2242
+ height: 12px;
2243
+ }
2244
+ .vars__mocktitle {
2245
+ color: var(--text-faint);
2246
+ font-size: 11px;
2247
+ }
2248
+
2249
+ /* 变量添加 / 编辑弹窗:骨架与节点属性面板同构(ni-panel / ni-head / ni-foot / ni-field-row),
2250
+ 这里只覆写尺寸与表单特有件:宽度同 ni-panel、高度随内容、代码编辑区与必填星号。 */
2251
+ /* node-inspector.css 晚于本文件载入,等特异性下 .ni-panel 的 80vh 会赢,故用双类提特异性 */
2252
+ .ni-panel.vars-dlg {
2253
+ width: 560px;
2254
+ height: auto;
2255
+ min-height: 0;
2256
+ max-height: 80vh;
2257
+ }
2258
+ /* 必填星号:与表单错误同族 danger 色 */
2259
+ .vars-dlg .ni-field-label i {
2260
+ font-style: normal;
2261
+ color: var(--danger);
2262
+ margin-right: 2px;
2263
+ }
2264
+ /* 默认值 / 描述行:标签与控件首行对齐(28px 控件首行基线) */
2265
+ .ni-field-row--top {
2266
+ align-items: flex-start;
2267
+ }
2268
+ .ni-field-row--top .ni-field-label {
2269
+ line-height: var(--ctrl-sm);
2270
+ }
2271
+ /* Dropdown 撑满控件区(ni-field-row 的 flex 规则只约束 .ni-input) */
2272
+ .vars-dlg__ctrl {
2273
+ flex: 1 1 auto;
2274
+ min-width: 0;
2275
+ }
2276
+ /* 默认值多行编辑区(数组 / 对象的 CodeJar 代码区、字符串的文本域)共用一把尺子:
2277
+ 高度下限 = 8 行文本 —— 行高 12px × 1.6 = 19.2px,18px = 上下 padding 16 + 边框 2(border-box)。
2278
+ 两者垂直内边距一致,切类型时弹窗高度不跳;min-height 同时夹住 flex 压缩与 resize 拖拽下限,
2279
+ 内容超出后在 max-height 内滚动。 */
2280
+ .vars-dlg__code,
2281
+ .vars-dlg__str {
2282
+ min-height: calc(8 * 1.6 * 12px + 18px);
2283
+ max-height: 264px;
2284
+ }
2285
+ /* 数组 / 对象默认值:CodeJar 代码编辑区(与 mock Raw 编辑器同族,嵌入表单行) */
2286
+ .vars-dlg__code {
2287
+ flex: 1 1 auto;
2288
+ min-width: 0;
2289
+ overflow: auto;
2290
+ padding: 8px 12px;
2291
+ background: var(--bg-input);
2292
+ border: 1px solid var(--border-strong);
2293
+ border-radius: 6px;
2294
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
2295
+ font-size: 12px;
2296
+ line-height: 1.6;
2297
+ color: var(--text);
2298
+ tab-size: 2;
2299
+ white-space: pre;
2300
+ outline: none;
2301
+ transition: border-color 0.15s;
2302
+ }
2303
+ .vars-dlg__code:focus {
2304
+ border-color: var(--accent);
2305
+ }
2306
+ /* 字符串默认值:多行文本域(数字走 NumberStepper、布尔走单选,都是单行高),
2307
+ 长文案与多行字符串能一眼看全。.ni-input 定义在 node-inspector.css(晚于本文件载入),
2308
+ 等特异性下会赢,故用双类提特异性覆盖其 28px 定高与 6px 垂直内边距,与代码区完全同高。 */
2309
+ .ni-input.vars-dlg__str {
2310
+ height: auto;
2311
+ padding: 8px 12px;
2312
+ line-height: 1.6;
2313
+ resize: vertical;
2314
+ overflow: auto;
2315
+ }
2316
+ .vars-dlg__desc {
2317
+ height: auto;
2318
+ /* 高度下限 = 4 行文本:行高 12px(.ni-input)× 1.6 = 19.2px,14px = 上下 padding 12 + 边框 2(border-box)。
2319
+ min-height 同时夹住 resize: vertical 的拖拽下限,拖不小于 4 行。 */
2320
+ min-height: calc(4 * 1.6 * 12px + 14px);
2321
+ max-height: 140px;
2322
+ resize: vertical;
2323
+ line-height: 1.6;
2324
+ }
2325
+ .vars-dlg__err {
2326
+ margin: 2px 0 0;
1873
2327
  color: var(--danger);
2328
+ font-size: 11px;
2329
+ }
2330
+ /* mock 二级视图头部右端弱提示:不抢视觉,仅解释覆盖语义 */
2331
+ .vars__mockhint {
2332
+ margin-left: auto;
2333
+ font-size: 11px;
2334
+ color: var(--text-faint);
1874
2335
  }
1875
2336
 
1876
2337
  /* 底部状态栏(类 VSCode 暗色状态栏,沿用主题 token,与顶栏/面板统一) */
@@ -1883,7 +2344,7 @@ button.statusbar__conn {
1883
2344
  order: 3;
1884
2345
  padding: 0 2px;
1885
2346
  background: var(--bg-bar);
1886
- border-top: 1px solid var(--border);
2347
+ border-top: var(--hairline) solid var(--border);
1887
2348
  font-size: 12px;
1888
2349
  color: var(--text-dim);
1889
2350
  user-select: none;
@@ -1903,9 +2364,9 @@ button.statusbar__conn {
1903
2364
  .statusbar__item--right {
1904
2365
  color: var(--text-faint);
1905
2366
  }
1906
- /* 问题指示器:沿用统一 hover 语言(bg-hover + accent 文字),保持与整体风格一致 */
1907
- /* 问题指示器:本质是一行状态栏文本读数,不是按钮——
1908
- 无边框 / 无圆角 / 无 hover 背景块;仅在有错误时文字+图标着 danger 红作为提示 */
2367
+ /* 问题指示器:本质是一行状态栏文本读数,不是按钮——无边框 / 无圆角 / 无 hover 背景块。
2368
+ 配色铁律:状态栏文字默认色,仅报错(danger)/ 警告(warn)态着语义色;
2369
+ 展开、有日志等非风险态不再着色(面板可见本身即「已展开」的提示)。 */
1909
2370
  .statusbar__item--prob {
1910
2371
  cursor: pointer;
1911
2372
  color: var(--text-dim);
@@ -1923,12 +2384,6 @@ button.statusbar__conn {
1923
2384
  .statusbar__item--prob.is-error:hover {
1924
2385
  color: var(--danger);
1925
2386
  }
1926
- .statusbar__item--prob.is-log {
1927
- color: var(--accent);
1928
- }
1929
- .statusbar__item--prob.is-log:hover {
1930
- color: var(--accent);
1931
- }
1932
2387
  .statusbar__item--prob.is-ok {
1933
2388
  color: var(--text-faint);
1934
2389
  cursor: default;
@@ -1958,7 +2413,7 @@ button.statusbar__conn {
1958
2413
  max-height: 60vh;
1959
2414
  overflow: hidden;
1960
2415
  background: var(--bg-panel);
1961
- border-top: 1px solid var(--border-strong);
2416
+ border-top: var(--hairline) solid var(--border-strong);
1962
2417
  }
1963
2418
  .errpanel__head {
1964
2419
  flex: 0 0 auto;
@@ -1967,7 +2422,7 @@ button.statusbar__conn {
1967
2422
  gap: 8px;
1968
2423
  height: var(--ctrl-lg);
1969
2424
  padding: 0 12px;
1970
- border-bottom: 1px solid var(--border);
2425
+ border-bottom: var(--hairline) solid var(--border);
1971
2426
  font-size: 13px;
1972
2427
  color: var(--text);
1973
2428
  }
@@ -2178,7 +2633,7 @@ button.statusbar__conn {
2178
2633
  align-items: baseline;
2179
2634
  gap: 8px;
2180
2635
  padding: 2px 12px;
2181
- border-bottom: 1px solid var(--border);
2636
+ border-bottom: var(--hairline) solid var(--border);
2182
2637
  }
2183
2638
  .log__item:last-child {
2184
2639
  border-bottom: none;
@@ -2256,7 +2711,7 @@ button.statusbar__conn {
2256
2711
  .log__json .apt__list--nested {
2257
2712
  margin-left: 4px;
2258
2713
  padding-left: 14px;
2259
- border-left: 1px solid var(--border);
2714
+ border-left: var(--hairline) solid var(--border);
2260
2715
  }
2261
2716
  .log__empty {
2262
2717
  color: var(--text-faint);
@@ -2387,7 +2842,7 @@ button.statusbar__conn {
2387
2842
  display: flex;
2388
2843
  /* 负外边距抵消对话框左右内边距,分割线贯通左右边缘 */
2389
2844
  margin: 18px -20px 0;
2390
- border-top: 1px solid #e8e8e8;
2845
+ border-top: var(--hairline) solid #e8e8e8;
2391
2846
  }
2392
2847
  .dlg__btn {
2393
2848
  flex: 1 1 0;
@@ -2404,7 +2859,7 @@ button.statusbar__conn {
2404
2859
  }
2405
2860
  .dlg__btn--cancel {
2406
2861
  color: #1677ff;
2407
- border-right: 1px solid #e8e8e8;
2862
+ border-right: var(--hairline) solid #e8e8e8;
2408
2863
  }
2409
2864
  /* cancelGrayStyle:取消按钮灰色风格 */
2410
2865
  .dlg__btn--cancel.dlg__btn--gray {
@@ -2568,7 +3023,7 @@ button.statusbar__conn {
2568
3023
  height: 44px;
2569
3024
  padding: 0 16px;
2570
3025
  box-sizing: border-box;
2571
- border-bottom: 1px solid #eef0f2;
3026
+ border-bottom: var(--hairline) solid #eef0f2;
2572
3027
  }
2573
3028
  .pk-bar__title {
2574
3029
  font-size: 15px;
@@ -2610,8 +3065,8 @@ button.statusbar__conn {
2610
3065
  height: 40px;
2611
3066
  transform: translateY(-50%);
2612
3067
  background: rgba(22, 119, 255, 0.08);
2613
- border-top: 1px solid #d6e4ff;
2614
- border-bottom: 1px solid #d6e4ff;
3068
+ border-top: var(--hairline) solid #d6e4ff;
3069
+ border-bottom: var(--hairline) solid #d6e4ff;
2615
3070
  pointer-events: none;
2616
3071
  }
2617
3072
  .pk-col__list {
@@ -2691,7 +3146,7 @@ button.statusbar__conn {
2691
3146
  align-items: center;
2692
3147
  justify-content: space-between;
2693
3148
  padding: 12px 14px;
2694
- border-bottom: 1px solid var(--border);
3149
+ border-bottom: var(--hairline) solid var(--border);
2695
3150
  }
2696
3151
  .rp-title {
2697
3152
  font-size: 14px;