From 5349ae3871efa9bf083bb368397fb0a2a4701aab Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Tue, 11 Nov 2025 20:19:34 -0800 Subject: [PATCH] hero design --- webui/index.html | 16 +++ webui/static/script.js | 78 +++++++++++++- webui/static/style.css | 234 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 298 insertions(+), 30 deletions(-) diff --git a/webui/index.html b/webui/index.html index 9c462bbe..b40a19f6 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1628,12 +1628,25 @@
+ + + + +
FEATURED ARTIST

Loading...

Discover new music tailored to your taste

+
+ + +
diff --git a/webui/static/script.js b/webui/static/script.js index ce7fae39..ce6a0480 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -24478,8 +24478,10 @@ function displayDiscoverHeroArtist(artist) { bgEl.style.backgroundPosition = 'center'; } - // Store artist ID for watchlist button and update its state + // Store artist ID for both buttons and update watchlist state const addBtn = document.getElementById('discover-hero-add'); + const discographyBtn = document.getElementById('discover-hero-discography'); + if (addBtn && artist.spotify_artist_id) { addBtn.setAttribute('data-artist-id', artist.spotify_artist_id); addBtn.setAttribute('data-artist-name', artist.artist_name); @@ -24487,6 +24489,14 @@ function displayDiscoverHeroArtist(artist) { // Check if this artist is already in watchlist and update button appearance checkAndUpdateDiscoverHeroWatchlistButton(artist.spotify_artist_id); } + + if (discographyBtn && artist.spotify_artist_id) { + discographyBtn.setAttribute('data-artist-id', artist.spotify_artist_id); + discographyBtn.setAttribute('data-artist-name', artist.artist_name); + } + + // Update slideshow indicators + updateDiscoverHeroIndicators(); } async function checkAndUpdateDiscoverHeroWatchlistButton(artistId) { @@ -24540,6 +24550,72 @@ function toggleDiscoverHeroWatchlist(event) { toggleWatchlist(event, artistId, artistName); } +function navigateDiscoverHero(direction) { + if (!discoverHeroArtists || discoverHeroArtists.length === 0) return; + + // Update index with wrapping + discoverHeroIndex = (discoverHeroIndex + direction + discoverHeroArtists.length) % discoverHeroArtists.length; + + // Display the artist + displayDiscoverHeroArtist(discoverHeroArtists[discoverHeroIndex]); + + // Update indicators + updateDiscoverHeroIndicators(); +} + +function updateDiscoverHeroIndicators() { + const indicatorsContainer = document.getElementById('discover-hero-indicators'); + if (!indicatorsContainer || !discoverHeroArtists || discoverHeroArtists.length === 0) return; + + // Create indicator dots + indicatorsContainer.innerHTML = discoverHeroArtists.map((_, index) => ` + + `).join(''); +} + +function jumpToDiscoverHeroSlide(index) { + if (!discoverHeroArtists || index < 0 || index >= discoverHeroArtists.length) return; + + discoverHeroIndex = index; + displayDiscoverHeroArtist(discoverHeroArtists[discoverHeroIndex]); + updateDiscoverHeroIndicators(); +} + +async function viewDiscoverHeroDiscography() { + const button = document.getElementById('discover-hero-discography'); + if (!button) return; + + const artistId = button.getAttribute('data-artist-id'); + const artistName = button.getAttribute('data-artist-name'); + + if (!artistId || !artistName) { + console.error('No artist data found for discography view'); + return; + } + + // Create artist object matching the expected format + const artist = { + id: artistId, + name: artistName, + image_url: discoverHeroArtists[discoverHeroIndex]?.image_url || '', + genres: discoverHeroArtists[discoverHeroIndex]?.genres || [], + popularity: discoverHeroArtists[discoverHeroIndex]?.popularity || 0 + }; + + console.log(`🎵 Navigating to artist detail for: ${artistName}`); + + // Navigate to Artists page + navigateToPage('artists'); + + // Small delay to let the page load + await new Promise(resolve => setTimeout(resolve, 100)); + + // Load the artist details + await selectArtistForDetail(artist); +} + function showDiscoverHeroEmpty() { const titleEl = document.getElementById('discover-hero-title'); const subtitleEl = document.getElementById('discover-hero-subtitle'); diff --git a/webui/static/style.css b/webui/static/style.css index d2dabf05..79a4c615 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -16116,10 +16116,11 @@ body { .discover-hero { position: relative; width: 100%; - height: 500px; - border-radius: 12px; + height: 550px; + border-radius: 16px; overflow: hidden; margin-bottom: 40px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); } .discover-hero-background { @@ -16160,76 +16161,165 @@ body { } .discover-hero-label { - font-size: 12px; + font-size: 13px; font-weight: 700; - letter-spacing: 2px; + letter-spacing: 3px; color: #1db954; - margin-bottom: 12px; + margin-bottom: 16px; text-transform: uppercase; + display: inline-block; + padding: 6px 16px; + background: rgba(29, 185, 84, 0.15); + border-radius: 20px; + border: 1px solid rgba(29, 185, 84, 0.3); } .discover-hero-title { - font-size: 56px; - font-weight: 800; + font-size: 64px; + font-weight: 900; color: #fff; - margin: 0 0 16px 0; - line-height: 1.1; - text-shadow: 0 4px 12px rgba(0,0,0,0.4); + margin: 0 0 20px 0; + line-height: 1.05; + text-shadow: 0 4px 16px rgba(0,0,0,0.5); + letter-spacing: -1px; } .discover-hero-subtitle { - font-size: 18px; - color: rgba(255, 255, 255, 0.85); - margin-bottom: 32px; - line-height: 1.6; + font-size: 19px; + color: rgba(255, 255, 255, 0.9); + margin-bottom: 36px; + line-height: 1.7; + font-weight: 400; } .discover-hero-actions { display: flex; gap: 16px; + align-items: center; + flex-wrap: wrap; } .discover-hero-button { display: flex; align-items: center; - gap: 8px; - padding: 14px 32px; + gap: 10px; + padding: 16px 36px; border: none; border-radius: 50px; font-size: 16px; font-weight: 600; cursor: pointer; - transition: all 0.2s ease; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + position: relative; + overflow: hidden; + z-index: 1; } -.discover-hero-button.primary { +.discover-hero-button::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 255, 255, 0.2); + transform: translate(-50%, -50%); + transition: width 0.6s, height 0.6s; +} + +.discover-hero-button:hover::before { + width: 300px; + height: 300px; +} + +/* Discography button - prominent and large */ +.discover-hero-button.secondary { + background-color: rgba(255, 255, 255, 0.12); + color: #fff; + border: 2px solid rgba(255, 255, 255, 0.25); + backdrop-filter: blur(10px); + padding: 18px 48px !important; + font-size: 17px !important; + font-weight: 700 !important; + gap: 12px !important; +} + +.discover-hero-button.secondary .button-icon { + font-size: 20px !important; +} + +.discover-hero-button.secondary .button-text { + font-size: 17px !important; + font-weight: 700 !important; +} + +/* Watchlist button - smaller and subtle */ +.discover-hero-button.primary.watchlist-toggle-btn { background-color: #1db954; color: #fff; + padding: 9px 16px !important; + font-size: 13px !important; + font-weight: 600 !important; + gap: 6px !important; } -.discover-hero-button.primary:hover { +.discover-hero-button.primary.watchlist-toggle-btn .watchlist-icon { + font-size: 13px !important; +} + +.discover-hero-button.primary.watchlist-toggle-btn .watchlist-text { + flex: none !important; + text-align: left !important; + font-size: 13px !important; +} + +.discover-hero-button.primary.watchlist-toggle-btn:hover { background-color: #1ed760; - transform: scale(1.05); + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(29, 185, 84, 0.4); } -.discover-hero-button.secondary { - background-color: rgba(255, 255, 255, 0.1); - color: #fff; - border: 2px solid rgba(255, 255, 255, 0.3); +.discover-hero-button.primary.watchlist-toggle-btn:active { + transform: translateY(0); } .discover-hero-button.secondary:hover { background-color: rgba(255, 255, 255, 0.2); - border-color: rgba(255, 255, 255, 0.5); + border-color: rgba(255, 255, 255, 0.4); + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(255, 255, 255, 0.15); +} + +.discover-hero-button.secondary:active { + transform: translateY(0); +} + +.discover-hero-button.primary.watchlist-toggle-btn.watching { + background-color: rgba(29, 185, 84, 0.2) !important; + border: 2px solid rgba(29, 185, 84, 0.5) !important; + color: #1db954 !important; +} + +.discover-hero-button.primary.watchlist-toggle-btn.watching:hover { + background-color: rgba(29, 185, 84, 0.3) !important; + border-color: rgba(29, 185, 84, 0.7) !important; } .discover-hero-image { flex-shrink: 0; - width: 320px; - height: 320px; - border-radius: 12px; + width: 360px; + height: 360px; + border-radius: 16px; overflow: hidden; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); + box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6); + border: 3px solid rgba(255, 255, 255, 0.1); + transition: transform 0.3s ease; +} + +.discover-hero-image:hover { + transform: scale(1.02); } .hero-image-placeholder { @@ -16248,6 +16338,92 @@ body { object-fit: cover; } +/* Hero Navigation Arrows - Hidden by default, show on hover */ +.discover-hero-nav { + position: absolute; + top: 50%; + transform: translateY(-50%); + z-index: 10; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + color: #fff; + width: 50px; + height: 50px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.3s ease; + font-size: 28px; + line-height: 1; + padding: 0; + opacity: 0; + pointer-events: none; +} + +.discover-hero:hover .discover-hero-nav { + opacity: 1; + pointer-events: auto; +} + +.discover-hero-nav:hover { + background: rgba(0, 0, 0, 0.7); + border-color: rgba(255, 255, 255, 0.3); + transform: translateY(-50%) scale(1.1); +} + +.discover-hero-nav:active { + transform: translateY(-50%) scale(0.95); +} + +.discover-hero-nav-prev { + left: 20px; +} + +.discover-hero-nav-next { + right: 20px; +} + +/* Hero Slideshow Indicators */ +.discover-hero-indicators { + position: absolute; + bottom: 24px; + left: 50%; + transform: translateX(-50%); + z-index: 10; + display: flex; + gap: 10px; + padding: 12px 20px; + background: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(10px); + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.hero-indicator { + width: 8px; + height: 8px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.4); + border: none; + padding: 0; + cursor: pointer; + transition: all 0.3s ease; +} + +.hero-indicator:hover { + background: rgba(255, 255, 255, 0.7); + transform: scale(1.2); +} + +.hero-indicator.active { + background: #1db954; + width: 24px; + border-radius: 4px; +} + /* Discover Sections */ .discover-section { margin-bottom: 50px;