@philomelcc/dsh-workbench 0.1.4 → 0.1.5

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 +51 -3
  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
@@ -456,6 +456,10 @@ window.__ModuleLoader__.load({
456
456
  '--dsw-alias-state-success-primary': '#4f7a5a',
457
457
  '--dsw-alias-state-idle-primary': '#a49a89',
458
458
  '--dsw-specific-sidebar-fill': '#efe9db',
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': '#efe7d6',
462
+ '--dsw-specific-bubble-highlight': '#e4d8c0',
459
463
  };
460
464
 
461
465
  // Swatches double as both the current-state indicator and the toggle.
@@ -507,9 +511,47 @@ window.__ModuleLoader__.load({
507
511
  }
508
512
 
509
513
  function ThemeSwitcher() {
514
+ const boxRef = React.useRef(null);
510
515
  const [paper, setPaperState] = React.useState(readPaper);
511
516
  const [preference, setPreference] = React.useState(readPreference);
512
517
 
518
+ // The account block is fixed to the right and changes width (a reconnect
519
+ // banner widens it), so park the swatches against its measured left edge
520
+ // instead of a guessed margin.
521
+ React.useEffect(() => {
522
+ const box = boxRef.current;
523
+ if (!box) return undefined;
524
+ const place = () => {
525
+ const settings = document.querySelector('[class*="settingsArea"]');
526
+ if (!settings) {
527
+ box.style.right = '150px';
528
+ return;
529
+ }
530
+ const rect = settings.getBoundingClientRect();
531
+ if (rect.width > 0) box.style.right = (rect.width + 16 + 12) + 'px';
532
+ // Same box as the account block, so `align-items: center` lands on
533
+ // the account's optical center instead of a guessed offset.
534
+ if (rect.height > 0) {
535
+ box.style.top = rect.top + 'px';
536
+ box.style.height = rect.height + 'px';
537
+ }
538
+ };
539
+ place();
540
+ let observer = null;
541
+ const settings = document.querySelector('[class*="settingsArea"]');
542
+ if (settings && typeof ResizeObserver !== 'undefined') {
543
+ observer = new ResizeObserver(place);
544
+ // border-box: the account's width changes through its chrome, not
545
+ // just its text content.
546
+ observer.observe(settings, { box: 'border-box' });
547
+ }
548
+ window.addEventListener('resize', place);
549
+ return () => {
550
+ if (observer) observer.disconnect();
551
+ window.removeEventListener('resize', place);
552
+ };
553
+ }, []);
554
+
513
555
  // Re-apply the saved paper layer after a reload / remount.
514
556
  React.useEffect(() => {
515
557
  if (readPaper()) setPaper(true);
@@ -555,7 +597,11 @@ window.__ModuleLoader__.load({
555
597
  };
556
598
 
557
599
  return h('div', {
558
- style: { display: 'inline-flex', alignItems: 'center', gap: 8, flex: '0 0 auto' },
600
+ ref: boxRef,
601
+ style: {
602
+ position: 'fixed', top: 2, height: 40, zIndex: 301,
603
+ display: 'inline-flex', alignItems: 'center', gap: 8,
604
+ },
559
605
  title: '主题',
560
606
  },
561
607
  THEME_SWATCHES.map((swatch) => {
@@ -593,7 +639,9 @@ window.__ModuleLoader__.load({
593
639
  const tone = snap.phase === 'ready' ? balanceTone(snap.amount) : 'muted';
594
640
  const value = snap.phase === 'ready' && typeof snap.amount === 'number' ? snap.amount.toFixed(2) : (snap.phase === 'loading' ? '…' : '—');
595
641
  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)';
642
+ // The border follows the theme: hard-coded dark greens read as a black
643
+ // ring on light/paper backgrounds.
644
+ const borderBase = 'var(--dsw-alias-border-l2)';
597
645
  const at = new Date(snap.updatedAt || Date.now()).toLocaleTimeString('zh-CN', { hour12: false });
598
646
  return h('div', {
599
647
  style: { position: 'relative', display: 'inline-flex' },
@@ -789,7 +837,7 @@ window.__ModuleLoader__.load({
789
837
  iconBtn('plugins', '插件', IconPlugins),
790
838
  iconBtn('schedules', '自动化任务', IconClock),
791
839
  ),
792
- h('div', { style: { flex: '0 0 auto', marginRight: 150 } }, h(ThemeSwitcher)),
840
+ h(ThemeSwitcher),
793
841
  ),
794
842
  h('div', { style: { height: 45, display: 'flex', alignItems: 'center', gap: 8, padding: '0 14px', borderTop: '1px solid var(--dsw-alias-border-l1)' } },
795
843
  h('div', { ref: tabsRef, style: { position: 'relative', display: 'flex', alignItems: 'center', gap: 4, flex: 1, overflowX: 'auto', overflowY: 'hidden' } },
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.5",
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",