dsh-scroll-piano 0.3.4 → 0.3.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.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  - 竖条上有**「我的消息」小地图刻度**:你每发一条消息,对应位置一根蓝色小横杠——**按「在整段对话里的位置」定位,与滚动无关**,所以不管你滚到对话多深,自己的消息始终标在那、点得到。
10
10
  - **气泡只在鼠标贴近某条刻度(±16px)时出现**,内容就是那条消息的正文(最多 3 行);**其余位置整个不显示**(不显示音名、不显示 MIDI 数字)。
11
11
  - **点蓝色小横杠 → 跳到那条消息**(平滑滚动、滚到视口中央)。蓝条命中区放大到 18×12px(可视化仍是 7×2 细条,悬停时加宽变亮),比原来 2px 高好点得多;**点气泡也能跳**(两者同一个 `jumpTo`)。
12
- - 左下角一枚 `🎵 滚动钢琴 ON/OFF` 胶囊:点开关切换、右侧滑块调音量(设置存 `localStorage`)。
12
+ - 左下角一枚 `🎵 滚动钢琴 ON/OFF` 胶囊:点开关切换、右侧滑块调音量(设置存 `localStorage`)。**胶囊可拖动**(`cursor:grab`):位移 >6px 判定为拖、松手位置存 `localStorage("dsh-scroll-piano:pillPos")`、拖完 400ms 内不吞点击;**按在音量滑块上不进拖动**,滑块照常调音量。
13
13
  - 默认音域 C3–C6(3 个八度),只按半音触发(同音不重复触发)。
14
14
 
15
15
  > 预览**只显示用户自己发的消息**,**不做「取全局最近一条」兜底**(否则同一条会在整片区域反复出现 = 重复显示),位置感交给刻度。**声音与预览彼此独立**——任何位置滑动都照常出声,只有预览挑消息。
package/lib/client.js CHANGED
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
23
23
 
24
24
  //#region styles
