@philomelcc/dsh-workbench 0.1.4 → 0.1.6

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 (3) hide show
  1. package/README.md +11 -14
  2. package/client.js +100 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,26 +1,23 @@
1
1
  # @philomelcc/dsh-workbench
2
2
 
3
- The shell: a second top-bar row of workbench tabs, one page per module, plus the
4
- small API modules register against.
3
+ 外壳本体:顶部第二行的标签切换、每个模块一整页,以及模块注册用的那套小 API。
5
4
 
6
- This package does almost nothing on its own — install it together with at least
7
- one module:
5
+ 它单独装没什么用——至少配一个模块:
8
6
 
9
7
  ```powershell
10
8
  dsh plugin --profile web add @philomelcc/dsh-workbench
11
9
  dsh plugin --profile web add @philomelcc/dsh-status-monitor
12
10
  ```
13
11
 
14
- Contract: [`docs/SPEC.md`](../../docs/SPEC.md) · module template: [`template/`](../../template) ·
15
- ready-made modules: [status monitor](../status-monitor), [download center](../download-center).
12
+ 契约:[`docs/SPEC.md`](../../docs/SPEC.md) · 模板:[`template/`](../../template) ·
13
+ 现成模块:[状态监控](../status-monitor)、[下载中心](../download-center)。
16
14
 
17
- What the shell provides:
15
+ 外壳提供:
18
16
 
19
- - `registerView({ id, title, icon, component, order, subtitle, badge, tab })` —
20
- one tab, one full page;
21
- - `components` (StatusDot, Card, SectionHeader, EmptyState, Spinner, Button, Field);
22
- - `tokens` (theme colors that follow light/dark);
23
- - `apiVersion` — `1` today;
24
- - `refresh()` — repaint the tab row after a badge changed.
17
+ - `registerView({ id, title, icon, component, order, subtitle, badge, tab })` —— 一个标签、一整页;
18
+ - `components`(StatusDot / Card / SectionHeader / EmptyState / Spinner / Button / Field);
19
+ - `tokens`(跟随明暗主题的颜色 token);
20
+ - `apiVersion` —— 目前是 `1`;
21
+ - `refresh()` —— 角标变化后重绘标签行。
25
22
 
