@rooode/dsh-plugin-preview 0.1.17 → 0.1.19
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/lib/client.js +156 -65
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
const STORAGE_KEY_TREE_OPEN = 'dsh:preview:tree:open:v1';
|
|
28
28
|
const STORAGE_KEY_TREE_WIDTH = 'dsh:preview:tree:width:v1';
|
|
29
29
|
const STORAGE_KEY_MANUAL_WS = 'dsh:preview:manual_workspace:v1';
|
|
30
|
-
const DEFAULT_PANEL_WIDTH =
|
|
30
|
+
const DEFAULT_PANEL_WIDTH = 700;
|
|
31
31
|
const MIN_PANEL_WIDTH = 380;
|
|
32
|
-
const DEFAULT_TREE_WIDTH =
|
|
33
|
-
const MIN_TREE_WIDTH =
|
|
32
|
+
const DEFAULT_TREE_WIDTH = 220;
|
|
33
|
+
const MIN_TREE_WIDTH = 170;
|
|
34
34
|
const MAX_TREE_WIDTH = 450;
|
|
35
35
|
const SUPPORTED_EXTENSIONS = new Set([
|
|
36
36
|
'.md', '.markdown', '.mdown', '.mkdn', '.mdwn',
|
|
@@ -394,75 +394,108 @@
|
|
|
394
394
|
return result;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
function
|
|
398
|
-
// Priority 1: User manual override selection (if explicitly chosen by user)
|
|
397
|
+
function resolveActiveWorkspace(ctx) {
|
|
399
398
|
if (globalManualWorkspace && typeof globalManualWorkspace === 'string' && globalManualWorkspace.trim()) {
|
|
400
|
-
|
|
399
|
+
const p = globalManualWorkspace.trim().replace(/[\\/]+$/, '');
|
|
400
|
+
return { path: p, id: 'manual', title: getFileName(p) || p };
|
|
401
401
|
}
|
|
402
|
-
|
|
403
|
-
// Priority 2: Derive active workspace from clientCtx (workspaces + sessions)
|
|
404
|
-
if (clientCtx) {
|
|
402
|
+
if (ctx) {
|
|
405
403
|
try {
|
|
406
|
-
const sSnap =
|
|
407
|
-
const wSnap =
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
//
|
|
411
|
-
if (
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
404
|
+
const sSnap = ctx.sessions?.list?.getSnapshot?.();
|
|
405
|
+
const wSnap = ctx.workspaces?.list?.getSnapshot?.();
|
|
406
|
+
const curSessionId = sSnap?.current;
|
|
407
|
+
|
|
408
|
+
// 1. Session cwd or workspaceId
|
|
409
|
+
if (curSessionId && sSnap?.byId?.[curSessionId]) {
|
|
410
|
+
const sess = sSnap.byId[curSessionId];
|
|
411
|
+
let wsPath = sess.cwd;
|
|
412
|
+
let wsId = sess.workspaceId;
|
|
413
|
+
let wsTitle = sess.title;
|
|
414
|
+
|
|
415
|
+
if (sess.workspaceId && wSnap?.items) {
|
|
416
|
+
const match = wSnap.items.find(item => item.workspaceId === sess.workspaceId);
|
|
417
|
+
if (match) {
|
|
418
|
+
if (match.path) wsPath = match.path;
|
|
419
|
+
if (match.title) wsTitle = match.title;
|
|
420
|
+
wsId = match.workspaceId;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (wsPath && typeof wsPath === 'string' && wsPath.trim()) {
|
|
424
|
+
const clean = wsPath.trim().replace(/[\\/]+$/, '');
|
|
425
|
+
return {
|
|
426
|
+
path: clean,
|
|
427
|
+
id: wsId || clean,
|
|
428
|
+
title: wsTitle || getFileName(clean) || '工作区',
|
|
429
|
+
};
|
|
415
430
|
}
|
|
416
431
|
}
|
|
417
432
|
|
|
418
|
-
//
|
|
419
|
-
if (
|
|
420
|
-
const
|
|
421
|
-
if (
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
}
|
|
433
|
+
// 2. Find in wSnap.items by sessionIds
|
|
434
|
+
if (curSessionId && wSnap?.items) {
|
|
435
|
+
const match = wSnap.items.find(item => Array.isArray(item.sessionIds) && item.sessionIds.includes(curSessionId));
|
|
436
|
+
if (match?.path) {
|
|
437
|
+
const clean = match.path.trim().replace(/[\\/]+$/, '');
|
|
438
|
+
return {
|
|
439
|
+
path: clean,
|
|
440
|
+
id: match.workspaceId || clean,
|
|
441
|
+
title: match.title || getFileName(clean) || '工作区',
|
|
442
|
+
};
|
|
429
443
|
}
|
|
430
444
|
}
|
|
431
445
|
|
|
432
|
-
//
|
|
433
|
-
if (wSnap
|
|
446
|
+
// 3. Recent workspace
|
|
447
|
+
if (wSnap?.recentWorkspaceId && wSnap?.items) {
|
|
434
448
|
const recent = wSnap.items.find(item => item.workspaceId === wSnap.recentWorkspaceId);
|
|
435
|
-
if (recent
|
|
436
|
-
|
|
449
|
+
if (recent?.path) {
|
|
450
|
+
const clean = recent.path.trim().replace(/[\\/]+$/, '');
|
|
451
|
+
return {
|
|
452
|
+
path: clean,
|
|
453
|
+
id: recent.workspaceId || clean,
|
|
454
|
+
title: recent.title || getFileName(clean) || '工作区',
|
|
455
|
+
};
|
|
437
456
|
}
|
|
438
457
|
}
|
|
439
458
|
|
|
440
|
-
//
|
|
441
|
-
if (wSnap
|
|
459
|
+
// 4. First workspace item
|
|
460
|
+
if (wSnap?.items && wSnap.items.length > 0) {
|
|
442
461
|
const first = wSnap.items[0];
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
445
|
-
|
|
462
|
+
const p = first.path || first.directory || first.cwd;
|
|
463
|
+
if (p && typeof p === 'string' && p.trim()) {
|
|
464
|
+
const clean = p.trim().replace(/[\\/]+$/, '');
|
|
465
|
+
return {
|
|
466
|
+
path: clean,
|
|
467
|
+
id: first.workspaceId || clean,
|
|
468
|
+
title: first.title || getFileName(clean) || '工作区',
|
|
469
|
+
};
|
|
446
470
|
}
|
|
447
471
|
}
|
|
448
472
|
} catch (e) {
|
|
449
|
-
console.warn('[Preview]
|
|
473
|
+
console.warn('[Preview] resolveActiveWorkspace error:', e);
|
|
450
474
|
}
|
|
451
475
|
}
|
|
452
476
|
|
|
453
|
-
// Priority 3: URL hash or search parameter
|
|
454
477
|
if (typeof location !== 'undefined') {
|
|
455
478
|
if (location.hash) {
|
|
456
479
|
const m = location.hash.match(/workspace=([^&]+)/);
|
|
457
|
-
if (m)
|
|
480
|
+
if (m) {
|
|
481
|
+
const p = decodeURIComponent(m[1]).replace(/[\\/]+$/, '');
|
|
482
|
+
return { path: p, id: p, title: getFileName(p) || p };
|
|
483
|
+
}
|
|
458
484
|
}
|
|
459
485
|
if (location.search) {
|
|
460
486
|
const m = location.search.match(/workspace=([^&]+)/);
|
|
461
|
-
if (m)
|
|
487
|
+
if (m) {
|
|
488
|
+
const p = decodeURIComponent(m[1]).replace(/[\\/]+$/, '');
|
|
489
|
+
return { path: p, id: p, title: getFileName(p) || p };
|
|
490
|
+
}
|
|
462
491
|
}
|
|
463
492
|
}
|
|
464
493
|
|
|
465
|
-
return '';
|
|
494
|
+
return { path: '.', id: 'default', title: '工作区' };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function getCurrentWorkspaceRoot() {
|
|
498
|
+
return resolveActiveWorkspace(clientCtx).path || '.';
|
|
466
499
|
}
|
|
467
500
|
|
|
468
501
|
function resolveAbsoluteFilePath(targetPath) {
|
|
@@ -1813,11 +1846,11 @@
|
|
|
1813
1846
|
}
|
|
1814
1847
|
}, [searchQuery, treeData]);
|
|
1815
1848
|
|
|
1816
|
-
// Listen to external workspace switch events (e.g. from Git plugin)
|
|
1849
|
+
// Listen to external workspace switch events (e.g. from DSH sidebar or Git plugin)
|
|
1817
1850
|
useEffect(() => {
|
|
1818
1851
|
const handleWsSwitch = (e) => {
|
|
1819
|
-
if (e.detail?.path
|
|
1820
|
-
|
|
1852
|
+
if (e.detail?.path) {
|
|
1853
|
+
setCurrentWs(e.detail.path);
|
|
1821
1854
|
}
|
|
1822
1855
|
};
|
|
1823
1856
|
window.addEventListener('dsh:workspace:switch', handleWsSwitch);
|
|
@@ -3404,13 +3437,6 @@
|
|
|
3404
3437
|
h('div', { className: 'dsh-preview-toolbar' },
|
|
3405
3438
|
// Left: View mode toggles
|
|
3406
3439
|
h('div', { className: 'dsh-preview-toolbar-left' },
|
|
3407
|
-
h('button', {
|
|
3408
|
-
type: 'button',
|
|
3409
|
-
className: `dsh-preview-tool-btn ${isTreeOpen ? 'active' : ''}`,
|
|
3410
|
-
onClick: onToggleTree,
|
|
3411
|
-
title: isTreeOpen ? '隐藏工作区目录树 (Ctrl/Cmd+B)' : '展开工作区目录树 (Ctrl/Cmd+B)',
|
|
3412
|
-
}, '🗂️ 目录树'),
|
|
3413
|
-
|
|
3414
3440
|
// Adaptive View Mode buttons based on File Category
|
|
3415
3441
|
category === 'markdown' ? (
|
|
3416
3442
|
h('div', { className: 'dsh-preview-mode-group' },
|
|
@@ -4304,19 +4330,28 @@
|
|
|
4304
4330
|
}
|
|
4305
4331
|
|
|
4306
4332
|
/* Side-by-Side Right Sidebar Layout Integration */
|
|
4307
|
-
body.dsh-preview-sidebar-active div[class*="
|
|
4308
|
-
|
|
4309
|
-
max-width: calc(100% - var(--dsh-preview-width,
|
|
4333
|
+
body.dsh-preview-sidebar-active div[class*="frame"] {
|
|
4334
|
+
width: calc(100% - var(--dsh-preview-width, 700px)) !important;
|
|
4335
|
+
max-width: calc(100% - var(--dsh-preview-width, 700px)) !important;
|
|
4310
4336
|
box-sizing: border-box !important;
|
|
4311
|
-
transition:
|
|
4337
|
+
transition: width 0.18s cubic-bezier(0.16, 1, 0.3, 1), max-width 0.18s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
|
4312
4338
|
}
|
|
4313
|
-
body.dsh-preview-sidebar-active.dsh-preview-maximized div[class*="
|
|
4339
|
+
body.dsh-preview-sidebar-active.dsh-preview-maximized div[class*="frame"] {
|
|
4314
4340
|
display: none !important;
|
|
4315
4341
|
}
|
|
4316
4342
|
body.dsh-preview-sidebar-active.dsh-preview-maximized .dsh-preview-drawer-container {
|
|
4317
4343
|
width: 100vw !important;
|
|
4318
4344
|
}
|
|
4319
4345
|
|
|
4346
|
+
/* Shift Right Activity Rail to dock on the preview sidebar left border when open */
|
|
4347
|
+
body.dsh-preview-sidebar-active .dsh-right-activity-rail {
|
|
4348
|
+
right: var(--dsh-preview-width, 700px) !important;
|
|
4349
|
+
transition: right 0.18s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
|
4350
|
+
}
|
|
4351
|
+
body.dsh-preview-sidebar-active.dsh-preview-maximized .dsh-right-activity-rail {
|
|
4352
|
+
display: none !important;
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4320
4355
|
/* Workspace Switcher Header & Popover */
|
|
4321
4356
|
.dsh-tree-sidebar-title.dsh-tree-title-clickable {
|
|
4322
4357
|
cursor: pointer;
|
|
@@ -4713,15 +4748,18 @@
|
|
|
4713
4748
|
display: flex;
|
|
4714
4749
|
align-items: center;
|
|
4715
4750
|
justify-content: space-between;
|
|
4716
|
-
padding:
|
|
4751
|
+
padding: 4px 8px;
|
|
4717
4752
|
height: 38px;
|
|
4718
4753
|
min-height: 38px;
|
|
4719
4754
|
flex-shrink: 0;
|
|
4720
4755
|
background: var(--dsw-alias-bg-layer-2, #f8fafc);
|
|
4721
4756
|
border-bottom: 1px solid var(--dsw-alias-border-l2, #e2e8f0);
|
|
4722
|
-
gap:
|
|
4757
|
+
gap: 6px;
|
|
4723
4758
|
box-sizing: border-box;
|
|
4759
|
+
overflow-x: auto;
|
|
4760
|
+
scrollbar-width: none;
|
|
4724
4761
|
}
|
|
4762
|
+
.dsh-preview-toolbar::-webkit-scrollbar { display: none; }
|
|
4725
4763
|
body[data-ds-dark-theme] .dsh-preview-toolbar {
|
|
4726
4764
|
background: var(--dsw-alias-bg-layer-2, #161a24);
|
|
4727
4765
|
border-bottom-color: var(--dsw-alias-border-l2, #252d3d);
|
|
@@ -4730,7 +4768,7 @@
|
|
|
4730
4768
|
.dsh-preview-toolbar-right {
|
|
4731
4769
|
display: flex;
|
|
4732
4770
|
align-items: center;
|
|
4733
|
-
gap:
|
|
4771
|
+
gap: 4px;
|
|
4734
4772
|
flex-shrink: 0;
|
|
4735
4773
|
white-space: nowrap;
|
|
4736
4774
|
}
|
|
@@ -4752,7 +4790,7 @@
|
|
|
4752
4790
|
border: none;
|
|
4753
4791
|
color: var(--dsw-alias-label-secondary, #64748b);
|
|
4754
4792
|
font-size: 11px;
|
|
4755
|
-
padding:
|
|
4793
|
+
padding: 3px 7px;
|
|
4756
4794
|
border-radius: 4px;
|
|
4757
4795
|
cursor: pointer;
|
|
4758
4796
|
transition: all 0.15s;
|
|
@@ -4778,13 +4816,13 @@
|
|
|
4778
4816
|
border: 1px solid var(--dsw-alias-border-l2, #cbd5e1);
|
|
4779
4817
|
color: var(--dsw-alias-label-primary, #334155);
|
|
4780
4818
|
font-size: 11px;
|
|
4781
|
-
padding:
|
|
4782
|
-
border-radius:
|
|
4819
|
+
padding: 3px 7px;
|
|
4820
|
+
border-radius: 4px;
|
|
4783
4821
|
cursor: pointer;
|
|
4784
4822
|
transition: all 0.15s;
|
|
4785
4823
|
display: flex;
|
|
4786
4824
|
align-items: center;
|
|
4787
|
-
gap:
|
|
4825
|
+
gap: 3px;
|
|
4788
4826
|
white-space: nowrap;
|
|
4789
4827
|
flex-shrink: 0;
|
|
4790
4828
|
}
|
|
@@ -6399,6 +6437,59 @@
|
|
|
6399
6437
|
injectStyles();
|
|
6400
6438
|
setupFileInterceptors(ctx);
|
|
6401
6439
|
|
|
6440
|
+
// Subscribe to DSH Session & Workspace store changes (Left Sidebar updates)
|
|
6441
|
+
let lastTrackedSessionId = null;
|
|
6442
|
+
let lastTrackedWsPath = getCurrentWorkspaceRoot();
|
|
6443
|
+
|
|
6444
|
+
function handleDshSessionOrWorkspaceChange() {
|
|
6445
|
+
try {
|
|
6446
|
+
const sSnap = ctx.sessions?.list?.getSnapshot?.();
|
|
6447
|
+
const curSessionId = sSnap?.current;
|
|
6448
|
+
|
|
6449
|
+
// When user clicks a session on the left sidebar:
|
|
6450
|
+
if (curSessionId && curSessionId !== lastTrackedSessionId) {
|
|
6451
|
+
lastTrackedSessionId = curSessionId;
|
|
6452
|
+
// Clear manual override when user actively selects a session in the left sidebar
|
|
6453
|
+
if (globalManualWorkspace) {
|
|
6454
|
+
globalManualWorkspace = null;
|
|
6455
|
+
try { localStorage.removeItem(STORAGE_KEY_MANUAL_WS); } catch (e) {}
|
|
6456
|
+
}
|
|
6457
|
+
}
|
|
6458
|
+
|
|
6459
|
+
const activeWsInfo = resolveActiveWorkspace(ctx);
|
|
6460
|
+
const activeWsPath = activeWsInfo.path;
|
|
6461
|
+
|
|
6462
|
+
if (activeWsPath && activeWsPath !== lastTrackedWsPath) {
|
|
6463
|
+
lastTrackedWsPath = activeWsPath;
|
|
6464
|
+
syncCurrentWorkspaceTabs(activeWsPath);
|
|
6465
|
+
notifyStateChange();
|
|
6466
|
+
if (typeof window !== 'undefined') {
|
|
6467
|
+
window.dispatchEvent(new CustomEvent('dsh:workspace:switch', {
|
|
6468
|
+
detail: { path: activeWsPath, id: activeWsInfo.id, title: activeWsInfo.title }
|
|
6469
|
+
}));
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
6472
|
+
} catch (e) {
|
|
6473
|
+
console.warn('[Preview] Session/Workspace change handler error:', e);
|
|
6474
|
+
}
|
|
6475
|
+
}
|
|
6476
|
+
|
|
6477
|
+
if (ctx.sessions?.list?.subscribe) {
|
|
6478
|
+
ctx.sessions.list.subscribe(handleDshSessionOrWorkspaceChange);
|
|
6479
|
+
}
|
|
6480
|
+
if (ctx.workspaces?.list?.subscribe) {
|
|
6481
|
+
ctx.workspaces.list.subscribe(handleDshSessionOrWorkspaceChange);
|
|
6482
|
+
}
|
|
6483
|
+
|
|
6484
|
+
// Safety polling every 800ms for route or state changes
|
|
6485
|
+
setInterval(handleDshSessionOrWorkspaceChange, 800);
|
|
6486
|
+
|
|
6487
|
+
// Listen to popstate / hashchange
|
|
6488
|
+
if (typeof window !== 'undefined') {
|
|
6489
|
+
window.addEventListener('popstate', handleDshSessionOrWorkspaceChange);
|
|
6490
|
+
window.addEventListener('hashchange', handleDshSessionOrWorkspaceChange);
|
|
6491
|
+
}
|
|
6492
|
+
|
|
6402
6493
|
console.log('[Preview] Markdown Preview Client Plugin loaded successfully!');
|
|
6403
6494
|
|
|
6404
6495
|
// 1. Mount Unified Right Activity Rail Host into shell.overlay
|
package/lib/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export class PreviewService extends Service {
|
|
|
29
29
|
handler: this.handleHttpRequest.bind(this),
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
|
-
console.log('[PreviewService] Registered /api/preview route on webServer (v0.1.
|
|
32
|
+
console.log('[PreviewService] Registered /api/preview route on webServer (v0.1.19)');
|
|
33
33
|
} else {
|
|
34
34
|
console.warn('[PreviewService] webServer not available yet in ctx');
|
|
35
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rooode/dsh-plugin-preview",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "DeepSeek Harness Markdown 文档与工作空间文件浏览器右侧预览插件 (支持工作区文件树、文件夹创建与文件移动、JSON 交互结构树/格式化、Java/C++/Python/JS/TS/YAML/Go/Rust 多语言语法高亮与符号大纲、自动换行与多标签 FileTabs)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|