@rooode/dsh-plugin-preview 0.1.6 → 0.1.8
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/README.md +120 -64
- package/lib/client.js +317 -43
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,103 +12,159 @@
|
|
|
12
12
|
## 🌟 核心特性 (Features)
|
|
13
13
|
|
|
14
14
|
1. **📁 工作空间目录树浏览器 (Workspace Tree Explorer)**:
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
15
|
+
- 树状层级展开/折叠项目所有目录与文件,支持文件大小与修改时间展示;
|
|
16
|
+
- 文件名即时过滤搜索,自动展开命中路径并折叠无关项;
|
|
17
|
+
- 快捷折叠全部目录、一键刷新磁盘目录结构;
|
|
18
18
|
- 目录树宽度支持鼠标自由拖拽调节。
|
|
19
|
-
|
|
20
19
|
2. **💡 对话区智能交互与自动收起**:
|
|
21
|
-
-
|
|
20
|
+
- 当预览抽屉处于打开状态时,点击左侧会话列表或对话输入框,抽屉自动平滑收起/隐藏,保证专注对话输入;
|
|
22
21
|
- 收起后右下角保留胶囊浮窗,一键随时恢复展开。
|
|
23
|
-
|
|
24
22
|
3. **🌳 交互式 JSON 结构树检查器 (JSON Tree Inspector)**:
|
|
25
|
-
- `.json` 文件默认以交互结构树呈现,支持 `Object{N}` 与 `Array[N]`
|
|
26
|
-
-
|
|
27
|
-
- 单击快捷复制指定字段路径(如 `scripts.build
|
|
23
|
+
- `.json` 文件默认以交互结构树呈现,支持 `Object{N}` 与 `Array[N]` 多层级折叠展开;
|
|
24
|
+
- 属性名与属性值即时过滤搜索;
|
|
25
|
+
- 单击快捷复制指定字段路径(如 `scripts.build`)或字段值;
|
|
28
26
|
- 提供 `⚡ 格式化 (2空格对齐)` 与 `🗜️ 压缩 (单行)` 快捷操作,并支持随时切换至高亮代码模式。
|
|
29
|
-
|
|
30
27
|
4. **🌐 多语言语法高亮与符号大纲 (Polyglot Highlighting & Symbol TOC)**:
|
|
31
|
-
- 采用单趟扫描分词器(Single-Pass Tokenizer),杜绝 HTML
|
|
28
|
+
- 采用单趟扫描分词器(Single-Pass Tokenizer),杜绝 HTML 嵌套污染;
|
|
32
29
|
- **全面支持主流语言**:
|
|
33
|
-
- ☕ **Java**:注解(`@Service`, `@Autowired`, `@Override`)、泛型、集合类、文本块、Package/Class/Method
|
|
34
|
-
- ⚙️ **C / C++**:预处理指令(`#include <...>`)、命名空间、模板、标准库类型、智能指针、Namespace/Class/Struct/Function
|
|
35
|
-
- 🐍 **Python**:装饰器(`@dataclass`, `@property`)、多行 Docstrings、异步协程(`async def`)、类型标注、Class/Def
|
|
36
|
-
- ⚡ **JavaScript / TypeScript**:ES 模块、JSX 标签、接口/枚举、模板字符串、箭头函数、Class/Fn/Type/Export
|
|
37
|
-
- 🦀 **Rust** / 🌐 **Go** / ⌨️ **Shell** / 🗄️ **SQL** / ⚙️ **YAML** / 📝 **Markdown**
|
|
38
|
-
-
|
|
30
|
+
- ☕ **Java**:注解(`@Service`, `@Autowired`, `@Override`)、泛型、集合类、文本块、Package/Class/Method 符号大纲;
|
|
31
|
+
- ⚙️ **C / C++**:预处理指令(`#include <...>`)、命名空间、模板、标准库类型、智能指针、Namespace/Class/Struct/Function 符号大纲;
|
|
32
|
+
- 🐍 **Python**:装饰器(`@dataclass`, `@property`)、多行 Docstrings、异步协程(`async def`)、类型标注、Class/Def 符号大纲;
|
|
33
|
+
- ⚡ **JavaScript / TypeScript**:ES 模块、JSX 标签、接口/枚举、模板字符串、箭头函数、Class/Fn/Type/Export 符号大纲;
|
|
34
|
+
- 🦀 **Rust** / 🌐 **Go** / ⌨️ **Shell** / 🗄️ **SQL** / ⚙️ **YAML** / 📝 **Markdown** 等;
|
|
35
|
+
- **大纲点击平滑跳转**:点击大纲侧栏任一项,代码区域自动平滑滚动定位至目标代码行,并在行号及对应行触发高亮闪烁反馈;
|
|
39
36
|
- **代码排版优化**:默认水平滚动,点击 `↩️ 换行` 可在单行与自动折行(`overflow-wrap: break-word`)间无缝切换,杜绝单词被撕裂打碎。
|
|
40
|
-
|
|
41
37
|
5. **📖 全功能 GFM Markdown 渲染引擎**:
|
|
42
|
-
- **三模视图切换**:📖 渲染预览 (Preview) / 📝 源码模式 (Source) / 🌓 分栏对比 (Split)
|
|
43
|
-
- **GitHub Alerts 提示框**:完整支持 `> [!NOTE]`、`> [!TIP]`、`> [!IMPORTANT]`、`> [!WARNING]`、`> [!CAUTION]`
|
|
44
|
-
- **LaTeX 数学公式**:支持 `$inline$` 与 `$$block$$`
|
|
45
|
-
-
|
|
38
|
+
- **三模视图切换**:📖 渲染预览 (Preview) / 📝 源码模式 (Source) / 🌓 分栏对比 (Split);
|
|
39
|
+
- **GitHub Alerts 提示框**:完整支持 `> [!NOTE]`、`> [!TIP]`、`> [!IMPORTANT]`、`> [!WARNING]`、`> [!CAUTION]` 彩色卡片渲染;
|
|
40
|
+
- **LaTeX 数学公式**:支持 `$inline$` 与 `$$block$$` 数学公式排版;
|
|
41
|
+
- **数据表格与任务清单**:斑马纹表格自适应排版、交互式勾选框列表;
|
|
46
42
|
- **目录大纲导航 (TOC)**:自动提取 H1~H6 标题生成侧栏目录,点击平滑滚动跳转。
|
|
47
|
-
|
|
48
43
|
6. **📑 右侧多标签页 (FileTabs)**:
|
|
49
|
-
-
|
|
50
|
-
-
|
|
44
|
+
- 支持同时打开多个文档与代码文件,标签栏展示对应语言彩色图标、文件名与独立关闭按钮;
|
|
45
|
+
- 支持快速切换激活标签、一键全部关闭;
|
|
51
46
|
- 左侧边框支持鼠标自由拖拽调节宽度(支持 380px 至 90vw 自由调整)。
|
|
52
47
|
|
|
53
48
|
---
|
|
54
49
|
|
|
55
50
|
## 📦 快速安装 (Installation)
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
在终端中执行以下命令,将插件一键安装到 DSH 的 `web` profile 中:
|
|
53
|
+
|
|
54
|
+
### 方式 1:标准 `npx` 安装(推荐,无需全局安装)
|
|
58
55
|
```bash
|
|
59
|
-
# 1.
|
|
56
|
+
# 1. 一键从 npm 下载并安装插件
|
|
60
57
|
npx @deepseek-ai/dsh plugin --profile web add @rooode/dsh-plugin-preview
|
|
61
58
|
|
|
62
|
-
# 2. 启动 DSH Web
|
|
59
|
+
# 2. 启动 DSH Web 界面
|
|
63
60
|
npx @deepseek-ai/dsh web
|
|
64
61
|
```
|
|
65
62
|
|
|
66
|
-
### 方式 2
|
|
67
|
-
|
|
63
|
+
### 方式 2:全局 `dsh` CLI 安装
|
|
64
|
+
如果您已全局安装了 `npm install -g @deepseek-ai/dsh`:
|
|
68
65
|
```bash
|
|
69
|
-
#
|
|
70
|
-
|
|
66
|
+
# 1. 安装插件
|
|
67
|
+
dsh plugin --profile web add @rooode/dsh-plugin-preview
|
|
71
68
|
|
|
72
|
-
# 启动
|
|
73
|
-
|
|
69
|
+
# 2. 启动
|
|
70
|
+
dsh web
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 方式 3:离线 Tarball 安装(适合内网/断网环境)
|
|
74
|
+
```bash
|
|
75
|
+
# 下载或拷贝 rooode-dsh-plugin-preview-*.tgz 后执行:
|
|
76
|
+
npx @deepseek-ai/dsh plugin --profile web add ./rooode-dsh-plugin-preview-0.1.7.tgz
|
|
74
77
|
```
|
|
75
78
|
|
|
76
79
|
---
|
|
77
80
|
|
|
78
81
|
## ⚙️ 配置项说明 (Configuration)
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
可在 `cordis.patch.yml` 中自定义配置以下参数:
|
|
81
84
|
|
|
82
85
|
```yaml
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
86
|
+
- insert:
|
|
87
|
+
- id: ui-preview
|
|
88
|
+
name: '@rooode/dsh-plugin-preview'
|
|
89
|
+
config:
|
|
90
|
+
# 自动拦截并在右侧预览的文件后缀列表
|
|
91
|
+
autoPreviewExtensions:
|
|
92
|
+
- .md
|
|
93
|
+
- .markdown
|
|
94
|
+
- .txt
|
|
95
|
+
- .json
|
|
96
|
+
- .yaml
|
|
97
|
+
- .yml
|
|
98
|
+
- .js
|
|
99
|
+
- .ts
|
|
100
|
+
- .java
|
|
101
|
+
- .cpp
|
|
102
|
+
- .c
|
|
103
|
+
- .h
|
|
104
|
+
- .hpp
|
|
105
|
+
- .py
|
|
106
|
+
- .go
|
|
107
|
+
- .rs
|
|
108
|
+
- .sh
|
|
109
|
+
- .sql
|
|
110
|
+
# 最大允许读取的文件大小 (MB)
|
|
111
|
+
maxFileSizeMb: 10
|
|
112
|
+
# 默认打开视图: 'preview' (预览) | 'source' (源码) | 'split' (分栏)
|
|
113
|
+
defaultViewMode: 'preview'
|
|
114
|
+
# 右侧预览面板默认初始宽度 (px)
|
|
115
|
+
defaultPanelWidth: 560
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 配置参数列表
|
|
119
|
+
|
|
120
|
+
| 配置项 | 类型 | 默认值 | 说明 |
|
|
121
|
+
| :--- | :--- | :--- | :--- |
|
|
122
|
+
| `autoPreviewExtensions` | `string[]` | `['.md', '.markdown', '.txt', ...]` | 点击文档链接时自动在右侧面板滑出预览的文件扩展名白名单列表 |
|
|
123
|
+
| `maxFileSizeMb` | `number` | `10` | 最大允许读取和预览的文件体积上限(MB) |
|
|
124
|
+
| `defaultViewMode` | `'preview' \| 'source' \| 'split'` | `'preview'` | 默认打开视图模式(渲染预览 / 源码模式 / 双栏分栏对比) |
|
|
125
|
+
| `defaultPanelWidth` | `number` | `560` | 右侧预览面板默认初始化宽度(px) |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 📁 项目结构 (Directory Structure)
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
dsh-plugin-preview/
|
|
133
|
+
├── package.json # 插件元信息、dsh.bundle/client 声明与 npm scripts
|
|
134
|
+
├── cordis.patch.yml # DSH 组合包 patch 描述文件
|
|
135
|
+
├── tsconfig.json # TypeScript 严格编译与类型输出配置
|
|
136
|
+
├── README.md # 插件技术说明与安装文档
|
|
137
|
+
├── src/
|
|
138
|
+
│ ├── types.ts # 文件节点、目录树、视图模式与配置类型定义
|
|
139
|
+
│ ├── service.ts # Cordis 服务 PreviewService (Node 端文件扫描与读取 REST API)
|
|
140
|
+
│ ├── index.ts # Node 端入口:服务初始化、WebServer 注入与 Schema 校验
|
|
141
|
+
│ └── client.js # 前端 React 多标签抽屉、目录树、GFM 渲染与多语言高亮引擎
|
|
142
|
+
├── lib/
|
|
143
|
+
│ ├── index.js # Node 端 ESM 产物
|
|
144
|
+
│ ├── index.d.ts # 类型定义声明
|
|
145
|
+
│ └── client.js # 前端独立分发 Bundle
|
|
146
|
+
└── scripts/
|
|
147
|
+
└── build.js # 编译与 Profile 自动分发同步脚本
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 🛠️ 本地开发与二次构建 (Development)
|
|
153
|
+
|
|
154
|
+
在本项目根目录下执行:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# 1. 编译并将最新产物同步至本地 DSH 运行环境
|
|
158
|
+
npm run build
|
|
159
|
+
|
|
160
|
+
# 2. 监听文件修改并自动重新编译分发
|
|
161
|
+
npm run dev
|
|
162
|
+
|
|
163
|
+
# 3. 执行 TypeScript 类型检查
|
|
164
|
+
npm run typecheck
|
|
165
|
+
|
|
166
|
+
# 4. 生成离线分发 tarball 压缩包
|
|
167
|
+
npm run package
|
|
112
168
|
```
|
|
113
169
|
|
|
114
170
|
---
|
package/lib/client.js
CHANGED
|
@@ -2586,9 +2586,8 @@
|
|
|
2586
2586
|
return;
|
|
2587
2587
|
}
|
|
2588
2588
|
|
|
2589
|
-
// 4. If clicking on the
|
|
2590
|
-
|
|
2591
|
-
if (floatPill && (floatPill === target || floatPill.contains(target))) {
|
|
2589
|
+
// 4. If clicking on the right activity rail, preview drawer or git drawer, do not close
|
|
2590
|
+
if (target.closest && target.closest('.dsh-right-activity-rail, .dsh-rail-tab-item, .dsh-preview-drawer-container, .dsh-git-drawer-container')) {
|
|
2592
2591
|
return;
|
|
2593
2592
|
}
|
|
2594
2593
|
|
|
@@ -2616,6 +2615,17 @@
|
|
|
2616
2615
|
};
|
|
2617
2616
|
}, [isOpen, isDragging, isTreeDragging]);
|
|
2618
2617
|
|
|
2618
|
+
// Mutual exclusion with other tool windows (e.g. Git modal)
|
|
2619
|
+
useEffect(() => {
|
|
2620
|
+
const handleToolWindowOpen = (e) => {
|
|
2621
|
+
if (e.detail?.id && e.detail.id !== 'preview') {
|
|
2622
|
+
setPanelOpen(false);
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2625
|
+
window.addEventListener('dsh:tool-window:open', handleToolWindowOpen);
|
|
2626
|
+
return () => window.removeEventListener('dsh:tool-window:open', handleToolWindowOpen);
|
|
2627
|
+
}, []);
|
|
2628
|
+
|
|
2619
2629
|
// Hotkey: Esc closes preview, Ctrl/Cmd+B toggles file tree
|
|
2620
2630
|
useEffect(() => {
|
|
2621
2631
|
const onKeyDown = (e) => {
|
|
@@ -2631,24 +2641,42 @@
|
|
|
2631
2641
|
return () => window.removeEventListener('keydown', onKeyDown);
|
|
2632
2642
|
}, []);
|
|
2633
2643
|
|
|
2644
|
+
// Register into Unified Right Activity Rail
|
|
2645
|
+
useEffect(() => {
|
|
2646
|
+
if (typeof window === 'undefined' || !window.__DSH_RIGHT_RAIL__) return;
|
|
2647
|
+
return window.__DSH_RIGHT_RAIL__.register('preview', {
|
|
2648
|
+
id: 'preview',
|
|
2649
|
+
order: 10,
|
|
2650
|
+
label: '预览',
|
|
2651
|
+
icon: '📁',
|
|
2652
|
+
badge: tabs.length > 0 ? tabs.length : null,
|
|
2653
|
+
title: tabs.length > 0 ? `工作区文件与文档预览 (${tabs.length} 个标签)` : '浏览工作空间文件树',
|
|
2654
|
+
onClick: (nextActive) => {
|
|
2655
|
+
setPanelOpen(nextActive);
|
|
2656
|
+
},
|
|
2657
|
+
});
|
|
2658
|
+
}, [tabs.length]);
|
|
2659
|
+
|
|
2660
|
+
// Sync activeId with Right Rail
|
|
2661
|
+
useEffect(() => {
|
|
2662
|
+
if (typeof window === 'undefined' || !window.__DSH_RIGHT_RAIL__) return;
|
|
2663
|
+
if (isOpen && window.__DSH_RIGHT_RAIL__.activeId !== 'preview') {
|
|
2664
|
+
window.__DSH_RIGHT_RAIL__.activeId = 'preview';
|
|
2665
|
+
window.__DSH_RIGHT_RAIL__.notify();
|
|
2666
|
+
} else if (!isOpen && window.__DSH_RIGHT_RAIL__.activeId === 'preview') {
|
|
2667
|
+
window.__DSH_RIGHT_RAIL__.activeId = null;
|
|
2668
|
+
window.__DSH_RIGHT_RAIL__.notify();
|
|
2669
|
+
}
|
|
2670
|
+
}, [isOpen]);
|
|
2671
|
+
|
|
2634
2672
|
const activeKey = activeTab?.filePath?.toLowerCase();
|
|
2635
2673
|
const currentFileInfo = activeKey ? fileData[activeKey] : null;
|
|
2636
2674
|
const currentLoading = activeKey ? !!loadingMap[activeKey] : false;
|
|
2637
2675
|
const currentError = activeKey ? errorMap[activeKey] : null;
|
|
2638
2676
|
|
|
2639
|
-
return h(
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
className: 'dsh-preview-float-pill',
|
|
2643
|
-
onClick: () => setPanelOpen(true),
|
|
2644
|
-
title: tabs.length > 0 ? `展开文档与工作区文件浏览 (${tabs.length} 个标签)` : '浏览工作空间文件树',
|
|
2645
|
-
},
|
|
2646
|
-
h('span', { className: 'dsh-float-pill-icon' }, '📁'),
|
|
2647
|
-
h('span', { className: 'dsh-float-pill-text' }, tabs.length > 0 ? `预览: ${activeTab?.title || '文档'}` : '工作区文件'),
|
|
2648
|
-
tabs.length > 0 ? h('span', { className: 'dsh-float-pill-badge' }, tabs.length) : null
|
|
2649
|
-
) : null,
|
|
2650
|
-
|
|
2651
|
-
// Right-Side Slide Drawer
|
|
2677
|
+
return h(
|
|
2678
|
+
Fragment,
|
|
2679
|
+
null,
|
|
2652
2680
|
isOpen ? h('div', {
|
|
2653
2681
|
ref: drawerRef,
|
|
2654
2682
|
className: `dsh-preview-drawer-container ${isDragging || isTreeDragging ? 'dragging' : ''}`,
|
|
@@ -2832,45 +2860,185 @@
|
|
|
2832
2860
|
DeepSeek Harness Preview Plugin Styles (WorkBuddy FileTabs Inspired)
|
|
2833
2861
|
===================================================================== */
|
|
2834
2862
|
|
|
2835
|
-
/*
|
|
2836
|
-
.dsh-
|
|
2863
|
+
/* Unified Right Activity Rail Container */
|
|
2864
|
+
.dsh-right-activity-rail {
|
|
2837
2865
|
position: fixed;
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2866
|
+
right: 0;
|
|
2867
|
+
top: 40%;
|
|
2868
|
+
transform: translateY(-50%);
|
|
2869
|
+
z-index: 9998;
|
|
2841
2870
|
display: flex;
|
|
2842
|
-
|
|
2871
|
+
flex-direction: column;
|
|
2843
2872
|
gap: 8px;
|
|
2844
|
-
|
|
2873
|
+
align-items: flex-end;
|
|
2874
|
+
pointer-events: auto;
|
|
2875
|
+
user-select: none;
|
|
2876
|
+
transition: none !important;
|
|
2877
|
+
animation: none !important;
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
/* Right-Edge Vertical Tool Window Tab (Preview Tab & Unified Item) */
|
|
2881
|
+
.dsh-rail-tab-item, .dsh-preview-right-rail-tab, .dsh-preview-float-pill, .dsh-git-right-rail-tab {
|
|
2882
|
+
box-sizing: border-box;
|
|
2883
|
+
display: flex;
|
|
2884
|
+
flex-direction: column;
|
|
2885
|
+
align-items: center;
|
|
2886
|
+
justify-content: space-between;
|
|
2887
|
+
width: 28px;
|
|
2888
|
+
min-width: 28px;
|
|
2889
|
+
max-width: 28px;
|
|
2890
|
+
height: 84px;
|
|
2891
|
+
min-height: 84px;
|
|
2892
|
+
max-height: 84px;
|
|
2893
|
+
padding: 8px 3px 6px;
|
|
2845
2894
|
background: var(--dsw-alias-bg-layer-2, #f8fafc);
|
|
2846
2895
|
color: var(--dsw-alias-label-primary, #0f172a);
|
|
2847
|
-
border: 1px solid var(--dsw-alias-border-
|
|
2848
|
-
border-
|
|
2849
|
-
|
|
2896
|
+
border: 1px solid var(--dsw-alias-border-l2, #cbd5e1);
|
|
2897
|
+
border-right: none;
|
|
2898
|
+
border-radius: 8px 0 0 8px;
|
|
2899
|
+
box-shadow: -3px 3px 12px rgba(0, 0, 0, 0.08);
|
|
2850
2900
|
cursor: pointer;
|
|
2851
|
-
font-size: 13px;
|
|
2852
|
-
font-weight: 500;
|
|
2853
|
-
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2854
2901
|
user-select: none;
|
|
2902
|
+
transition: transform 0.16s ease, background 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease, color 0.16s ease;
|
|
2903
|
+
font-family: inherit;
|
|
2904
|
+
outline: none;
|
|
2905
|
+
overflow: hidden;
|
|
2855
2906
|
}
|
|
2856
|
-
body[data-ds-dark-theme] .dsh-
|
|
2907
|
+
body[data-ds-dark-theme] .dsh-rail-tab-item,
|
|
2908
|
+
body[data-ds-dark-theme] .dsh-preview-right-rail-tab,
|
|
2909
|
+
body[data-ds-dark-theme] .dsh-preview-float-pill,
|
|
2910
|
+
body[data-ds-dark-theme] .dsh-git-right-rail-tab {
|
|
2857
2911
|
background: var(--dsw-alias-bg-layer-2, #1e222d);
|
|
2858
2912
|
color: var(--dsw-alias-label-primary, #e2e8f0);
|
|
2859
|
-
border-color: var(--dsw-alias-border-
|
|
2860
|
-
box-shadow:
|
|
2913
|
+
border-color: var(--dsw-alias-border-l2, #334155);
|
|
2914
|
+
box-shadow: -4px 4px 16px rgba(0, 0, 0, 0.35);
|
|
2861
2915
|
}
|
|
2862
|
-
.dsh-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2916
|
+
.dsh-rail-tab-item:hover,
|
|
2917
|
+
.dsh-preview-right-rail-tab:hover,
|
|
2918
|
+
.dsh-preview-float-pill:hover,
|
|
2919
|
+
.dsh-git-right-rail-tab:hover {
|
|
2920
|
+
background: var(--dsw-alias-bg-layer-1, #ffffff);
|
|
2921
|
+
color: #3b82f6;
|
|
2922
|
+
border-color: #3b82f6;
|
|
2923
|
+
transform: translateX(-4px);
|
|
2924
|
+
box-shadow: -5px 5px 18px rgba(59, 130, 246, 0.22);
|
|
2925
|
+
}
|
|
2926
|
+
body[data-ds-dark-theme] .dsh-rail-tab-item:hover,
|
|
2927
|
+
body[data-ds-dark-theme] .dsh-preview-right-rail-tab:hover,
|
|
2928
|
+
body[data-ds-dark-theme] .dsh-preview-float-pill:hover,
|
|
2929
|
+
body[data-ds-dark-theme] .dsh-git-right-rail-tab:hover {
|
|
2930
|
+
background: var(--dsw-alias-bg-layer-1, #252a36);
|
|
2931
|
+
color: #60a5fa;
|
|
2932
|
+
border-color: #3b82f6;
|
|
2866
2933
|
}
|
|
2867
|
-
.dsh-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
border-
|
|
2934
|
+
.dsh-rail-tab-item.active,
|
|
2935
|
+
.dsh-preview-right-rail-tab.active,
|
|
2936
|
+
.dsh-git-right-rail-tab.active {
|
|
2937
|
+
background: #2563eb;
|
|
2938
|
+
color: #ffffff;
|
|
2939
|
+
border-color: #1d4ed8;
|
|
2940
|
+
transform: translateX(-3px);
|
|
2941
|
+
box-shadow: -5px 5px 18px rgba(37, 99, 235, 0.35);
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
.dsh-rail-tab-icon {
|
|
2945
|
+
display: flex;
|
|
2946
|
+
align-items: center;
|
|
2947
|
+
justify-content: center;
|
|
2948
|
+
width: 16px;
|
|
2949
|
+
height: 16px;
|
|
2950
|
+
min-width: 16px;
|
|
2951
|
+
min-height: 16px;
|
|
2952
|
+
max-width: 16px;
|
|
2953
|
+
max-height: 16px;
|
|
2954
|
+
line-height: 1;
|
|
2955
|
+
flex-shrink: 0;
|
|
2956
|
+
transition: none !important;
|
|
2957
|
+
animation: none !important;
|
|
2958
|
+
transform: none !important;
|
|
2959
|
+
}
|
|
2960
|
+
.dsh-rail-tab-icon svg {
|
|
2961
|
+
width: 14px !important;
|
|
2962
|
+
height: 14px !important;
|
|
2963
|
+
min-width: 14px !important;
|
|
2964
|
+
min-height: 14px !important;
|
|
2965
|
+
max-width: 14px !important;
|
|
2966
|
+
max-height: 14px !important;
|
|
2967
|
+
flex-shrink: 0 !important;
|
|
2968
|
+
display: block !important;
|
|
2969
|
+
transition: none !important;
|
|
2970
|
+
animation: none !important;
|
|
2971
|
+
transform: none !important;
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
.dsh-rail-tab-title, .dsh-preview-rail-title, .dsh-git-rail-title {
|
|
2975
|
+
writing-mode: vertical-rl;
|
|
2976
|
+
text-orientation: mixed;
|
|
2977
|
+
font-size: 11.5px;
|
|
2873
2978
|
font-weight: 600;
|
|
2979
|
+
letter-spacing: 2px;
|
|
2980
|
+
line-height: 1;
|
|
2981
|
+
flex-shrink: 0;
|
|
2982
|
+
user-select: none;
|
|
2983
|
+
transition: none !important;
|
|
2984
|
+
animation: none !important;
|
|
2985
|
+
transform: none !important;
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
.dsh-rail-tab-badge, .dsh-float-pill-badge, .dsh-preview-rail-badge, .dsh-git-rail-badge {
|
|
2989
|
+
writing-mode: horizontal-tb;
|
|
2990
|
+
display: inline-flex;
|
|
2991
|
+
align-items: center;
|
|
2992
|
+
justify-content: center;
|
|
2993
|
+
min-width: 17px;
|
|
2994
|
+
height: 17px;
|
|
2995
|
+
min-height: 17px;
|
|
2996
|
+
max-height: 17px;
|
|
2997
|
+
padding: 0 4px;
|
|
2998
|
+
border-radius: 9px;
|
|
2999
|
+
background: #2563eb;
|
|
3000
|
+
color: #ffffff;
|
|
3001
|
+
font-size: 10px;
|
|
3002
|
+
font-weight: 700;
|
|
3003
|
+
line-height: 1;
|
|
3004
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
3005
|
+
flex-shrink: 0;
|
|
3006
|
+
box-sizing: border-box;
|
|
3007
|
+
transition: none !important;
|
|
3008
|
+
animation: none !important;
|
|
3009
|
+
transform: none !important;
|
|
3010
|
+
}
|
|
3011
|
+
body[data-ds-dark-theme] .dsh-rail-tab-badge,
|
|
3012
|
+
body[data-ds-dark-theme] .dsh-float-pill-badge,
|
|
3013
|
+
body[data-ds-dark-theme] .dsh-preview-rail-badge,
|
|
3014
|
+
body[data-ds-dark-theme] .dsh-git-rail-badge {
|
|
3015
|
+
background: #3b82f6;
|
|
3016
|
+
}
|
|
3017
|
+
.dsh-rail-tab-item.active .dsh-rail-tab-badge,
|
|
3018
|
+
.dsh-preview-right-rail-tab.active .dsh-preview-rail-badge,
|
|
3019
|
+
.dsh-git-right-rail-tab.active .dsh-git-rail-badge {
|
|
3020
|
+
background: #ffffff;
|
|
3021
|
+
color: #2563eb;
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
.dsh-rail-tab-badge-placeholder {
|
|
3025
|
+
width: 17px;
|
|
3026
|
+
height: 17px;
|
|
3027
|
+
min-height: 17px;
|
|
3028
|
+
max-height: 17px;
|
|
3029
|
+
flex-shrink: 0;
|
|
3030
|
+
visibility: hidden;
|
|
3031
|
+
}
|
|
3032
|
+
body[data-ds-dark-theme] .dsh-rail-tab-badge,
|
|
3033
|
+
body[data-ds-dark-theme] .dsh-float-pill-badge,
|
|
3034
|
+
body[data-ds-dark-theme] .dsh-preview-rail-badge {
|
|
3035
|
+
background: #3b82f6;
|
|
3036
|
+
}
|
|
3037
|
+
.dsh-rail-tab-item.active .dsh-rail-tab-badge,
|
|
3038
|
+
.dsh-preview-right-rail-tab.active .dsh-float-pill-badge,
|
|
3039
|
+
.dsh-preview-right-rail-tab.active .dsh-preview-rail-badge {
|
|
3040
|
+
background: #ffffff;
|
|
3041
|
+
color: #2563eb;
|
|
2874
3042
|
}
|
|
2875
3043
|
|
|
2876
3044
|
/* Right-Side Drawer Container */
|
|
@@ -4502,6 +4670,102 @@
|
|
|
4502
4670
|
document.head.appendChild(style);
|
|
4503
4671
|
}
|
|
4504
4672
|
|
|
4673
|
+
// =========================================================================
|
|
4674
|
+
// =========================================================================
|
|
4675
|
+
// Unified Right Activity Rail Registry & Host
|
|
4676
|
+
// =========================================================================
|
|
4677
|
+
if (typeof window !== 'undefined' && !window.__DSH_RIGHT_RAIL__) {
|
|
4678
|
+
window.__DSH_RIGHT_RAIL__ = {
|
|
4679
|
+
tabs: new Map(),
|
|
4680
|
+
listeners: new Set(),
|
|
4681
|
+
activeId: null,
|
|
4682
|
+
register(id, config) {
|
|
4683
|
+
this.tabs.set(id, config);
|
|
4684
|
+
this.notify();
|
|
4685
|
+
return () => {
|
|
4686
|
+
this.tabs.delete(id);
|
|
4687
|
+
this.notify();
|
|
4688
|
+
};
|
|
4689
|
+
},
|
|
4690
|
+
setActive(id) {
|
|
4691
|
+
if (this.activeId === id) return;
|
|
4692
|
+
this.activeId = id;
|
|
4693
|
+
this.notify();
|
|
4694
|
+
window.dispatchEvent(new CustomEvent('dsh:tool-window:open', { detail: { id } }));
|
|
4695
|
+
},
|
|
4696
|
+
subscribe(fn) {
|
|
4697
|
+
this.listeners.add(fn);
|
|
4698
|
+
return () => this.listeners.delete(fn);
|
|
4699
|
+
},
|
|
4700
|
+
notify() {
|
|
4701
|
+
for (const fn of this.listeners) {
|
|
4702
|
+
try { fn(); } catch (e) {}
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
};
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
function RightActivityRailHost() {
|
|
4709
|
+
const [, setTick] = useState(0);
|
|
4710
|
+
const hostIdRef = useRef(null);
|
|
4711
|
+
|
|
4712
|
+
if (!hostIdRef.current) {
|
|
4713
|
+
hostIdRef.current = Math.random().toString(36).slice(2);
|
|
4714
|
+
}
|
|
4715
|
+
|
|
4716
|
+
useEffect(() => {
|
|
4717
|
+
if (typeof window === 'undefined' || !window.__DSH_RIGHT_RAIL__) return;
|
|
4718
|
+
if (!window.__DSH_ACTIVE_RAIL_HOST_ID__) {
|
|
4719
|
+
window.__DSH_ACTIVE_RAIL_HOST_ID__ = hostIdRef.current;
|
|
4720
|
+
}
|
|
4721
|
+
return window.__DSH_RIGHT_RAIL__.subscribe(() => setTick((t) => t + 1));
|
|
4722
|
+
}, []);
|
|
4723
|
+
|
|
4724
|
+
useEffect(() => {
|
|
4725
|
+
return () => {
|
|
4726
|
+
if (typeof window !== 'undefined' && window.__DSH_ACTIVE_RAIL_HOST_ID__ === hostIdRef.current) {
|
|
4727
|
+
window.__DSH_ACTIVE_RAIL_HOST_ID__ = null;
|
|
4728
|
+
}
|
|
4729
|
+
};
|
|
4730
|
+
}, []);
|
|
4731
|
+
|
|
4732
|
+
if (typeof window !== 'undefined' && window.__DSH_ACTIVE_RAIL_HOST_ID__ && window.__DSH_ACTIVE_RAIL_HOST_ID__ !== hostIdRef.current) {
|
|
4733
|
+
return null;
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4736
|
+
const rail = typeof window !== 'undefined' ? window.__DSH_RIGHT_RAIL__ : null;
|
|
4737
|
+
if (!rail || rail.tabs.size === 0) return null;
|
|
4738
|
+
|
|
4739
|
+
const tabList = Array.from(rail.tabs.values()).sort((a, b) => (a.order ?? 50) - (b.order ?? 50));
|
|
4740
|
+
|
|
4741
|
+
return h(
|
|
4742
|
+
'div',
|
|
4743
|
+
{ className: 'dsh-right-activity-rail' },
|
|
4744
|
+
tabList.map((tab) => {
|
|
4745
|
+
const isActive = rail.activeId === tab.id;
|
|
4746
|
+
return h(
|
|
4747
|
+
'button',
|
|
4748
|
+
{
|
|
4749
|
+
key: tab.id,
|
|
4750
|
+
type: 'button',
|
|
4751
|
+
className: `dsh-rail-tab-item ${isActive ? 'active' : ''}`,
|
|
4752
|
+
onClick: () => {
|
|
4753
|
+
const nextActive = !isActive;
|
|
4754
|
+
rail.setActive(nextActive ? tab.id : null);
|
|
4755
|
+
if (tab.onClick) tab.onClick(nextActive);
|
|
4756
|
+
},
|
|
4757
|
+
title: tab.title || tab.label || tab.id,
|
|
4758
|
+
},
|
|
4759
|
+
h('span', { className: 'dsh-rail-tab-icon' }, tab.icon),
|
|
4760
|
+
h('span', { className: 'dsh-rail-tab-title' }, tab.label || tab.id),
|
|
4761
|
+
tab.badge !== undefined && tab.badge !== null && tab.badge !== 0
|
|
4762
|
+
? h('span', { className: 'dsh-rail-tab-badge' }, tab.badge)
|
|
4763
|
+
: h('span', { className: 'dsh-rail-tab-badge-placeholder' })
|
|
4764
|
+
);
|
|
4765
|
+
})
|
|
4766
|
+
);
|
|
4767
|
+
}
|
|
4768
|
+
|
|
4505
4769
|
// =========================================================================
|
|
4506
4770
|
// Cordis Client Plugin Apply & Slot Injection
|
|
4507
4771
|
// =========================================================================
|
|
@@ -4519,7 +4783,17 @@
|
|
|
4519
4783
|
|
|
4520
4784
|
console.log('[Preview] Markdown Preview Client Plugin loaded successfully!');
|
|
4521
4785
|
|
|
4522
|
-
//
|
|
4786
|
+
// 1. Mount Unified Right Activity Rail Host into shell.overlay
|
|
4787
|
+
ctx.slots.inject(
|
|
4788
|
+
'shell.overlay',
|
|
4789
|
+
() => ctx.slots.register({
|
|
4790
|
+
name: 'shell.overlay',
|
|
4791
|
+
id: 'preview-right-rail-host',
|
|
4792
|
+
order: 34,
|
|
4793
|
+
}, () => h(RightActivityRailHost, { hostId: 'preview' }))
|
|
4794
|
+
);
|
|
4795
|
+
|
|
4796
|
+
// 2. Mount Preview Drawer into shell.overlay
|
|
4523
4797
|
ctx.slots.inject(
|
|
4524
4798
|
'shell.overlay',
|
|
4525
4799
|
() => ctx.slots.register({
|
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.8",
|
|
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",
|