feat: implement enlarged cover view mode and make 'show album' default
This commit is contained in:
parent
95559f6614
commit
25c6f1e5fb
5 changed files with 170 additions and 3 deletions
18
index.html
18
index.html
|
|
@ -35,6 +35,21 @@
|
||||||
<div id="queue-list"></div>
|
<div id="queue-list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="fullscreen-cover-overlay" style="display: none;">
|
||||||
|
<div class="fullscreen-cover-content">
|
||||||
|
<button id="close-fullscreen-cover-btn" title="Close">×</button>
|
||||||
|
<img id="fullscreen-cover-image" src="" alt="Album Cover">
|
||||||
|
<div class="fullscreen-track-info">
|
||||||
|
<h2 id="fullscreen-track-title"></h2>
|
||||||
|
<h3 id="fullscreen-track-artist"></h3>
|
||||||
|
</div>
|
||||||
|
<div class="fullscreen-controls">
|
||||||
|
<!-- Controls will be cloned or managed here if needed, or we just rely on main controls -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="queue-track-menu" id="queue-track-menu">
|
<div class="queue-track-menu" id="queue-track-menu">
|
||||||
<ul>
|
<ul>
|
||||||
<li data-action="remove">Remove from Queue</li>
|
<li data-action="remove">Remove from Queue</li>
|
||||||
|
|
@ -299,7 +314,8 @@
|
||||||
<span class="description">Choose what shows when you click the album art</span>
|
<span class="description">Choose what shows when you click the album art</span>
|
||||||
</div>
|
</div>
|
||||||
<select id="now-playing-mode">
|
<select id="now-playing-mode">
|
||||||
<option value="cover">Album Cover</option>
|
<option value="album">Show Album</option>
|
||||||
|
<option value="cover">Enlarged Cover</option>
|
||||||
<option value="lyrics">Lyrics Panel</option>
|
<option value="lyrics">Lyrics Panel</option>
|
||||||
<option value="karaoke">Karaoke Mode</option>
|
<option value="karaoke">Karaoke Mode</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
11
js/app.js
11
js/app.js
|
|
@ -251,9 +251,20 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
// Clear sync when hiding
|
// Clear sync when hiding
|
||||||
clearLyricsPanelSync(audioPlayer, lyricsPanel);
|
clearLyricsPanelSync(audioPlayer, lyricsPanel);
|
||||||
}
|
}
|
||||||
|
} else if (mode === 'cover') {
|
||||||
|
ui.showFullscreenCover(player.currentTrack);
|
||||||
|
} else {
|
||||||
|
// Default to 'album' mode - navigate to album
|
||||||
|
if (player.currentTrack.album?.id) {
|
||||||
|
window.location.hash = `#album/${player.currentTrack.album.id}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('close-fullscreen-cover-btn')?.addEventListener('click', () => {
|
||||||
|
ui.closeFullscreenCover();
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById('close-lyrics-btn')?.addEventListener('click', (e) => {
|
document.getElementById('close-lyrics-btn')?.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
lyricsPanel.classList.add('hidden');
|
lyricsPanel.classList.add('hidden');
|
||||||
|
|
|
||||||
|
|
@ -305,9 +305,9 @@ export const nowPlayingSettings = {
|
||||||
|
|
||||||
getMode() {
|
getMode() {
|
||||||
try {
|
try {
|
||||||
return localStorage.getItem(this.STORAGE_KEY) || 'cover';
|
return localStorage.getItem(this.STORAGE_KEY) || 'album';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return 'cover';
|
return 'album';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
24
js/ui.js
24
js/ui.js
|
|
@ -259,6 +259,30 @@ export class UIRenderer {
|
||||||
root.style.removeProperty('--ring');
|
root.style.removeProperty('--ring');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showFullscreenCover(track) {
|
||||||
|
if (!track) return;
|
||||||
|
|
||||||
|
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||||
|
const image = document.getElementById('fullscreen-cover-image');
|
||||||
|
const title = document.getElementById('fullscreen-track-title');
|
||||||
|
const artist = document.getElementById('fullscreen-track-artist');
|
||||||
|
|
||||||
|
const coverUrl = this.api.getCoverUrl(track.album?.cover, '1280');
|
||||||
|
|
||||||
|
image.src = coverUrl;
|
||||||
|
title.textContent = track.title;
|
||||||
|
artist.textContent = track.artist?.name || 'Unknown Artist';
|
||||||
|
|
||||||
|
// Set the background image via CSS variable for the pseudo-element to use
|
||||||
|
overlay.style.setProperty('--bg-image', `url('${coverUrl}')`);
|
||||||
|
|
||||||
|
overlay.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
closeFullscreenCover() {
|
||||||
|
document.getElementById('fullscreen-cover-overlay').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
showPage(pageId) {
|
showPage(pageId) {
|
||||||
document.querySelectorAll('.page').forEach(page => {
|
document.querySelectorAll('.page').forEach(page => {
|
||||||
page.classList.toggle('active', page.id === `page-${pageId}`);
|
page.classList.toggle('active', page.id === `page-${pageId}`);
|
||||||
|
|
|
||||||
116
styles.css
116
styles.css
|
|
@ -259,6 +259,8 @@ kbd {
|
||||||
grid-template-columns: 1fr 2fr 1fr;
|
grid-template-columns: 1fr 2fr 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-xl);
|
gap: var(--spacing-xl);
|
||||||
|
position: relative;
|
||||||
|
z-index: 2100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-logo {
|
||||||
|
|
@ -1222,6 +1224,120 @@ input:checked + .slider::before {
|
||||||
animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#fullscreen-cover-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 2000;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
animation: fadeIn 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000; /* Solid background to prevent see-through */
|
||||||
|
/* Use a CSS variable for the image so we can set it in JS */
|
||||||
|
--bg-image: none;
|
||||||
|
padding-bottom: 90px; /* Account for desktop player bar */
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-cover-overlay::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: -20px;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
filter: blur(30px) brightness(0.4);
|
||||||
|
z-index: -1;
|
||||||
|
background-image: var(--bg-image);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-cover-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* Remove fixed padding to allow flex centering to work within the overlay's padded box */
|
||||||
|
padding: 1rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#close-fullscreen-cover-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 2rem;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#close-fullscreen-cover-btn:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-cover-image {
|
||||||
|
max-width: 80vw;
|
||||||
|
max-height: 60vh;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
|
||||||
|
object-fit: contain;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-track-info {
|
||||||
|
text-align: center;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-track-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: #ffffff;
|
||||||
|
text-shadow: 0 2px 10px rgba(0,0,0,0.5);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-track-artist {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-weight: 500;
|
||||||
|
text-shadow: 0 2px 10px rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
#fullscreen-cover-overlay {
|
||||||
|
padding-bottom: 160px; /* Account for taller mobile player bar */
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-cover-image {
|
||||||
|
max-height: 45vh; /* Reduce height on mobile to fit text */
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-track-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fullscreen-track-artist {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#queue-modal {
|
#queue-modal {
|
||||||
background-color: var(--card);
|
background-color: var(--card);
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue