Improve web UI
This commit is contained in:
@@ -238,14 +238,15 @@ body {
|
|||||||
.queue-item .qi-info { flex: 1; overflow: hidden; }
|
.queue-item .qi-info { flex: 1; overflow: hidden; }
|
||||||
.queue-item .qi-title { font-size: 0.875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.queue-item .qi-title { font-size: 0.875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.queue-item .qi-artist { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.queue-item .qi-artist { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.queue-item .qi-dur { font-size: 0.72rem; color: var(--text-muted); flex-shrink: 0; }
|
.queue-item .qi-dur { font-size: 0.75rem; color: var(--text-muted); margin-left: auto; margin-right: 0.5rem; }
|
||||||
.queue-item .qi-remove {
|
.qi-remove, .qi-locate {
|
||||||
opacity: 0; font-size: 0.8rem; color: var(--text-muted);
|
background: none; border: none; font-size: 0.9rem;
|
||||||
background: none; border: none; cursor: pointer; padding: 2px 5px;
|
color: var(--text-muted); cursor: pointer; padding: 0.3rem;
|
||||||
border-radius: 4px; transition: all 0.15s;
|
border-radius: 4px; transition: all 0.2s; opacity: 0;
|
||||||
}
|
}
|
||||||
.queue-item:hover .qi-remove { opacity: 1; }
|
.queue-item:hover .qi-remove, .queue-item:hover .qi-locate { opacity: 1; }
|
||||||
.queue-item .qi-remove:hover { color: var(--danger); }
|
.qi-remove:hover { background: rgba(248,113,113,0.15); color: var(--danger); }
|
||||||
|
.qi-locate:hover { background: rgba(124,106,247,0.15); color: var(--primary); }
|
||||||
.queue-item.dragging { opacity: 0.5; background: var(--bg-active); }
|
.queue-item.dragging { opacity: 0.5; background: var(--bg-active); }
|
||||||
.queue-item.drag-over { border-top: 2px solid var(--accent); margin-top: -2px; }
|
.queue-item.drag-over { border-top: 2px solid var(--accent); margin-top: -2px; }
|
||||||
|
|
||||||
@@ -772,7 +773,7 @@ async function loadMeta(track) {
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const meta = await res.json();
|
const meta = await res.json();
|
||||||
metaCache[track.path] = meta;
|
metaCache[track.path] = meta;
|
||||||
track.meta = meta;
|
if (queue[idx]) { queue[idx].meta = meta; }
|
||||||
updateNowPlaying(track);
|
updateNowPlaying(track);
|
||||||
renderQueue();
|
renderQueue();
|
||||||
}
|
}
|
||||||
@@ -840,6 +841,7 @@ function renderQueue() {
|
|||||||
<div class="qi-artist">${esc(artist)}</div>
|
<div class="qi-artist">${esc(artist)}</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="qi-dur">${dur}</span>
|
<span class="qi-dur">${dur}</span>
|
||||||
|
<button class="qi-locate" title="Go to folder" onclick="locateTrack(${origIdx}, event)">📂</button>
|
||||||
<button class="qi-remove" title="Remove track" onclick="removeFromQueue(${origIdx}, event)">✕</button>
|
<button class="qi-remove" title="Remove track" onclick="removeFromQueue(${origIdx}, event)">✕</button>
|
||||||
`;
|
`;
|
||||||
div.addEventListener('click', () => playIndex(origIdx));
|
div.addEventListener('click', () => playIndex(origIdx));
|
||||||
@@ -878,22 +880,45 @@ function scrollQueueToActive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeFromQueue(origIdx, ev) {
|
function removeFromQueue(origIdx, ev) {
|
||||||
ev.stopPropagation();
|
if (ev) ev.stopPropagation();
|
||||||
|
const isPlaying = origIdx === queueIndex;
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
queueIndex = -1;
|
||||||
|
audio.pause();
|
||||||
|
audio.src = '';
|
||||||
|
updateNowPlaying();
|
||||||
|
} else if (queueIndex > origIdx) {
|
||||||
|
queueIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
queue.splice(origIdx, 1);
|
queue.splice(origIdx, 1);
|
||||||
if (queueIndex === origIdx) { queueIndex = -1; audio.pause(); audio.src = ''; }
|
|
||||||
else if (queueIndex > origIdx) queueIndex--;
|
|
||||||
|
|
||||||
if (shuffle) {
|
if (shuffle) {
|
||||||
const sidx = shuffleOrder.indexOf(origIdx);
|
const sidx = shuffleOrder.indexOf(origIdx);
|
||||||
if (sidx !== -1) shuffleOrder.splice(sidx, 1);
|
if (sidx !== -1) shuffleOrder.splice(sidx, 1);
|
||||||
for (let i = 0; i < shuffleOrder.length; i++) {
|
for (let i = 0; i < shuffleOrder.length; i++) {
|
||||||
if (shuffleOrder[i] > origIdx) shuffleOrder[i]--;
|
if (shuffleOrder[i] > origIdx) shuffleOrder[i]--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderQueue();
|
renderQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function locateTrack(idx, ev) {
|
||||||
|
if (ev) ev.stopPropagation();
|
||||||
|
const track = queue[idx];
|
||||||
|
if (!track) return;
|
||||||
|
const parts = track.path.split('/');
|
||||||
|
parts.pop(); // remove filename
|
||||||
|
const folder = parts.join('/');
|
||||||
|
navigate(folder);
|
||||||
|
if (window.innerWidth <= 768) {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
if (!sidebar.classList.contains('open')) toggleSidebar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function moveQueueItem(fromPos, toPos) {
|
function moveQueueItem(fromPos, toPos) {
|
||||||
if (fromPos === toPos) return;
|
if (fromPos === toPos) return;
|
||||||
|
|
||||||
@@ -1061,6 +1086,12 @@ const trackPath = urlParams.get('t');
|
|||||||
if (trackPath) {
|
if (trackPath) {
|
||||||
const parts = trackPath.split('/');
|
const parts = trackPath.split('/');
|
||||||
const name = parts[parts.length - 1];
|
const name = parts[parts.length - 1];
|
||||||
|
|
||||||
|
// Navigate to folder
|
||||||
|
const folderParts = [...parts];
|
||||||
|
folderParts.pop(); // remove name
|
||||||
|
navigate(folderParts.join('/'));
|
||||||
|
|
||||||
addToQueue(trackPath, name, true);
|
addToQueue(trackPath, name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user