dsh-music-panel 0.3.10 → 0.3.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.11
4
+
5
+ ### 变更
6
+
7
+ - 播放列表面板支持拖动移动位置:拖动顶部正在播放条/标题区即可,位置记在偏好里,下次打开恢复
8
+ - 播放列表面板内禁用文本框选(`user-select: none`)
9
+
3
10
  ## 0.3.10
4
11
 
5
12
  ### 变更
package/client.js CHANGED
@@ -33,6 +33,7 @@ window.__ModuleLoader__.load({
33
33
  /** Defaults for every appearance / lyric preference. */
34
34
  var PREF_DEFAULTS = {
35
35
  miniPlayer: true,
36
+ queuePos: null,
36
37
  composerQueueButton: true,
37
38
  circularCover: true,
38
39
  vinylRing: false,
@@ -2124,6 +2125,12 @@ window.__ModuleLoader__.load({
2124
2125
  function QueueOverlay() {
2125
2126
  var [open, setOpen] = useState(queueOverlaySnapshot())
2126
2127
  var [snap, setSnap] = useState(player.getSnapshot())
2128
+ var [pos, setPos] = useState(function () {
2129
+ var saved = readPrefs().queuePos
2130
+ if (saved === null || typeof saved !== 'object') return null
2131
+ if (!isFinite(saved.x) || !isFinite(saved.y)) return null
2132
+ return { x: Number(saved.x), y: Number(saved.y) }
2133
+ })
2127
2134
  // Drag state lives entirely in refs/DOM classes so React never
2128
2135
  // re-renders the dragged row mid-drag (Chromium cancels that).
2129
2136
  var dragFromRef = useRef(null)
@@ -2245,6 +2252,73 @@ window.__ModuleLoader__.load({
2245
2252
  document.addEventListener('pointercancel', onUp)
2246
2253
  }
2247
2254
 
2255
+ // Drag the whole panel by its header strip (buttons and queue rows keep
2256
+ // their own gestures). Position is remembered in prefs.
2257
+ function startPanelDrag(event) {
2258
+ if (event.button !== undefined && event.button !== 0) return
2259
+ var target = event.target
2260
+ if (target === null || target === undefined || typeof target.closest !== 'function') return
2261
+ if (target.closest('button, .mu-queue-row, .mu-queue-grip') !== null) return
2262
+ if (target.closest('.mu-qoverlay-now, .mu-qoverlay-head') === null) return
2263
+ var el = ref.current
2264
+ if (el === null) return
2265
+ var rect = el.getBoundingClientRect()
2266
+ var start = {
2267
+ x: event.clientX,
2268
+ y: event.clientY,
2269
+ left: rect.left,
2270
+ top: rect.top,
2271
+ width: rect.width,
2272
+ height: rect.height,
2273
+ moved: false,
2274
+ }
2275
+ event.preventDefault()
2276
+ document.body.style.userSelect = 'none'
2277
+ document.body.style.cursor = 'grabbing'
2278
+ el.classList.add('is-dragging-panel')
2279
+
2280
+ function clamp(value, min, max) {
2281
+ return Math.max(min, Math.min(max, value))
2282
+ }
2283
+
2284
+ function onMove(moveEvent) {
2285
+ start.moved = true
2286
+ var x = clamp(
2287
+ start.left + (moveEvent.clientX - start.x),
2288
+ 8,
2289
+ Math.max(8, window.innerWidth - start.width - 8),
2290
+ )
2291
+ var y = clamp(
2292
+ start.top + (moveEvent.clientY - start.y),
2293
+ 8,
2294
+ Math.max(8, window.innerHeight - start.height - 8),
2295
+ )
2296
+ el.style.left = x + 'px'
2297
+ el.style.top = y + 'px'
2298
+ el.style.right = 'auto'
2299
+ el.style.bottom = 'auto'
2300
+ }
2301
+
2302
+ function onUp() {
2303
+ document.removeEventListener('pointermove', onMove)
2304
+ document.removeEventListener('pointerup', onUp)
2305
+ document.removeEventListener('pointercancel', onUp)
2306
+ document.body.style.userSelect = ''
2307
+ document.body.style.cursor = ''
2308
+ el.classList.remove('is-dragging-panel')
2309
+ if (start.moved) {
2310
+ var next = el.getBoundingClientRect()
2311
+ var position = { x: Math.round(next.left), y: Math.round(next.top) }
2312
+ setPos(position)
2313
+ savePrefs({ queuePos: position })
2314
+ }
2315
+ }
2316
+
2317
+ document.addEventListener('pointermove', onMove)
2318
+ document.addEventListener('pointerup', onUp)
2319
+ document.addEventListener('pointercancel', onUp)
2320
+ }
2321
+
2248
2322
  var rows = queueView.map(function (entry, position) {
2249
2323
  var track = entry.track
2250
2324
  var originalIndex = entry.originalIndex
@@ -2299,7 +2373,17 @@ window.__ModuleLoader__.load({
2299
2373
 
2300
2374
  return h(
2301
2375
  'div',
2302
- { className: 'mu-qoverlay', ref: ref },
2376
+ {
2377
+ className: 'mu-qoverlay',
2378
+ ref: ref,
2379
+ style:
2380
+ pos !== null
2381
+ ? { left: pos.x + 'px', top: pos.y + 'px', right: 'auto', bottom: 'auto' }
2382
+ : undefined,
2383
+ onPointerDown: function (event) {
2384
+ startPanelDrag(event)
2385
+ },
2386
+ },
2303
2387
  h(QueueNowPlaying, null),
2304
2388
  h(
2305
2389
  'div',
@@ -5527,7 +5611,10 @@ window.__ModuleLoader__.load({
5527
5611
  '.mu-bar-right{display:flex;align-items:center;gap:6px;justify-self:end}',
5528
5612
  '.mu-quality{font-size:12px;color:var(--dsw-alias-label-tertiary,#a1a1aa);font-variant-numeric:tabular-nums;white-space:nowrap}',
5529
5613
  '.mu-pop{position:absolute;right:16px;bottom:84px;z-index:40;width:330px;max-height:58%;display:flex;flex-direction:column;border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-1,#1a1a1e);border:.5px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));box-shadow:var(--dsw-elevation-prominent,0 16px 48px rgba(0,0,0,.5));overflow:hidden}',
5530
- '.mu-qoverlay{position:fixed;right:24px;bottom:96px;z-index:70;width:360px;max-width:calc(100vw - 48px);max-height:62vh;display:flex;flex-direction:column;border:.5px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));border-radius:14px;background:var(--dsw-alias-bg-layer-1,#1a1a1e);box-shadow:var(--dsw-elevation-prominent,0 16px 48px rgba(0,0,0,.5));overflow:hidden}',
5614
+ '.mu-qoverlay{position:fixed;right:24px;bottom:96px;z-index:70;width:360px;max-width:calc(100vw - 48px);max-height:62vh;display:flex;flex-direction:column;border:.5px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));border-radius:14px;background:var(--dsw-alias-bg-layer-1,#1a1a1e);box-shadow:var(--dsw-elevation-prominent,0 16px 48px rgba(0,0,0,.5));overflow:hidden;user-select:none}',
5615
+ '.mu-qoverlay.is-dragging-panel{cursor:grabbing}',
5616
+ '.mu-qoverlay-now,.mu-qoverlay-head{cursor:grab}',
5617
+ '.mu-qoverlay-now:active,.mu-qoverlay-head:active{cursor:grabbing}',
5531
5618
  '.mu-qoverlay-now{display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:.5px solid var(--dsw-alias-border-l1,rgba(255,255,255,.08))}',
5532
5619
  '.mu-qoverlay-now.is-empty{padding:14px 12px;color:var(--dsw-alias-label-tertiary,#8a8a93);font-size:12px}',
5533
5620
  '.mu-qoverlay-now-main{flex:1;min-width:0}',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-music-panel",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "type": "module",
5
5
  "description": "Local music library for DeepSeek Harness: scan a folder, browse tracks with cover art and tags, and play through a sidebar-panel player with loop, shuffle and volume. · DSH 本地音乐插件:扫描音乐目录、读取封面与标签、侧栏入口 + 全屏播放器。",
6
6
  "license": "MIT",