dsh-desktop-windows 0.2.5 → 0.2.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/screenshot.html +53 -32
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.5",
4
+ "version": "0.2.6",
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",
@@ -8,7 +8,23 @@
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
- #cv { position: fixed; inset: 0; pointer-events: none; z-index: 2; }
11
+ /* 遮罩:全屏半透明黑 + clip-path 挖洞(GPU 加速,每帧只改字符串) */
12
+ #mask {
13
+ position: fixed; inset: 0; z-index: 2; pointer-events: none;
14
+ background: rgba(0, 0, 0, 0.45);
15
+ clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
16
+ }
17
+ /* 选区框:border div,transform 定位 + 尺寸更新 */
18
+ #sel {
19
+ position: fixed; z-index: 3; pointer-events: none;
20
+ border: 1.5px solid #2563eb; background: rgba(37, 99, 235, 0.08);
21
+ transform-origin: 0 0;
22
+ }
23
+ #sel .sz {
24
+ position: absolute; left: 0; top: -22px;
25
+ background: #2563eb; color: #fff;
26
+ font: 11px/18px sans-serif; padding: 0 6px; border-radius: 4px; white-space: nowrap;
27
+ }
12
28
  .handle {
13
29
  position: fixed; width: 9px; height: 9px; background: #2563eb;
14
30
  border: 1px solid #fff; border-radius: 2px; display: none;
@@ -40,7 +56,8 @@
40
56
  </head>
41
57
  <body>
42
58
  <div id="stage"><img id="bg" alt=""></div>
43
- <canvas id="cv"></canvas>
59
+ <div id="mask"></div>
60
+ <div id="sel"><div class="sz"></div></div>
44
61
  <div id="hN" class="handle" style="cursor:n-resize"></div>
45
62
  <div id="hS" class="handle" style="cursor:s-resize"></div>
46
63
  <div id="hE" class="handle" style="cursor:e-resize"></div>
@@ -58,11 +75,12 @@
58
75
 
59
76
  <script>
60
77
  var bg = document.getElementById('bg')
78
+ var mask = document.getElementById('mask')
79
+ var sel = document.getElementById('sel')
80
+ var sz = sel.querySelector('.sz')
61
81
  var toolbar = document.getElementById('toolbar')
62
82
  var hint = document.getElementById('hint')
63
83
  var tip = document.getElementById('tip')
64
- var cv = document.getElementById('cv')
65
- var cx = cv.getContext('2d')
66
84
  var handles = {
67
85
  n: document.getElementById('hN'), s: document.getElementById('hS'),
68
86
  e: document.getElementById('hE'), w: document.getElementById('hW'),
@@ -70,7 +88,6 @@
70
88
  se: document.getElementById('hSE'), sw: document.getElementById('hSW'),
71
89
  }
72
90
  var W = window.innerWidth, H = window.innerHeight
73
- cv.width = W; cv.height = H
74
91
  var MIN = 8
75
92
  var rect = null
76
93
  var mode = 'draw' // draw | adjust
@@ -80,7 +97,7 @@
80
97
  window.__screenshot.onData(function (dataUrl) {
81
98
  bg.onload = function () {
82
99
  window.__screenshot.loaded()
83
- draw()
100
+ update()
84
101
  setTimeout(function () { hint.style.opacity = '0.9' }, 100)
85
102
  }
86
103
  bg.src = dataUrl
@@ -94,28 +111,29 @@
94
111
  return { x: x, y: y, w: w, h: h }
95
112
  }
96
113
 
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))
114
+ // 每帧只更新 2 个元素:mask clip-path(GPU)+ sel 的位置尺寸
115
+ function update() {
116
+ if (!rect) {
117
+ mask.style.clipPath = 'polygon(0px 0px, 0px 0px, 0px 0px, 0px 0px, 0px 0px)'
118
+ sel.style.display = 'none'
119
+ hideHandles()
120
+ return
121
+ }
122
+ var x = rect.x, y = rect.y, w = rect.w, h = rect.h
123
+ // clip-path:外框逆时针 + 选区顺时针 → 挖洞
124
+ mask.style.clipPath =
125
+ 'polygon(0px 0px, ' + W + 'px 0px, ' + W + 'px ' + H + 'px, 0px ' + H + 'px, 0px 0px, ' +
126
+ x + 'px ' + y + 'px, ' + (x + w) + 'px ' + y + 'px, ' + (x + w) + 'px ' + (y + h) + 'px, ' + x + 'px ' + (y + h) + 'px, ' + x + 'px ' + y + 'px)'
127
+ sel.style.display = 'block'
128
+ sel.style.transform = 'translate(' + x + 'px, ' + y + 'px)'
129
+ sel.style.width = w + 'px'
130
+ sel.style.height = h + 'px'
131
+ sz.textContent = Math.round(w) + ' × ' + Math.round(h)
132
+ updateHandles()
112
133
  }
113
134
 
114
135
  function updateHandles() {
115
- if (mode !== 'adjust' || !rect) {
116
- for (var k in handles) handles[k].style.display = 'none'
117
- return
118
- }
136
+ if (mode !== 'adjust' || !rect) { hideHandles(); return }
119
137
  var x = rect.x, y = rect.y, w = rect.w, h = rect.h
120
138
  var pos = {
121
139
  n: [x + w / 2, y], s: [x + w / 2, y + h],
@@ -129,13 +147,16 @@
129
147
  }
130
148
  }
131
149
 
132
- function scheduleDraw() {
150
+ function hideHandles() {
151
+ for (var k in handles) handles[k].style.display = 'none'
152
+ }
153
+
154
+ function scheduleUpdate() {
133
155
  if (rafPending) return
134
156
  rafPending = true
135
157
  requestAnimationFrame(function () {
136
158
  rafPending = false
137
- draw()
138
- updateHandles()
159
+ update()
139
160
  })
140
161
  }
141
162
 
@@ -161,7 +182,7 @@
161
182
  toolbar.style.display = 'none'
162
183
  hint.style.opacity = '0.9'
163
184
  drag = { type: 'draw', x0: e.clientX, y0: e.clientY }
164
- scheduleDraw()
185
+ scheduleUpdate()
165
186
  }
166
187
  })
167
188
 
@@ -182,7 +203,7 @@
182
203
  if (drag.dir.indexOf('n') !== -1) { r.y = o.y + dy; r.h = o.h - dy }
183
204
  rect = clampRect(r)
184
205
  }
185
- scheduleDraw()
206
+ scheduleUpdate()
186
207
  })
187
208
 
188
209
  document.addEventListener('mouseup', function () {
@@ -195,11 +216,11 @@
195
216
  t.style.left = Math.min(rect.x + rect.w + 10, W - 250) + 'px'
196
217
  t.style.top = (rect.y + rect.h + 14 > H - 60 ? rect.y - 60 : rect.y + rect.h + 14) + 'px'
197
218
  hint.style.opacity = '0'
198
- scheduleDraw() // 显示手柄
219
+ scheduleUpdate()
199
220
  }
200
221
  })
201
222
 
202
- // 关键修复:点击工具栏(确定/取消)不触发 document 的画框逻辑
223
+ // 关键:点击工具栏(确定/取消)不触发 document 的画框逻辑
203
224
  toolbar.addEventListener('mousedown', function (e) { e.stopPropagation() })
204
225
 
205
226
  document.getElementById('okBtn').onclick = function () {