diff --git a/index.html b/index.html index 86e68be..8d00374 100644 --- a/index.html +++ b/index.html @@ -35,6 +35,21 @@
+ + + diff --git a/js/app.js b/js/app.js index 89af530..5e04325 100644 --- a/js/app.js +++ b/js/app.js @@ -251,9 +251,20 @@ document.addEventListener('DOMContentLoaded', async () => { // Clear sync when hiding 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) => { e.stopPropagation(); lyricsPanel.classList.add('hidden'); diff --git a/js/storage.js b/js/storage.js index 3c7250c..1ceb671 100644 --- a/js/storage.js +++ b/js/storage.js @@ -305,9 +305,9 @@ export const nowPlayingSettings = { getMode() { try { - return localStorage.getItem(this.STORAGE_KEY) || 'cover'; + return localStorage.getItem(this.STORAGE_KEY) || 'album'; } catch (e) { - return 'cover'; + return 'album'; } }, diff --git a/js/ui.js b/js/ui.js index 78fb887..ef8041b 100644 --- a/js/ui.js +++ b/js/ui.js @@ -259,6 +259,30 @@ export class UIRenderer { 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) { document.querySelectorAll('.page').forEach(page => { page.classList.toggle('active', page.id === `page-${pageId}`); diff --git a/styles.css b/styles.css index f945bcb..6575356 100644 --- a/styles.css +++ b/styles.css @@ -259,6 +259,8 @@ kbd { grid-template-columns: 1fr 2fr 1fr; align-items: center; gap: var(--spacing-xl); + position: relative; + z-index: 2100; } .sidebar-logo { @@ -1222,6 +1224,120 @@ input:checked + .slider::before { 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 { background-color: var(--card); width: 90%;