improvements
This commit is contained in:
parent
d296652995
commit
aeea0038f3
6 changed files with 39 additions and 8 deletions
|
|
@ -32,7 +32,10 @@
|
|||
<div id="queue-modal">
|
||||
<div id="queue-modal-header">
|
||||
<h3>Queue</h3>
|
||||
<button id="close-queue-btn">×</button>
|
||||
<div style="display: flex; gap: 0.5rem; align-items: center;">
|
||||
<button id="clear-queue-btn" class="btn-secondary">Clear All</button>
|
||||
<button id="close-queue-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="queue-list"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -250,9 +250,14 @@ function initializeSmoothSliders(audioPlayer, player) {
|
|||
progressBar.addEventListener('click', e => {
|
||||
if (!isSeeking) {
|
||||
seek(progressBar, e, position => {
|
||||
if (!isNaN(audioPlayer.duration)) {
|
||||
if (!isNaN(audioPlayer.duration) && audioPlayer.duration > 0 && audioPlayer.duration !== Infinity) {
|
||||
audioPlayer.currentTime = position * audioPlayer.duration;
|
||||
player.updateMediaSessionPositionState();
|
||||
} else if (player.currentTrack && player.currentTrack.duration) {
|
||||
const targetTime = position * player.currentTrack.duration;
|
||||
const progressFill = document.querySelector('.progress-fill');
|
||||
if (progressFill) progressFill.style.width = `${position * 100}%`;
|
||||
player.playTrackFromQueue(targetTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -310,7 +315,7 @@ export async function handleTrackAction(action, item, player, api, lyricsManager
|
|||
// Update all instances of this item's like button on the page
|
||||
const id = type === 'playlist' ? item.uuid : item.id;
|
||||
const selector = type === 'track'
|
||||
? `.track-item[data-track-id="${id}"] .like-btn`
|
||||
? `[data-track-id="${id}"] .like-btn`
|
||||
: `.card[data-${type}-id="${id}"] .like-btn, .card[data-playlist-id="${id}"] .like-btn`;
|
||||
|
||||
// Also check header buttons
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ export class Player {
|
|||
if (coverEl) coverEl.src = this.api.getCoverUrl(track.album?.cover, '1280');
|
||||
if (titleEl) titleEl.textContent = trackTitle;
|
||||
if (artistEl) artistEl.textContent = trackArtists;
|
||||
const totalDurationEl = document.getElementById('total-duration');
|
||||
if (totalDurationEl) totalDurationEl.textContent = formatTime(track.duration);
|
||||
document.title = `${trackTitle} • ${track.artist?.name || 'Unknown'}`;
|
||||
|
||||
this.updatePlayingTrackIndicator();
|
||||
|
|
@ -154,7 +156,7 @@ export class Player {
|
|||
}
|
||||
}
|
||||
|
||||
async playTrackFromQueue() {
|
||||
async playTrackFromQueue(startTime = 0) {
|
||||
const currentQueue = this.shuffleActive ? this.shuffledQueue : this.queue;
|
||||
if (this.currentQueueIndex < 0 || this.currentQueueIndex >= currentQueue.length) {
|
||||
return;
|
||||
|
|
@ -193,6 +195,9 @@ export class Player {
|
|||
}
|
||||
|
||||
this.audio.src = streamUrl;
|
||||
if (startTime > 0) {
|
||||
this.audio.currentTime = startTime;
|
||||
}
|
||||
await this.audio.play();
|
||||
|
||||
this.updateMediaSessionPlaybackState();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//js/ui-interactions.js
|
||||
import { SVG_CLOSE, formatTime, trackDataStore, getTrackTitle, getTrackArtists } from './utils.js';
|
||||
import { SVG_CLOSE, SVG_BIN, formatTime, trackDataStore, getTrackTitle, getTrackArtists } from './utils.js';
|
||||
|
||||
export function initializeUIInteractions(player, api) {
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
|
|
@ -8,6 +8,7 @@ export function initializeUIInteractions(player, api) {
|
|||
const queueBtn = document.getElementById('queue-btn');
|
||||
const queueModalOverlay = document.getElementById('queue-modal-overlay');
|
||||
const closeQueueBtn = document.getElementById('close-queue-btn');
|
||||
const clearQueueBtn = document.getElementById('clear-queue-btn');
|
||||
const queueList = document.getElementById('queue-list');
|
||||
|
||||
let draggedQueueIndex = null;
|
||||
|
|
@ -40,6 +41,13 @@ export function initializeUIInteractions(player, api) {
|
|||
closeQueueBtn.addEventListener('click', () => {
|
||||
queueModalOverlay.style.display = 'none';
|
||||
});
|
||||
|
||||
if (clearQueueBtn) {
|
||||
clearQueueBtn.addEventListener('click', () => {
|
||||
player.clearQueue();
|
||||
renderQueue();
|
||||
});
|
||||
}
|
||||
|
||||
queueModalOverlay.addEventListener('click', e => {
|
||||
if (e.target === queueModalOverlay) {
|
||||
|
|
@ -50,6 +58,10 @@ export function initializeUIInteractions(player, api) {
|
|||
function renderQueue() {
|
||||
const currentQueue = player.getCurrentQueue();
|
||||
|
||||
if (clearQueueBtn) {
|
||||
clearQueueBtn.style.display = currentQueue.length > 0 ? 'block' : 'none';
|
||||
}
|
||||
|
||||
if (currentQueue.length === 0) {
|
||||
queueList.innerHTML = '<div class="placeholder-text">Queue is empty.</div>';
|
||||
return;
|
||||
|
|
@ -78,7 +90,7 @@ export function initializeUIInteractions(player, api) {
|
|||
</div>
|
||||
<div class="track-item-duration">${formatTime(track.duration)}</div>
|
||||
<button class="queue-remove-btn" data-track-index="${index}" title="Remove from queue">
|
||||
${SVG_CLOSE}
|
||||
${SVG_BIN}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export const SVG_DOWNLOAD = '<svg xmlns="http://www.w3.org/2000/svg" width="24"
|
|||
export const SVG_MENU = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="5" r="1"></circle><circle cx="12" cy="19" r="1"></circle></svg>';
|
||||
export const SVG_HEART = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="heart-icon"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>';
|
||||
export const SVG_CLOSE = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
|
||||
export const SVG_BIN = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>';
|
||||
|
||||
export const formatTime = (seconds) => {
|
||||
if (isNaN(seconds)) return '0:00';
|
||||
|
|
|
|||
|
|
@ -1520,7 +1520,7 @@ input:checked + .slider::before {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#queue-modal-header button {
|
||||
#queue-modal-header #close-queue-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--muted-foreground);
|
||||
|
|
@ -1535,7 +1535,12 @@ input:checked + .slider::before {
|
|||
transition: all var(--transition);
|
||||
}
|
||||
|
||||
#queue-modal-header button:hover {
|
||||
#queue-modal-header #clear-queue-btn {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#queue-modal-header #clear-queue-btn:hover,
|
||||
#queue-modal-header #close-queue-btn:hover {
|
||||
background-color: var(--secondary);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue