@philomelcc/dsh-workbench 0.1.2 → 0.1.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.
- package/client.js +100 -1
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -434,7 +434,96 @@ window.__ModuleLoader__.load({
|
|
|
434
434
|
h('path', { d: 'M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H9l-4 3.5V6z', stroke: 'currentColor', strokeWidth: 1.6, strokeLinejoin: 'round' }));
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
// ---------- theme switcher ----------
|
|
438
|
+
// `paper` builds on the light palette and overrides the alias layer only.
|
|
439
|
+
const PAPER_THEME = {
|
|
440
|
+
id: 'paper',
|
|
441
|
+
colorScheme: 'light',
|
|
442
|
+
tokens: {
|
|
443
|
+
'--dsw-alias-bg-base': '#f4efe3',
|
|
444
|
+
'--dsw-alias-bg-layer-1': '#efe9db',
|
|
445
|
+
'--dsw-alias-bg-layer-2': '#e7dfcd',
|
|
446
|
+
'--dsw-alias-bg-overlay': '#fbf7ee',
|
|
447
|
+
'--dsw-alias-border-l1': '#d8cfba',
|
|
448
|
+
'--dsw-alias-border-l2': '#c6bba2',
|
|
449
|
+
'--dsw-alias-brand-primary': '#8a6a45',
|
|
450
|
+
'--dsw-alias-label-primary': '#3b342a',
|
|
451
|
+
'--dsw-alias-label-secondary': '#6f6557',
|
|
452
|
+
'--dsw-alias-state-error-primary': '#a34a3c',
|
|
453
|
+
'--dsw-alias-state-warn-primary': '#a8792c',
|
|
454
|
+
'--dsw-alias-state-success-primary': '#4f7a5a',
|
|
455
|
+
'--dsw-alias-state-idle-primary': '#a49a89',
|
|
456
|
+
'--dsw-specific-sidebar-fill': '#efe9db',
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// Swatches double as both the current-state indicator and the toggle.
|
|
461
|
+
const THEME_SWATCHES = [
|
|
462
|
+
{ id: 'dark', label: '深色', color: '#15171a' },
|
|
463
|
+
{ id: 'light', label: '浅色', color: '#f7f8fa' },
|
|
464
|
+
{ id: 'paper', label: '纸质', color: '#f4efe3' },
|
|
465
|
+
];
|
|
466
|
+
|
|
467
|
+
function createThemeSwitcher(ctx) {
|
|
468
|
+
function ThemeSwitcher() {
|
|
469
|
+
const theme = typeof ctx.get === 'function' ? ctx.get('theme') : ctx.theme;
|
|
470
|
+
const read = () => {
|
|
471
|
+
try {
|
|
472
|
+
const snapshot = theme && typeof theme.getTheme === 'function' ? theme.getTheme() : null;
|
|
473
|
+
return snapshot ? snapshot.preference : null;
|
|
474
|
+
} catch (_error) {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
const [preference, setPreference] = React.useState(read);
|
|
479
|
+
|
|
480
|
+
React.useEffect(() => {
|
|
481
|
+
if (!theme || typeof theme.getTheme !== 'function' || typeof ctx.on !== 'function') return undefined;
|
|
482
|
+
let off = null;
|
|
483
|
+
try {
|
|
484
|
+
off = ctx.on('theme/change', () => setPreference(read()));
|
|
485
|
+
} catch (_error) {
|
|
486
|
+
off = null;
|
|
487
|
+
}
|
|
488
|
+
return () => { if (typeof off === 'function') off(); };
|
|
489
|
+
}, []);
|
|
490
|
+
|
|
491
|
+
return h('div', {
|
|
492
|
+
style: { display: 'inline-flex', alignItems: 'center', gap: 7, flex: '0 0 auto' },
|
|
493
|
+
title: '主题',
|
|
494
|
+
},
|
|
495
|
+
THEME_SWATCHES.map((swatch) => {
|
|
496
|
+
const active = preference === swatch.id;
|
|
497
|
+
return h('button', {
|
|
498
|
+
key: swatch.id,
|
|
499
|
+
type: 'button',
|
|
500
|
+
title: swatch.label,
|
|
501
|
+
'aria-label': swatch.label,
|
|
502
|
+
'aria-pressed': active ? 'true' : 'false',
|
|
503
|
+
onClick: () => {
|
|
504
|
+
if (!theme || typeof theme.setTheme !== 'function') return;
|
|
505
|
+
try { theme.setTheme(swatch.id); } catch (error) { console.warn('[workbench] setTheme failed', error); }
|
|
506
|
+
},
|
|
507
|
+
style: {
|
|
508
|
+
width: 15, height: 15, padding: 0, borderRadius: '50%', flex: '0 0 auto',
|
|
509
|
+
background: swatch.color,
|
|
510
|
+
border: '1px solid ' + (active ? 'var(--dsw-alias-brand-primary)' : 'var(--dsw-alias-border-l2)'),
|
|
511
|
+
boxShadow: active
|
|
512
|
+
? '0 0 0 2px var(--dsw-alias-bg-base), 0 0 0 3px var(--dsw-alias-brand-primary)'
|
|
513
|
+
: 'none',
|
|
514
|
+
cursor: 'pointer',
|
|
515
|
+
transition: 'box-shadow .12s, border-color .12s',
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
}),
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
return ThemeSwitcher;
|
|
522
|
+
}
|
|
523
|
+
|
|
437
524
|
function createTopBar(ctx, balance) {
|
|
525
|
+
const ThemeSwitcher = createThemeSwitcher(ctx);
|
|
526
|
+
|
|
438
527
|
function BalanceChip() {
|
|
439
528
|
const snap = React.useSyncExternalStore(balance.subscribe, balance.getSnapshot);
|
|
440
529
|
const [hover, setHover] = React.useState(false);
|
|
@@ -637,7 +726,7 @@ window.__ModuleLoader__.load({
|
|
|
637
726
|
iconBtn('plugins', '插件', IconPlugins),
|
|
638
727
|
iconBtn('schedules', '自动化任务', IconClock),
|
|
639
728
|
),
|
|
640
|
-
|
|
729
|
+
h('div', { style: { flex: '0 0 auto', marginRight: 150 } }, h(ThemeSwitcher)),
|
|
641
730
|
),
|
|
642
731
|
h('div', { style: { height: 45, display: 'flex', alignItems: 'center', gap: 8, padding: '0 14px', borderTop: '1px solid var(--dsw-alias-border-l1)' } },
|
|
643
732
|
h('div', { ref: tabsRef, style: { position: 'relative', display: 'flex', alignItems: 'center', gap: 4, flex: 1, overflowX: 'auto', overflowY: 'hidden' } },
|
|
@@ -1240,6 +1329,16 @@ div[data-row-key^="session:"]:has(svg[data-state="ongoing"]) svg[data-state="ong
|
|
|
1240
1329
|
layoutService = ctx.get('layout') || null;
|
|
1241
1330
|
layoutGetter = () => ctx.get('layout') || null;
|
|
1242
1331
|
|
|
1332
|
+
// Extra palette on top of the built-in light/dark pair.
|
|
1333
|
+
try {
|
|
1334
|
+
const themeService = typeof ctx.get === 'function' ? ctx.get('theme') : null;
|
|
1335
|
+
if (themeService && typeof themeService.register === 'function') {
|
|
1336
|
+
ctx.effect(() => themeService.register(PAPER_THEME), 'workbench: paper theme');
|
|
1337
|
+
}
|
|
1338
|
+
} catch (error) {
|
|
1339
|
+
console.warn('[workbench] paper theme registration failed', error);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1243
1342
|
// The shell's own overview lives above the tab row: it is reachable from
|
|
1244
1343
|
// the top-bar "工作台" icon, so it registers a page without a tab.
|
|
1245
1344
|
ctx.effect(() => api.registerView({
|
package/package.json
CHANGED