25
25
  const CSS = [
26
- ".dshscp_pill{box-sizing:border-box;position:fixed;left:132px;bottom:16px;z-index:2147483000;height:32px;display:inline-flex;align-items:center;gap:10px;padding:0 10px;border-radius:16px;background:var(--dsw-alias-bg-elevated,#1f2430);color:var(--dsw-alias-label-primary,#e6e8ee);box-shadow:0 4px 18px rgba(0,0,0,.35);font-size:12px;line-height:16px}",
26
+ ".dshscp_pill{box-sizing:border-box;position:fixed;left:132px;bottom:16px;z-index:2147483000;height:32px;display:inline-flex;align-items:center;gap:10px;padding:0 10px;border-radius:16px;background:var(--dsw-alias-bg-elevated,#1f2430);color:var(--dsw-alias-label-primary,#e6e8ee);box-shadow:0 4px 18px rgba(0,0,0,.35);font-size:12px;line-height:16px;cursor:grab;touch-action:none}",
27
27
  ".dshscp_pill button{box-sizing:border-box;border:none;background:transparent;color:inherit;font:inherit;cursor:pointer;padding:0 2px;display:inline-flex;align-items:center;gap:6px}",
28
28
  ".dshscp_dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-tertiary,#6b7280)}",
29
29
  ".dshscp_dotOn{background:#35c46a;box-shadow:0 0 6px rgba(53,196,106,.9)}",
@@ -241,6 +241,48 @@ window.__ModuleLoader__.load({
241
241
  //#region component
242
242
  function ScrollPiano() {
243
243
  const [settings, setSettings] = useState(loadSettings);
244
+ // —— 左下角那条黑胶囊**可拖动**(音量滑块除外,它自己要收拖动事件)——
245
+ const [pillPos, setPillPos] = useState(() => {
246
+ try { return JSON.parse(localStorage.getItem("dsh-scroll-piano:pillPos") || "null"); } catch { return null; }
247
+ });
248
+ const pillPosRef = useRef(pillPos);
249
+ pillPosRef.current = pillPos;
250
+ const pillDragRef = useRef(null);
251
+ const pillDraggedRef = useRef(false);
252
+ const pillClearRef = useRef(0);
253
+ const onPillDown = (e) => {
254
+ // 按在音量滑块上不进拖动,否则调音量会被拖走
255
+ if (e.target && e.target.tagName === "INPUT") return;
256
+ if (e.pointerType === "mouse" && e.button !== 0) return;
257
+ pillDraggedRef.current = false;
258
+ const r = e.currentTarget.getBoundingClientRect();
259
+ pillDragRef.current = { x: e.clientX, y: e.clientY, left: r.left, top: r.top, moved: false };
260
+ try { e.currentTarget.setPointerCapture(e.pointerId); } catch {}
261
+ };
262
+ const onPillMove = (e) => {
263
+ const d = pillDragRef.current;
264
+ if (!d) return;
265
+ const dx = e.clientX - d.x;
266
+ const dy = e.clientY - d.y;
267
+ if (!d.moved && Math.abs(dx) + Math.abs(dy) > 6) d.moved = true;
268
+ if (!d.moved) return;
269
+ const left = Math.max(4, Math.min(window.innerWidth - 60, d.left + dx));
270
+ const top = Math.max(4, Math.min(window.innerHeight - 40, d.top + dy));
271
+ pillPosRef.current = { left, top };
272
+ setPillPos({ left, top });
273
+ };
274
+ const onPillUp = (e) => {
275
+ const d = pillDragRef.current;
276
+ pillDragRef.current = null;
277
+ try { e.currentTarget.releasePointerCapture(e.pointerId); } catch {}
278
+ if (!d || !d.moved) return;
279
+ pillDraggedRef.current = true;
280
+ const pos = pillPosRef.current;
281
+ if (pos) { try { localStorage.setItem("dsh-scroll-piano:pillPos", JSON.stringify(pos)); } catch {} }
282
+ // 拖完不一定紧跟 click → 400ms 自动清,别吞掉下一次真正点击
283
+ if (pillClearRef.current) window.clearTimeout(pillClearRef.current);
284
+ pillClearRef.current = window.setTimeout(() => { pillDraggedRef.current = false; }, 400);
285
+ };
244
286
  const settingsRef = useRef(settings);
245
287
  settingsRef.current = settings;
246
288
  const lastMidiRef = useRef(null);
@@ -468,9 +510,19 @@ window.__ModuleLoader__.load({
468
510
  ),
469
511
  h("div", { ref: textRef, className: "dshscp_prevText" })
470
512
  ),
471
- h("div", { className: "dshscp_pill" },
513
+ h("div", {
514
+ className: "dshscp_pill",
515
+ onPointerDown: onPillDown,
516
+ onPointerMove: onPillMove,
517
+ onPointerUp: onPillUp,
518
+ onPointerCancel: onPillUp,
519
+ style: pillPos ? { left: pillPos.left + "px", top: pillPos.top + "px", bottom: "auto" } : undefined
520
+ },
472
521
  h("button", {
473
- onClick: () => setOn(!settings.on),
522
+ onClick: () => {
523
+ if (pillDraggedRef.current) { pillDraggedRef.current = false; return; } // 刚才是拖,不是点
524
+ setOn(!settings.on);
525
+ },
474
526
  title: settings.on ? "关闭滚动钢琴" : "开启滚动钢琴"
475
527
  },
476
528
  h("span", { className: "dshscp_dot" + (settings.on ? " dshscp_dotOn" : "") }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-scroll-piano",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "滚动钢琴:鼠标滑过 DSH 右侧边缘的滚动条竖条时,按纵向位置发出钢琴音(越高音越高,特雷门琴式)。",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -49,11 +49,13 @@
49
49
  },
50
50
  "compatibility": {
51
51
  "dshReleases": {
52
- "0.2.0-rc.2": "compatible"
52
+ "0.2.0-rc.2": "compatible",
53
+ "0.2.1-rc.2": "compatible",
54
+ "0.2.2-rc.1": "compatible"
53
55
  }
54
56
  }
55
57
  },
56
58
  "scripts": {
57
59
  "test": "node test/bundle-check.mjs"
58
60
  }
59
- }
61
+ }