dsh-music-panel 0.3.7 → 0.3.9
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 +14 -0
- package/client.js +107 -50
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.9
|
|
4
|
+
|
|
5
|
+
### 修复
|
|
6
|
+
|
|
7
|
+
- 播放队列拖拽改为 Pointer Events 实现(参考 DSH 侧栏行拖拽的落点语义 + SortableJS 的 pointer 方案):此前 HTML5 dragstart 在 composer 宿主浮层内不触发,导致松手后顺序不变
|
|
8
|
+
- 按住行左侧 `⋮⋮` 手柄拖动即可;拖拽中目标行显示插入线,松手立即重排;拖拽后不会误触发行的点击跳转
|
|
9
|
+
|
|
10
|
+
## 0.3.8
|
|
11
|
+
|
|
12
|
+
### 修复
|
|
13
|
+
|
|
14
|
+
- 修复播放队列拖拽松手后顺序不变:dragstart 中不再同步 setState(避免 Chromium 取消拖拽),拖拽源索引用 ref 记录
|
|
15
|
+
- 拖到行与行之间的空隙也能落位(容器兜底按指针位置计算目标行)
|
|
16
|
+
|
|
3
17
|
## 0.3.7
|
|
4
18
|
|
|
5
19
|
### 变更
|
package/client.js
CHANGED
|
@@ -2124,9 +2124,13 @@ window.__ModuleLoader__.load({
|
|
|
2124
2124
|
function QueueOverlay() {
|
|
2125
2125
|
var [open, setOpen] = useState(queueOverlaySnapshot())
|
|
2126
2126
|
var [snap, setSnap] = useState(player.getSnapshot())
|
|
2127
|
-
|
|
2128
|
-
|
|
2127
|
+
// Drag state lives entirely in refs/DOM classes so React never
|
|
2128
|
+
// re-renders the dragged row mid-drag (Chromium cancels that).
|
|
2129
|
+
var dragFromRef = useRef(null)
|
|
2130
|
+
var dragOverRef = useRef(null)
|
|
2131
|
+
var suppressClickRef = useRef(0)
|
|
2129
2132
|
var ref = useRef(null)
|
|
2133
|
+
var listRef = useRef(null)
|
|
2130
2134
|
|
|
2131
2135
|
useEffect(function () {
|
|
2132
2136
|
return subscribeQueueOverlay(function () {
|
|
@@ -2157,6 +2161,90 @@ window.__ModuleLoader__.load({
|
|
|
2157
2161
|
|
|
2158
2162
|
if (!open) return null
|
|
2159
2163
|
var queueView = buildQueueView(snap, player.getPlayOrder())
|
|
2164
|
+
|
|
2165
|
+
function clearDragMarks() {
|
|
2166
|
+
var list = listRef.current
|
|
2167
|
+
if (list === null) return
|
|
2168
|
+
var rowEls = list.querySelectorAll('.mu-queue-row')
|
|
2169
|
+
for (var i = 0; i < rowEls.length; i += 1) {
|
|
2170
|
+
rowEls[i].classList.remove('is-dragging', 'is-drop-target')
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
function moveRow(from, to) {
|
|
2175
|
+
if (from === null || from === to || from < 0 || to < 0) return
|
|
2176
|
+
if (from >= queueView.length || to >= queueView.length) return
|
|
2177
|
+
var order = queueView.map(function (item) {
|
|
2178
|
+
return item.originalIndex
|
|
2179
|
+
})
|
|
2180
|
+
var moved = order.splice(from, 1)[0]
|
|
2181
|
+
order.splice(to, 0, moved)
|
|
2182
|
+
player.reorderQueue(order)
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// Pointer-driven reorder (SortableJS' approach). The harness hosts this
|
|
2186
|
+
// overlay inside the composer area, where HTML5 dragstart is unreliable;
|
|
2187
|
+
// DSH's sidebar rows use HTML5 DnD with a custom drag preview, so this
|
|
2188
|
+
// keeps the same before/after marker semantics but with pointer events.
|
|
2189
|
+
var dragMoved = false
|
|
2190
|
+
function startDrag(event, position) {
|
|
2191
|
+
if (event.button !== undefined && event.button !== 0) return
|
|
2192
|
+
event.preventDefault()
|
|
2193
|
+
event.stopPropagation()
|
|
2194
|
+
var list = listRef.current
|
|
2195
|
+
if (list === null) return
|
|
2196
|
+
dragFromRef.current = position
|
|
2197
|
+
dragOverRef.current = position
|
|
2198
|
+
dragMoved = false
|
|
2199
|
+
var sourceRow = event.currentTarget.closest('.mu-queue-row')
|
|
2200
|
+
if (sourceRow !== null) sourceRow.classList.add('is-dragging')
|
|
2201
|
+
document.body.style.userSelect = 'none'
|
|
2202
|
+
|
|
2203
|
+
function mark(target) {
|
|
2204
|
+
dragOverRef.current = target
|
|
2205
|
+
var rowEls = list.querySelectorAll('.mu-queue-row')
|
|
2206
|
+
for (var i = 0; i < rowEls.length; i += 1) {
|
|
2207
|
+
rowEls[i].classList.toggle('is-drop-target', i === target)
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
function onMove(moveEvent) {
|
|
2212
|
+
dragMoved = true
|
|
2213
|
+
var rowEls = list.querySelectorAll('.mu-queue-row')
|
|
2214
|
+
if (rowEls.length === 0) return
|
|
2215
|
+
var target = rowEls.length - 1
|
|
2216
|
+
for (var i = 0; i < rowEls.length; i += 1) {
|
|
2217
|
+
var rect = rowEls[i].getBoundingClientRect()
|
|
2218
|
+
if (moveEvent.clientY < rect.top + rect.height / 2) {
|
|
2219
|
+
target = i
|
|
2220
|
+
break
|
|
2221
|
+
}
|
|
2222
|
+
target = i
|
|
2223
|
+
}
|
|
2224
|
+
mark(target)
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
function onUp() {
|
|
2228
|
+
document.removeEventListener('pointermove', onMove)
|
|
2229
|
+
document.removeEventListener('pointerup', onUp)
|
|
2230
|
+
document.removeEventListener('pointercancel', onUp)
|
|
2231
|
+
document.body.style.userSelect = ''
|
|
2232
|
+
var from = dragFromRef.current
|
|
2233
|
+
var to = dragOverRef.current
|
|
2234
|
+
dragFromRef.current = null
|
|
2235
|
+
dragOverRef.current = null
|
|
2236
|
+
clearDragMarks()
|
|
2237
|
+
if (dragMoved && from !== null && to !== null) {
|
|
2238
|
+
suppressClickRef.current = Date.now() + 250
|
|
2239
|
+
moveRow(from, to)
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
document.addEventListener('pointermove', onMove)
|
|
2244
|
+
document.addEventListener('pointerup', onUp)
|
|
2245
|
+
document.addEventListener('pointercancel', onUp)
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2160
2248
|
var rows = queueView.map(function (entry, position) {
|
|
2161
2249
|
var track = entry.track
|
|
2162
2250
|
var originalIndex = entry.originalIndex
|
|
@@ -2165,57 +2253,23 @@ window.__ModuleLoader__.load({
|
|
|
2165
2253
|
'div',
|
|
2166
2254
|
{
|
|
2167
2255
|
key: position + ':' + track.path,
|
|
2168
|
-
className:
|
|
2169
|
-
'mu-queue-row' +
|
|
2170
|
-
(visibleCurrent ? ' is-current' : '') +
|
|
2171
|
-
(dragFrom === position ? ' is-dragging' : '') +
|
|
2172
|
-
(dragOver === position && dragFrom !== position ? ' is-drop-target' : ''),
|
|
2173
|
-
draggable: true,
|
|
2256
|
+
className: 'mu-queue-row' + (visibleCurrent ? ' is-current' : ''),
|
|
2174
2257
|
onClick: function () {
|
|
2258
|
+
if (Date.now() < suppressClickRef.current) return
|
|
2175
2259
|
player.select(snap.queue, originalIndex)
|
|
2176
2260
|
},
|
|
2177
|
-
onDragStart: function (event) {
|
|
2178
|
-
setDragFrom(position)
|
|
2179
|
-
setDragOver(position)
|
|
2180
|
-
if (event.dataTransfer !== null && event.dataTransfer !== undefined) {
|
|
2181
|
-
event.dataTransfer.effectAllowed = 'move'
|
|
2182
|
-
try {
|
|
2183
|
-
event.dataTransfer.setData('text/plain', String(position))
|
|
2184
|
-
} catch (error) {
|
|
2185
|
-
// ignore
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
},
|
|
2189
|
-
onDragOver: function (event) {
|
|
2190
|
-
event.preventDefault()
|
|
2191
|
-
if (event.dataTransfer !== null && event.dataTransfer !== undefined) {
|
|
2192
|
-
event.dataTransfer.dropEffect = 'move'
|
|
2193
|
-
}
|
|
2194
|
-
if (dragOver !== position) setDragOver(position)
|
|
2195
|
-
},
|
|
2196
|
-
onDragLeave: function () {
|
|
2197
|
-
if (dragOver === position) setDragOver(null)
|
|
2198
|
-
},
|
|
2199
|
-
onDrop: function (event) {
|
|
2200
|
-
event.preventDefault()
|
|
2201
|
-
var from = dragFrom
|
|
2202
|
-
if (from !== null && from !== position) {
|
|
2203
|
-
var order = queueView.map(function (item) {
|
|
2204
|
-
return item.originalIndex
|
|
2205
|
-
})
|
|
2206
|
-
var moved = order.splice(from, 1)[0]
|
|
2207
|
-
order.splice(position, 0, moved)
|
|
2208
|
-
player.reorderQueue(order)
|
|
2209
|
-
}
|
|
2210
|
-
setDragFrom(null)
|
|
2211
|
-
setDragOver(null)
|
|
2212
|
-
},
|
|
2213
|
-
onDragEnd: function () {
|
|
2214
|
-
setDragFrom(null)
|
|
2215
|
-
setDragOver(null)
|
|
2216
|
-
},
|
|
2217
2261
|
},
|
|
2218
|
-
h(
|
|
2262
|
+
h(
|
|
2263
|
+
'span',
|
|
2264
|
+
{
|
|
2265
|
+
className: 'mu-queue-grip',
|
|
2266
|
+
title: t('page.dragSort'),
|
|
2267
|
+
onPointerDown: function (event) {
|
|
2268
|
+
startDrag(event, position)
|
|
2269
|
+
},
|
|
2270
|
+
},
|
|
2271
|
+
'⋮⋮',
|
|
2272
|
+
),
|
|
2219
2273
|
h(
|
|
2220
2274
|
'span',
|
|
2221
2275
|
{ className: 'mu-queue-index' },
|
|
@@ -2260,7 +2314,10 @@ window.__ModuleLoader__.load({
|
|
|
2260
2314
|
),
|
|
2261
2315
|
h(
|
|
2262
2316
|
'div',
|
|
2263
|
-
{
|
|
2317
|
+
{
|
|
2318
|
+
className: 'mu-qoverlay-list',
|
|
2319
|
+
ref: listRef,
|
|
2320
|
+
},
|
|
2264
2321
|
snap.queue.length === 0 ? h('div', { className: 'mu-state-sub' }, t('page.queueEmpty')) : rows,
|
|
2265
2322
|
),
|
|
2266
2323
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-music-panel",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
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",
|