dsh-desktop-windows 0.2.4 → 0.2.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.
- package/package.json +1 -1
- package/src/screenshot.html +79 -85
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-desktop-windows",
|
|
3
3
|
"productName": "DeepSeek Harness Desktop",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
5
5
|
"description": "DeepSeek Harness 桌面版(Windows)· Electron desktop shell for DeepSeek Harness (dsh web) — 双击即用,无需终端 / double-click to run the harness in a standalone window",
|
|
6
6
|
"main": "src/main.js",
|
|
7
7
|
"license": "MIT",
|
package/src/screenshot.html
CHANGED
|
@@ -8,21 +8,12 @@
|
|
|
8
8
|
html, body { width: 100%; height: 100%; overflow: hidden; background: #000; cursor: crosshair; }
|
|
9
9
|
#stage { position: fixed; inset: 0; }
|
|
10
10
|
#stage img { width: 100%; height: 100%; object-fit: fill; display: block; }
|
|
11
|
-
|
|
12
|
-
#sel {
|
|
13
|
-
position: fixed; border: 1.5px solid #2563eb;
|
|
14
|
-
background: rgba(37, 99, 235, 0.10);
|
|
15
|
-
display: none; pointer-events: none; z-index: 3;
|
|
16
|
-
}
|
|
17
|
-
#sel .sz {
|
|
18
|
-
position: absolute; left: 0; top: -22px;
|
|
19
|
-
background: #2563eb; color: #fff;
|
|
20
|
-
font: 11px/18px sans-serif; padding: 0 6px; border-radius: 4px; white-space: nowrap;
|
|
21
|
-
}
|
|
11
|
+
#cv { position: fixed; inset: 0; pointer-events: none; z-index: 2; }
|
|
22
12
|
.handle {
|
|
23
13
|
position: fixed; width: 9px; height: 9px; background: #2563eb;
|
|
24
14
|
border: 1px solid #fff; border-radius: 2px; display: none;
|
|
25
15
|
pointer-events: auto; z-index: 4;
|
|
16
|
+
transform: translate(-50%, -50%);
|
|
26
17
|
}
|
|
27
18
|
#toolbar {
|
|
28
19
|
position: fixed; display: none; align-items: center; gap: 8px;
|
|
@@ -32,8 +23,8 @@
|
|
|
32
23
|
}
|
|
33
24
|
#toolbar .tip { color: #94a3b8; font: 12px/1 sans-serif; margin-right: 4px; }
|
|
34
25
|
#toolbar button {
|
|
35
|
-
border: none; border-radius: 6px; padding:
|
|
36
|
-
font: 600
|
|
26
|
+
border: none; border-radius: 6px; padding: 7px 16px; cursor: pointer;
|
|
27
|
+
font: 600 13px/1 sans-serif;
|
|
37
28
|
}
|
|
38
29
|
#okBtn { background: #2563eb; color: #fff; }
|
|
39
30
|
#okBtn:hover { background: #1d4ed8; }
|
|
@@ -49,11 +40,7 @@
|
|
|
49
40
|
</head>
|
|
50
41
|
<body>
|
|
51
42
|
<div id="stage"><img id="bg" alt=""></div>
|
|
52
|
-
<
|
|
53
|
-
<div id="maskBottom" class="mask"></div>
|
|
54
|
-
<div id="maskLeft" class="mask"></div>
|
|
55
|
-
<div id="maskRight" class="mask"></div>
|
|
56
|
-
<div id="sel"><div class="sz"></div></div>
|
|
43
|
+
<canvas id="cv"></canvas>
|
|
57
44
|
<div id="hN" class="handle" style="cursor:n-resize"></div>
|
|
58
45
|
<div id="hS" class="handle" style="cursor:s-resize"></div>
|
|
59
46
|
<div id="hE" class="handle" style="cursor:e-resize"></div>
|
|
@@ -62,26 +49,20 @@
|
|
|
62
49
|
<div id="hNW" class="handle" style="cursor:nw-resize"></div>
|
|
63
50
|
<div id="hSE" class="handle" style="cursor:se-resize"></div>
|
|
64
51
|
<div id="hSW" class="handle" style="cursor:sw-resize"></div>
|
|
65
|
-
<div id="toolbar">
|
|
66
|
-
<span class="tip" id="tip"
|
|
52
|
+
<div id="toolbar" style="cursor:default">
|
|
53
|
+
<span class="tip" id="tip">可拖拽边框微调 · 点确定或双击完成</span>
|
|
67
54
|
<button id="okBtn">✔ 确定</button>
|
|
68
55
|
<button id="cancelBtn">✕ 取消 (Esc)</button>
|
|
69
56
|
</div>
|
|
70
|
-
<div id="hint">拖动鼠标框选要截取的区域 · 画完后可拖拽边框微调 · Esc 取消</div>
|
|
57
|
+
<div id="hint">拖动鼠标框选要截取的区域 · 画完后可拖拽边框微调 · 双击完成 · Esc 取消</div>
|
|
71
58
|
|
|
72
59
|
<script>
|
|
73
60
|
var bg = document.getElementById('bg')
|
|
74
|
-
var sel = document.getElementById('sel')
|
|
75
61
|
var toolbar = document.getElementById('toolbar')
|
|
76
62
|
var hint = document.getElementById('hint')
|
|
77
63
|
var tip = document.getElementById('tip')
|
|
78
|
-
var
|
|
79
|
-
var
|
|
80
|
-
top: document.getElementById('maskTop'),
|
|
81
|
-
bottom: document.getElementById('maskBottom'),
|
|
82
|
-
left: document.getElementById('maskLeft'),
|
|
83
|
-
right: document.getElementById('maskRight'),
|
|
84
|
-
}
|
|
64
|
+
var cv = document.getElementById('cv')
|
|
65
|
+
var cx = cv.getContext('2d')
|
|
85
66
|
var handles = {
|
|
86
67
|
n: document.getElementById('hN'), s: document.getElementById('hS'),
|
|
87
68
|
e: document.getElementById('hE'), w: document.getElementById('hW'),
|
|
@@ -89,14 +70,17 @@
|
|
|
89
70
|
se: document.getElementById('hSE'), sw: document.getElementById('hSW'),
|
|
90
71
|
}
|
|
91
72
|
var W = window.innerWidth, H = window.innerHeight
|
|
73
|
+
cv.width = W; cv.height = H
|
|
92
74
|
var MIN = 8
|
|
93
75
|
var rect = null
|
|
94
76
|
var mode = 'draw' // draw | adjust
|
|
95
77
|
var drag = null
|
|
78
|
+
var rafPending = false
|
|
96
79
|
|
|
97
80
|
window.__screenshot.onData(function (dataUrl) {
|
|
98
81
|
bg.onload = function () {
|
|
99
82
|
window.__screenshot.loaded()
|
|
83
|
+
draw()
|
|
100
84
|
setTimeout(function () { hint.style.opacity = '0.9' }, 100)
|
|
101
85
|
}
|
|
102
86
|
bg.src = dataUrl
|
|
@@ -105,38 +89,54 @@
|
|
|
105
89
|
function clampRect(r) {
|
|
106
90
|
var x = Math.max(0, Math.min(W - MIN, r.x))
|
|
107
91
|
var y = Math.max(0, Math.min(H - MIN, r.y))
|
|
108
|
-
var w = Math.min(r.w, W - x)
|
|
109
|
-
var h = Math.min(r.h, H - y)
|
|
110
|
-
w = Math.max(MIN, w); h = Math.max(MIN, h)
|
|
92
|
+
var w = Math.max(MIN, Math.min(r.w, W - x))
|
|
93
|
+
var h = Math.max(MIN, Math.min(r.h, H - y))
|
|
111
94
|
return { x: x, y: y, w: w, h: h }
|
|
112
95
|
}
|
|
113
96
|
|
|
114
|
-
|
|
115
|
-
|
|
97
|
+
// Canvas 一次性绘制遮罩 + 选区 + 尺寸(高性能)
|
|
98
|
+
function draw() {
|
|
99
|
+
cx.clearRect(0, 0, W, H)
|
|
100
|
+
cx.fillStyle = 'rgba(0,0,0,0.45)'
|
|
101
|
+
if (!rect) { cx.fillRect(0, 0, W, H); return }
|
|
102
|
+
cx.fillRect(0, 0, W, rect.y)
|
|
103
|
+
cx.fillRect(0, rect.y + rect.h, W, H - rect.y - rect.h)
|
|
104
|
+
cx.fillRect(0, rect.y, rect.x, rect.h)
|
|
105
|
+
cx.fillRect(rect.x + rect.w, rect.y, W - rect.x - rect.w, rect.h)
|
|
106
|
+
cx.strokeStyle = '#2563eb'
|
|
107
|
+
cx.lineWidth = 1.5
|
|
108
|
+
cx.strokeRect(rect.x + 0.75, rect.y + 0.75, rect.w, rect.h)
|
|
109
|
+
cx.fillStyle = '#2563eb'
|
|
110
|
+
cx.font = '12px sans-serif'
|
|
111
|
+
cx.fillText(Math.round(rect.w) + ' × ' + Math.round(rect.h), rect.x + 4, Math.max(14, rect.y - 6))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function updateHandles() {
|
|
115
|
+
if (mode !== 'adjust' || !rect) {
|
|
116
|
+
for (var k in handles) handles[k].style.display = 'none'
|
|
117
|
+
return
|
|
118
|
+
}
|
|
116
119
|
var x = rect.x, y = rect.y, w = rect.w, h = rect.h
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// 遮罩(4 块)
|
|
122
|
-
masks.top.style.cssText = 'left:0;top:0;width:' + W + 'px;height:' + y + 'px;display:block'
|
|
123
|
-
masks.bottom.style.cssText = 'left:0;top:' + (y + h) + 'px;width:' + W + 'px;height:' + (H - y - h) + 'px;display:block'
|
|
124
|
-
masks.left.style.cssText = 'left:0;top:' + y + 'px;width:' + x + 'px;height:' + h + 'px;display:block'
|
|
125
|
-
masks.right.style.cssText = 'left:' + (x + w) + 'px;top:' + y + 'px;width:' + (W - x - w) + 'px;height:' + h + 'px;display:block'
|
|
126
|
-
// 手柄
|
|
127
|
-
if (mode === 'adjust') {
|
|
128
|
-
var half = 4.5
|
|
129
|
-
handles.n.style.cssText = 'left:' + (x + w / 2 - half) + 'px;top:' + (y - half) + 'px;display:block'
|
|
130
|
-
handles.s.style.cssText = 'left:' + (x + w / 2 - half) + 'px;top:' + (y + h - half) + 'px;display:block'
|
|
131
|
-
handles.e.style.cssText = 'left:' + (x + w - half) + 'px;top:' + (y + h / 2 - half) + 'px;display:block'
|
|
132
|
-
handles.w.style.cssText = 'left:' + (x - half) + 'px;top:' + (y + h / 2 - half) + 'px;display:block'
|
|
133
|
-
handles.ne.style.cssText = 'left:' + (x + w - half) + 'px;top:' + (y - half) + 'px;display:block'
|
|
134
|
-
handles.nw.style.cssText = 'left:' + (x - half) + 'px;top:' + (y - half) + 'px;display:block'
|
|
135
|
-
handles.se.style.cssText = 'left:' + (x + w - half) + 'px;top:' + (y + h - half) + 'px;display:block'
|
|
136
|
-
handles.sw.style.cssText = 'left:' + (x - half) + 'px;top:' + (y + h - half) + 'px;display:block'
|
|
137
|
-
} else {
|
|
138
|
-
Object.keys(handles).forEach(function (k) { handles[k].style.display = 'none' })
|
|
120
|
+
var pos = {
|
|
121
|
+
n: [x + w / 2, y], s: [x + w / 2, y + h],
|
|
122
|
+
e: [x + w, y + h / 2], w: [x, y + h / 2],
|
|
123
|
+
ne: [x + w, y], nw: [x, y], se: [x + w, y + h], sw: [x, y + h],
|
|
139
124
|
}
|
|
125
|
+
for (var k in pos) {
|
|
126
|
+
handles[k].style.display = 'block'
|
|
127
|
+
handles[k].style.left = pos[k][0] + 'px'
|
|
128
|
+
handles[k].style.top = pos[k][1] + 'px'
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function scheduleDraw() {
|
|
133
|
+
if (rafPending) return
|
|
134
|
+
rafPending = true
|
|
135
|
+
requestAnimationFrame(function () {
|
|
136
|
+
rafPending = false
|
|
137
|
+
draw()
|
|
138
|
+
updateHandles()
|
|
139
|
+
})
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
function inside(e, r) {
|
|
@@ -147,25 +147,21 @@
|
|
|
147
147
|
if (e.button !== 0) return
|
|
148
148
|
if (mode === 'draw') {
|
|
149
149
|
drag = { type: 'draw', x0: e.clientX, y0: e.clientY }
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
var hKey = null
|
|
153
|
+
for (var k in handles) if (e.target === handles[k]) { hKey = k; break }
|
|
154
|
+
if (hKey) {
|
|
155
|
+
drag = { type: 'resize', dir: hKey, x0: e.clientX, y0: e.clientY, orig: { x: rect.x, y: rect.y, w: rect.w, h: rect.h } }
|
|
156
|
+
} else if (inside(e, rect)) {
|
|
157
|
+
drag = { type: 'move', x0: e.clientX, y0: e.clientY, orig: { x: rect.x, y: rect.y } }
|
|
150
158
|
} else {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
drag = { type: 'move', x0: e.clientX, y0: e.clientY, orig: { x: rect.x, y: rect.y } }
|
|
158
|
-
} else {
|
|
159
|
-
// 点击选区外 → 重新画
|
|
160
|
-
mode = 'draw'
|
|
161
|
-
rect = null
|
|
162
|
-
sel.style.display = 'none'
|
|
163
|
-
toolbar.style.display = 'none'
|
|
164
|
-
Object.keys(handles).forEach(function (k) { handles[k].style.display = 'none' })
|
|
165
|
-
masks.top.style.display = masks.bottom.style.display = masks.left.style.display = masks.right.style.display = 'none'
|
|
166
|
-
hint.style.opacity = '0.9'
|
|
167
|
-
drag = { type: 'draw', x0: e.clientX, y0: e.clientY }
|
|
168
|
-
}
|
|
159
|
+
mode = 'draw'
|
|
160
|
+
rect = null
|
|
161
|
+
toolbar.style.display = 'none'
|
|
162
|
+
hint.style.opacity = '0.9'
|
|
163
|
+
drag = { type: 'draw', x0: e.clientX, y0: e.clientY }
|
|
164
|
+
scheduleDraw()
|
|
169
165
|
}
|
|
170
166
|
})
|
|
171
167
|
|
|
@@ -175,10 +171,8 @@
|
|
|
175
171
|
var dy = e.clientY - drag.y0
|
|
176
172
|
if (drag.type === 'draw') {
|
|
177
173
|
rect = clampRect({ x: Math.min(drag.x0, e.clientX), y: Math.min(drag.y0, e.clientY), w: Math.abs(e.clientX - drag.x0), h: Math.abs(e.clientY - drag.y0) })
|
|
178
|
-
layout()
|
|
179
174
|
} else if (drag.type === 'move') {
|
|
180
175
|
rect = clampRect({ x: drag.orig.x + dx, y: drag.orig.y + dy, w: rect.w, h: rect.h })
|
|
181
|
-
layout()
|
|
182
176
|
} else if (drag.type === 'resize') {
|
|
183
177
|
var o = drag.orig
|
|
184
178
|
var r = { x: o.x, y: o.y, w: o.w, h: o.h }
|
|
@@ -187,8 +181,8 @@
|
|
|
187
181
|
if (drag.dir.indexOf('w') !== -1) { r.x = o.x + dx; r.w = o.w - dx }
|
|
188
182
|
if (drag.dir.indexOf('n') !== -1) { r.y = o.y + dy; r.h = o.h - dy }
|
|
189
183
|
rect = clampRect(r)
|
|
190
|
-
layout()
|
|
191
184
|
}
|
|
185
|
+
scheduleDraw()
|
|
192
186
|
})
|
|
193
187
|
|
|
194
188
|
document.addEventListener('mouseup', function () {
|
|
@@ -198,23 +192,23 @@
|
|
|
198
192
|
mode = 'adjust'
|
|
199
193
|
var t = document.getElementById('toolbar')
|
|
200
194
|
t.style.display = 'flex'
|
|
201
|
-
t.style.left = Math.min(rect.x + rect.w + 10, W -
|
|
202
|
-
t.style.top = (rect.y + rect.h + 14 > H - 60 ? rect.y -
|
|
203
|
-
tip.textContent = '可拖拽边框微调 · 点确定或双击完成'
|
|
195
|
+
t.style.left = Math.min(rect.x + rect.w + 10, W - 250) + 'px'
|
|
196
|
+
t.style.top = (rect.y + rect.h + 14 > H - 60 ? rect.y - 60 : rect.y + rect.h + 14) + 'px'
|
|
204
197
|
hint.style.opacity = '0'
|
|
205
|
-
|
|
198
|
+
scheduleDraw() // 显示手柄
|
|
206
199
|
}
|
|
207
200
|
})
|
|
208
201
|
|
|
209
|
-
//
|
|
210
|
-
|
|
211
|
-
if (rect && inside(e, rect)) window.__screenshot.done(rect)
|
|
212
|
-
})
|
|
202
|
+
// 关键修复:点击工具栏(确定/取消)不触发 document 的画框逻辑
|
|
203
|
+
toolbar.addEventListener('mousedown', function (e) { e.stopPropagation() })
|
|
213
204
|
|
|
214
205
|
document.getElementById('okBtn').onclick = function () {
|
|
215
206
|
if (rect) window.__screenshot.done(rect)
|
|
216
207
|
}
|
|
217
208
|
document.getElementById('cancelBtn').onclick = function () { window.__screenshot.cancel() }
|
|
209
|
+
document.addEventListener('dblclick', function (e) {
|
|
210
|
+
if (rect && inside(e, rect)) window.__screenshot.done(rect)
|
|
211
|
+
})
|
|
218
212
|
document.addEventListener('keydown', function (e) {
|
|
219
213
|
if (e.key === 'Escape') window.__screenshot.cancel()
|
|
220
214
|
if (e.key === 'Enter' && rect) window.__screenshot.done(rect)
|