26
- MIT.
23
+ MIT。
package/client.js CHANGED
@@ -442,10 +442,10 @@ window.__ModuleLoader__.load({
442
442
  // localStorage by us.
443
443
  const PAPER_KEY = 'dsh-workbench:paper';
444
444
  const PAPER_TOKENS = {
445
- '--dsw-alias-bg-base': '#f4efe3',
446
- '--dsw-alias-bg-layer-1': '#efe9db',
447
- '--dsw-alias-bg-layer-2': '#e7dfcd',
448
- '--dsw-alias-bg-overlay': '#fbf7ee',
445
+ '--dsw-alias-bg-base': '#f7f3ea',
446
+ '--dsw-alias-bg-layer-1': '#f2ece0',
447
+ '--dsw-alias-bg-layer-2': '#ece5d6',
448
+ '--dsw-alias-bg-overlay': '#faf5e9',
449
449
  '--dsw-alias-border-l1': '#d8cfba',
450
450
  '--dsw-alias-border-l2': '#c6bba2',
451
451
  '--dsw-alias-brand-primary': '#8a6a45',
@@ -455,7 +455,33 @@ window.__ModuleLoader__.load({
455
455
  '--dsw-alias-state-warn-primary': '#a8792c',
456
456
  '--dsw-alias-state-success-primary': '#4f7a5a',
457
457
  '--dsw-alias-state-idle-primary': '#a49a89',
458
- '--dsw-specific-sidebar-fill': '#efe9db',
458
+ '--dsw-specific-sidebar-fill': '#f2ece0',
459
+ // Chat bubbles: the light base uses a pale DeepSeek blue, which looks
460
+ // wrong on paper. These two are outside the alias layer.
461
+ '--dsw-specific-bubble': '#f2ecdf',
462
+ '--dsw-specific-bubble-highlight': '#e9dfcb',
463
+ // Pale blue surfaces the alias list does not cover: command chips,
464
+ // reference pills, selected file tabs, "load earlier", tool cards.
465
+ '--dsw-alias-state-business-tertiary': '#f1e9da',
466
+ '--dsw-alias-state-business-primary': '#8a6a45',
467
+ '--dsw-specific-sidebar-nav-item-active-accent': '#f1e9da',
468
+ '--dsw-specific-sidebar-nav-item-active': '#efe9db',
469
+ '--dsw-specific-selector': '#f1e9da',
470
+ '--dsw-specific-input-major': '#f2ece0',
471
+ '--dsw-specific-tip': '#f7f2e7',
472
+ '--dsw-specific-menu': '#fcf9f3',
473
+ // The neutral greys are blue-tinted. Buttons ("load earlier"), inputs,
474
+ // chips and cards read their pale surfaces from this ramp, so warm it up
475
+ // too; deep steps stay untouched because they are text/borders.
476
+ '--dsw-static-neutral-bluish-00': '#fbf6ea',
477
+ '--dsw-static-neutral-bluish-50': '#faf6ee',
478
+ '--dsw-static-neutral-bluish-55': '#f8f4ea',
479
+ '--dsw-static-neutral-bluish-60': '#f7f3ea',
480
+ '--dsw-static-neutral-bluish-75': '#f4eee1',
481
+ '--dsw-static-neutral-bluish-90': '#f2ecdf',
482
+ '--dsw-static-neutral-bluish-100': '#efe9db',
483
+ '--dsw-static-neutral-bluish-150': '#ece6d7',
484
+ '--dsw-static-neutral-bluish-200': '#e7dfcd',
459
485
  };
460
486
 
461
487
  // Swatches double as both the current-state indicator and the toggle.
@@ -504,12 +530,55 @@ window.__ModuleLoader__.load({
504
530
  try { paperDispose(); } catch (_error) { /* already gone */ }
505
531
  paperDispose = null;
506
532
  }
533
+ // Marker for paper-only rules (code surfaces) that tokens cannot reach.
534
+ try {
535
+ if (on) document.body.setAttribute('data-wb-paper', '1');
536
+ else document.body.removeAttribute('data-wb-paper');
537
+ } catch (_error) { /* body not ready */ }
507
538
  }
508
539
 
509
540
  function ThemeSwitcher() {
541
+ const boxRef = React.useRef(null);
510
542
  const [paper, setPaperState] = React.useState(readPaper);
511
543
  const [preference, setPreference] = React.useState(readPreference);
512
544
 
545
+ // The account block is fixed to the right and changes width (a reconnect
546
+ // banner widens it), so park the swatches against its measured left edge
547
+ // instead of a guessed margin.
548
+ React.useEffect(() => {
549
+ const box = boxRef.current;
550
+ if (!box) return undefined;
551
+ const place = () => {
552
+ const settings = document.querySelector('[class*="settingsArea"]');
553
+ if (!settings) {
554
+ box.style.right = '150px';
555
+ return;
556
+ }
557
+ const rect = settings.getBoundingClientRect();
558
+ if (rect.width > 0) box.style.right = (rect.width + 16 + 12) + 'px';
559
+ // Same box as the account block, so `align-items: center` lands on
560
+ // the account's optical center instead of a guessed offset.
561
+ if (rect.height > 0) {
562
+ box.style.top = rect.top + 'px';
563
+ box.style.height = rect.height + 'px';
564
+ }
565
+ };
566
+ place();
567
+ let observer = null;
568
+ const settings = document.querySelector('[class*="settingsArea"]');
569
+ if (settings && typeof ResizeObserver !== 'undefined') {
570
+ observer = new ResizeObserver(place);
571
+ // border-box: the account's width changes through its chrome, not
572
+ // just its text content.
573
+ observer.observe(settings, { box: 'border-box' });
574
+ }
575
+ window.addEventListener('resize', place);
576
+ return () => {
577
+ if (observer) observer.disconnect();
578
+ window.removeEventListener('resize', place);
579
+ };
580
+ }, []);
581
+
513
582
  // Re-apply the saved paper layer after a reload / remount.
514
583
  React.useEffect(() => {
515
584
  if (readPaper()) setPaper(true);
@@ -555,7 +624,11 @@ window.__ModuleLoader__.load({
555
624
  };
556
625
 
557
626
  return h('div', {
558
- style: { display: 'inline-flex', alignItems: 'center', gap: 8, flex: '0 0 auto' },
627
+ ref: boxRef,
628
+ style: {
629
+ position: 'fixed', top: 2, height: 40, zIndex: 301,
630
+ display: 'inline-flex', alignItems: 'center', gap: 8,
631
+ },
559
632
  title: '主题',
560
633
  },
561
634
  THEME_SWATCHES.map((swatch) => {
@@ -593,7 +666,9 @@ window.__ModuleLoader__.load({
593
666
  const tone = snap.phase === 'ready' ? balanceTone(snap.amount) : 'muted';
594
667
  const value = snap.phase === 'ready' && typeof snap.amount === 'number' ? snap.amount.toFixed(2) : (snap.phase === 'loading' ? '…' : '—');
595
668
  const toneColor = tone === 'green' ? '#4ade80' : tone === 'amber' ? '#e3b341' : tone === 'red' ? '#f87171' : 'var(--dsw-alias-label-secondary)';
596
- const borderBase = tone === 'green' ? '#2f4a37' : tone === 'amber' ? '#4a3d22' : tone === 'red' ? '#4a2a2a' : 'var(--dsw-alias-border-l2)';
669
+ // The border follows the theme: hard-coded dark greens read as a black
670
+ // ring on light/paper backgrounds.
671
+ const borderBase = 'var(--dsw-alias-border-l2)';
597
672
  const at = new Date(snap.updatedAt || Date.now()).toLocaleTimeString('zh-CN', { hour12: false });
598
673
  return h('div', {
599
674
  style: { position: 'relative', display: 'inline-flex' },
@@ -789,7 +864,7 @@ window.__ModuleLoader__.load({
789
864
  iconBtn('plugins', '插件', IconPlugins),
790
865
  iconBtn('schedules', '自动化任务', IconClock),
791
866
  ),
792
- h('div', { style: { flex: '0 0 auto', marginRight: 150 } }, h(ThemeSwitcher)),
867
+ h(ThemeSwitcher),
793
868
  ),
794
869
  h('div', { style: { height: 45, display: 'flex', alignItems: 'center', gap: 8, padding: '0 14px', borderTop: '1px solid var(--dsw-alias-border-l1)' } },
795
870
  h('div', { ref: tabsRef, style: { position: 'relative', display: 'flex', alignItems: 'center', gap: 4, flex: 1, overflowX: 'auto', overflowY: 'hidden' } },
@@ -1116,6 +1191,23 @@ div[data-row-key^="session:"]:has(svg[data-state="ongoing"]) svg[data-state="ong
1116
1191
  .dsh-glow-on > span:first-child > svg {
1117
1192
  display: none !important;
1118
1193
  }
1194
+ /* paper: every card-like surface follows the paper base; the code surface is
1195
+ deeper and overrides the card rule below (same specificity, later wins). */
1196
+ body[data-wb-paper="1"] [class*="_tile"],
1197
+ body[data-wb-paper="1"] [class*="_card"],
1198
+ body[data-wb-paper="1"] [class*="_Card"],
1199
+ body[data-wb-paper="1"] [class*="_fileCard"],
1200
+ body[data-wb-paper="1"] [class*="hz8-rW_header"] {
1201
+ background: #f2ece0 !important;
1202
+ }
1203
+ body[data-wb-paper="1"] .md-code-block,
1204
+ body[data-wb-paper="1"] pre,
1205
+ body[data-wb-paper="1"] [class*="_header_1mqf1"] {
1206
+ background: #ece2cc !important;
1207
+ }
1208
+ body[data-wb-paper="1"] :not(pre) > code {
1209
+ background: #efe6d4 !important;
1210
+ }
1119
1211
  `;
1120
1212
 
1121
1213
  function installGlow(ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@philomelcc/dsh-workbench",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "Workbench shell for DeepSeek Harness: a view/page module API, shared UI primitives and a top-bar switcher.",
6
6
  "license": "MIT",