diff --git a/static/css/album/album.css b/static/css/album/album.css index 0ecc305..47d77d7 100644 --- a/static/css/album/album.css +++ b/static/css/album/album.css @@ -4,26 +4,26 @@ padding: 0; box-sizing: border-box; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -body { - background-color: #121212; + } + + body { + background: linear-gradient(135deg, #121212, #1e1e1e); color: #ffffff; min-height: 100vh; line-height: 1.4; -} - -/* Main App Container */ -#app { + } + + /* Main App Container */ + #app { max-width: 1200px; margin: 0 auto; padding: 20px; position: relative; z-index: 1; -} - -/* Album Header */ -#album-header { + } + + /* Album Header */ + #album-header { display: flex; gap: 20px; margin-bottom: 2rem; @@ -31,41 +31,51 @@ body { padding-bottom: 1.5rem; border-bottom: 1px solid #2a2a2a; flex-wrap: wrap; -} - -#album-image { + transition: all 0.3s ease; + } + + #album-image { width: 200px; height: 200px; object-fit: cover; border-radius: 8px; flex-shrink: 0; -} - -#album-info { + box-shadow: 0 4px 8px rgba(0,0,0,0.3); + transition: transform 0.3s ease; + } + #album-image:hover { + transform: scale(1.02); + } + + #album-info { flex: 1; min-width: 0; -} - -#album-name { - font-size: 2rem; + } + + #album-name { + font-size: 2.5rem; margin-bottom: 0.5rem; -} - -#album-artist, -#album-stats, -#album-copyright { - font-size: 1rem; + background: linear-gradient(90deg, #1db954, #17a44b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + #album-artist, + #album-stats { + font-size: 1.1rem; color: #b3b3b3; margin-bottom: 0.5rem; -} - -#album-copyright { + } + + #album-copyright { font-size: 0.9rem; + color: #b3b3b3; opacity: 0.8; -} - -/* Playlist Header */ -#playlist-header { + margin-bottom: 0.5rem; + } + + /* Playlist Header */ + #playlist-header { display: flex; gap: 20px; margin-bottom: 2rem; @@ -73,55 +83,64 @@ body { padding-bottom: 1.5rem; border-bottom: 1px solid #2a2a2a; flex-wrap: wrap; -} - -#playlist-image { + transition: all 0.3s ease; + } + + #playlist-image { width: 200px; height: 200px; object-fit: cover; border-radius: 8px; flex-shrink: 0; -} - -#playlist-info { + box-shadow: 0 4px 8px rgba(0,0,0,0.3); + transition: transform 0.3s ease; + } + #playlist-image:hover { + transform: scale(1.02); + } + + #playlist-info { flex: 1; min-width: 0; -} - -#playlist-name { - font-size: 2rem; + } + + #playlist-name { + font-size: 2.5rem; margin-bottom: 0.5rem; -} - -#playlist-owner, -#playlist-stats, -#playlist-description { - font-size: 1rem; + background: linear-gradient(90deg, #1db954, #17a44b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + #playlist-owner, + #playlist-stats, + #playlist-description { + font-size: 1.1rem; color: #b3b3b3; margin-bottom: 0.5rem; -} - -/* Tracks Container */ -#tracks-container { + } + + /* Tracks Container */ + #tracks-container { margin-top: 2rem; -} - -#tracks-container h2 { - font-size: 1.5rem; + } + + #tracks-container h2 { + font-size: 1.75rem; margin-bottom: 1rem; border-bottom: 1px solid #2a2a2a; padding-bottom: 0.5rem; -} - -/* Tracks List */ -#tracks-list { + } + + /* Tracks List */ + #tracks-list { display: flex; flex-direction: column; gap: 1rem; -} - -/* Individual Track Styling */ -.track { + } + + /* Individual Track Styling */ + .track { display: flex; align-items: center; padding: 1rem; @@ -129,41 +148,41 @@ body { border-radius: 8px; transition: background 0.3s ease; flex-wrap: wrap; -} - -.track:hover { + } + + .track:hover { background: #2a2a2a; -} - -.track-number { + } + + .track-number { width: 30px; font-size: 1rem; font-weight: 500; text-align: center; margin-right: 1rem; flex-shrink: 0; -} - -.track-info { + } + + .track-info { flex: 1; display: flex; flex-direction: column; min-width: 0; align-items: flex-start; -} - -.track-name { + } + + .track-name { font-size: 1rem; font-weight: bold; word-wrap: break-word; -} - -.track-artist { + } + + .track-artist { font-size: 0.9rem; color: #b3b3b3; -} - -.track-album { + } + + .track-album { max-width: 200px; font-size: 0.9rem; color: #b3b3b3; @@ -172,105 +191,105 @@ body { text-overflow: ellipsis; white-space: nowrap; text-align: right; -} - -.track-duration { + } + + .track-duration { width: 60px; text-align: right; font-size: 0.9rem; color: #b3b3b3; margin-left: 1rem; flex-shrink: 0; -} - -/* Loading and Error States */ -.loading, -.error { + } + + /* Loading and Error States */ + .loading, + .error { width: 100%; text-align: center; font-size: 1rem; padding: 1rem; -} - -.error { + } + + .error { color: #c0392b; -} - -/* Utility Classes */ -.hidden { + } + + /* Utility Classes */ + .hidden { display: none !important; -} - -/* Unified Download Button Base Style */ -.download-btn { + } + + /* Unified Download Button Base Style */ + .download-btn { background-color: #1db954; color: #fff; border: none; border-radius: 4px; - padding: 0.5rem 1rem; - font-size: 0.95rem; + padding: 0.6rem 1.2rem; + font-size: 1rem; cursor: pointer; transition: background-color 0.2s ease, transform 0.2s ease; display: inline-flex; align-items: center; justify-content: center; margin: 0.5rem; -} - -.download-btn:hover { + } + + .download-btn:hover { background-color: #17a44b; -} - -.download-btn:active { + } + + .download-btn:active { transform: scale(0.98); -} - -/* Circular Variant for Compact Areas (e.g., in a queue list) */ -.download-btn--circle { + } + + /* Circular Variant for Compact Areas (e.g., in a queue list) */ + .download-btn--circle { width: 32px; height: 32px; padding: 0; border-radius: 50%; font-size: 0; -} - -.download-btn--circle::before { + } + + .download-btn--circle::before { content: "↓"; font-size: 16px; color: #fff; display: inline-block; -} - -/* Icon next to text */ -.download-btn .btn-icon { + } + + /* Icon next to text */ + .download-btn .btn-icon { margin-right: 0.5rem; display: inline-flex; align-items: center; -} - -/* Back Button Styling */ -.back-btn { + } + + /* Back Button Styling */ + .back-btn { background-color: #333; color: #fff; border: none; border-radius: 4px; - padding: 0.5rem 1rem; - font-size: 0.95rem; + padding: 0.6rem 1.2rem; + font-size: 1rem; cursor: pointer; transition: background-color 0.2s ease, transform 0.2s ease; margin-right: 1rem; -} - -.back-btn:hover { + } + + .back-btn:hover { background-color: #444; -} - -.back-btn:active { + } + + .back-btn:active { transform: scale(0.98); -} - -/* Download Queue Toggle Button */ -.queue-toggle { + } + + /* Download Queue Toggle Button */ + .queue-toggle { position: fixed; bottom: 20px; right: 20px; @@ -281,110 +300,106 @@ body { width: 56px; height: 56px; cursor: pointer; - font-size: 0.9rem; + font-size: 1rem; font-weight: bold; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: background-color 0.3s ease, transform 0.2s ease; z-index: 1002; -} - -.queue-toggle:hover { + } + + .queue-toggle:hover { background: #1ed760; transform: scale(1.05); -} - -.queue-toggle:active { + } + + .queue-toggle:active { transform: scale(1); -} - -/* Responsive Styles */ - -/* Medium Devices (Tablets) */ -@media (max-width: 768px) { - #playlist-header { - flex-direction: column; - align-items: flex-start; + } + + /* Responsive Styles */ + + /* Medium Devices (Tablets) */ + @media (max-width: 768px) { + #album-header, #playlist-header { + flex-direction: column; + align-items: center; + text-align: center; } - - #playlist-image { - width: 100%; - height: auto; - margin-bottom: 1rem; + + #album-image, #playlist-image { + width: 180px; + height: 180px; + margin-bottom: 1rem; } - + + #album-name, #playlist-name { + font-size: 2rem; + } + + #album-artist, + #album-stats, + #playlist-owner, + #playlist-stats, + #playlist-description { + font-size: 1rem; + } + .track { - flex-direction: column; - align-items: flex-start; + flex-direction: column; + align-items: flex-start; } .track-album, .track-duration { - margin-left: 0; - margin-top: 0.5rem; - width: 100%; - text-align: left; + margin-left: 0; + margin-top: 0.5rem; + width: 100%; + text-align: left; } -} - -/* Small Devices (Mobile Phones) */ -@media (max-width: 480px) { + } + + /* Small Devices (Mobile Phones) */ + @media (max-width: 480px) { #app { - padding: 10px; + padding: 10px; } - #playlist-name { - font-size: 1.5rem; - } - - .track { - padding: 0.8rem; - flex-direction: column; - align-items: center; - text-align: center; - } - - .track-number { - font-size: 0.9rem; - margin-right: 0; - margin-bottom: 0.5rem; - } - - .track-info { - align-items: center; - } - - .track-album, - .track-duration { - margin-left: 0; - margin-top: 0.5rem; - width: 100%; - text-align: center; - } - - /* Mobile-specific styles for Album Info */ - #album-header { - flex-direction: column; - align-items: center; - text-align: center; - } - - #album-image { - width: 150px; - height: 150px; - margin-bottom: 1rem; - } - - #album-info { - width: 100%; - } - - #album-name { - font-size: 1.5rem; + #album-name, #playlist-name { + font-size: 1.75rem; } #album-artist, #album-stats, - #album-copyright { - font-size: 0.9rem; + #album-copyright, + #playlist-owner, + #playlist-stats, + #playlist-description { + font-size: 0.9rem; } -} + + .track { + padding: 0.8rem; + flex-direction: column; + align-items: center; + text-align: center; + } + + .track-number { + font-size: 0.9rem; + margin-right: 0; + margin-bottom: 0.5rem; + } + + .track-info { + align-items: center; + } + + .track-album, + .track-duration { + margin-left: 0; + margin-top: 0.5rem; + width: 100%; + text-align: center; + } + } + \ No newline at end of file diff --git a/static/css/main/base.css b/static/css/main/base.css deleted file mode 100644 index 1e8f67f..0000000 --- a/static/css/main/base.css +++ /dev/null @@ -1,34 +0,0 @@ -/* GENERAL STYLING & UTILITIES */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -body { - background-color: #121212; - color: #ffffff; - min-height: 100vh; -} - -.container { - max-width: 1200px; - margin: 0 auto; - padding: 20px; - position: relative; - z-index: 1; -} - -/* LOADING & ERROR STATES */ -.loading, -.error { - width: 100%; - text-align: center; - font-size: 1rem; - padding: 1rem; -} - -.error { - color: #c0392b; -} \ No newline at end of file diff --git a/static/css/main/main.css b/static/css/main/main.css new file mode 100644 index 0000000..383b397 --- /dev/null +++ b/static/css/main/main.css @@ -0,0 +1,299 @@ +/* GENERAL STYLING & UTILITIES */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + } + + body { + /* Use a subtle dark gradient for a modern feel */ + background: linear-gradient(135deg, #121212, #1e1e1e); + color: #ffffff; + min-height: 100vh; + } + + /* Main container for page content */ + .container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + position: relative; + z-index: 1; + } + + /* LOADING & ERROR STATES */ + .loading, + .error { + width: 100%; + text-align: center; + font-size: 1rem; + padding: 1rem; + } + + .error { + color: #c0392b; + } + + /* SEARCH HEADER COMPONENT */ + .search-header { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 30px; + position: sticky; + top: 0; + background: rgba(18, 18, 18, 1); + backdrop-filter: blur(10px); + padding: 20px 0; + z-index: 100; + border-bottom: 1px solid #2a2a2a; + } + + + .search-input { + flex: 1; + padding: 12px 20px; + border: none; + border-radius: 25px; + background: #2a2a2a; + color: #ffffff; + font-size: 16px; + outline: none; + transition: background-color 0.3s ease; + } + + .search-input:focus { + background: #333333; + } + + .search-type { + padding: 12px 15px; + background: #2a2a2a; + border: none; + border-radius: 25px; + color: #ffffff; + cursor: pointer; + transition: background-color 0.3s ease; + } + + .search-type:hover { + background: #3a3a3a; + } + + .search-button { + padding: 12px 30px; + background-color: #1db954; + border: none; + border-radius: 25px; + color: #ffffff; + font-weight: bold; + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease; + } + + .search-button:hover { + background-color: #1ed760; + transform: translateY(-2px); + } + + /* RESULTS GRID COMPONENT */ + .results-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 20px; + } + + /* Each result card gets a modern look with subtle borders, shadows, and transitions */ + .result-card { + background: #181818; + border: 1px solid #2a2a2a; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); + overflow: hidden; + transition: transform 0.2s ease, box-shadow 0.2s ease; + display: flex; + flex-direction: column; + cursor: pointer; + max-width: 100%; + } + + .result-card:hover { + transform: translateY(-4px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25); + } + + /* Album/Art image wrapper maintains aspect ratio */ + .album-art-wrapper { + position: relative; + width: 100%; + overflow: hidden; + border-radius: 4px; + margin-bottom: 15px; + } + + .album-art-wrapper::before { + content: ""; + display: block; + padding-top: 100%; + } + + .album-art { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; + } + + .album-art:hover { + transform: scale(1.02); + } + + /* Result text details */ + .track-title { + padding: 0.5rem 1rem; + font-size: 1.1rem; + font-weight: 600; + color: #ffffff; + margin-bottom: 0.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + background: linear-gradient(90deg, #1db954, #17a44b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + .track-artist { + padding: 0 1rem; + font-size: 0.95rem; + color: #b3b3b3; + margin-bottom: 0.5rem; + } + + /* Track details (e.g., duration, extra info) */ + .track-details { + padding: 0.5rem 1rem; + font-size: 0.85rem; + color: #ccc; + display: flex; + justify-content: space-between; + align-items: center; + border-top: 1px solid #2a2a2a; + } + + .duration { + font-style: italic; + color: #999; + } + + /* Centered Download Button styling */ + .download-btn { + margin: 0.75rem 1rem 1rem; + padding: 0.5rem 1rem; + background-color: #1db954; + color: #ffffff; + border: none; + border-radius: 4px; + font-size: 0.95rem; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.2s ease; + display: block; + text-align: center; + width: calc(100% - 2rem); + } + + .download-btn:hover { + background-color: #17a44b; + transform: scale(1.02); + } + + /* ARTIST DOWNLOAD OPTIONS */ + .artist-download-buttons { + border-top: 1px solid #2a2a2a; + padding: 0.5rem 1rem; + } + + .options-toggle { + width: 100%; + background: none; + border: none; + color: #b3b3b3; + padding: 8px 16px; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + transition: color 0.2s ease; + } + + .options-toggle:hover { + color: #ffffff; + } + + .download-options-container { + margin-top: 0.5rem; + } + + .secondary-options { + display: none; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.5rem; + } + + .secondary-options.expanded { + display: flex; + } + + .option-btn { + flex: 1; + background-color: #2a2a2a; + color: #ffffff; + padding: 0.4rem 0.6rem; + border: none; + border-radius: 4px; + font-size: 0.85rem; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.2s ease; + } + + .option-btn:hover { + background-color: #3a3a3a; + transform: translateY(-1px); + } + + /* MOBILE RESPONSIVENESS */ + @media (max-width: 600px) { + .search-header { + flex-wrap: wrap; + justify-content: center; + padding: 10px 0; + } + + .search-input, + .search-type, + .search-button { + flex: 1 1 100%; + margin-bottom: 10px; + } + + .search-type, + .search-button { + padding: 10px; + font-size: 15px; + } + + .results-grid { + justify-content: center; + } + + .result-card { + width: 90%; + margin: 0 auto; + } + } + \ No newline at end of file diff --git a/static/css/main/results-grid.css b/static/css/main/results-grid.css deleted file mode 100644 index 701f4b6..0000000 --- a/static/css/main/results-grid.css +++ /dev/null @@ -1,160 +0,0 @@ -/* RESULTS GRID COMPONENT */ -.results-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 20px; -} - -.result-card { - background-color: #181818; - border: 1px solid #2a2a2a; - border-radius: 8px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); - overflow: hidden; - transition: transform 0.2s ease, box-shadow 0.2s ease; - display: flex; - flex-direction: column; - cursor: pointer; - max-width: 100%; -} - -.result-card:hover { - transform: translateY(-4px); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25); -} - -.album-art-wrapper { - position: relative; - width: 100%; - overflow: hidden; - border-radius: 4px; - margin-bottom: 15px; -} - -.album-art-wrapper::before { - content: ""; - display: block; - padding-top: 100%; -} - -.album-art { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - object-fit: cover; -} - -.track-title { - padding: 0.5rem 1rem; - font-size: 1.1rem; - font-weight: 600; - color: #fff; - margin-bottom: 0.25rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.track-artist { - padding: 0 1rem; - font-size: 0.95rem; - color: #b3b3b3; - margin-bottom: 0.5rem; -} - -.track-details { - padding: 0.5rem 1rem; - font-size: 0.85rem; - color: #ccc; - display: flex; - justify-content: space-between; - align-items: center; - border-top: 1px solid #2a2a2a; -} - -.duration { - font-style: italic; - color: #999; -} - -.download-btn { - margin: 0.75rem 1rem 1rem; - padding: 0.5rem 1rem; - background-color: #1db954; - color: #fff; - border: none; - border-radius: 4px; - font-size: 0.95rem; - cursor: pointer; - transition: background-color 0.2s ease; - display: flex; - align-items: center; - justify-content: center; - width: calc(100% - 2rem); -} - -.download-btn:hover { - background-color: #17a44b; -} - -/* Artist Download Options */ -.artist-download-buttons { - border-top: 1px solid #2a2a2a; - padding: 0.5rem 1rem; -} - -.options-toggle { - width: 100%; - background: none; - border: none; - color: #b3b3b3; - padding: 8px 16px; - display: flex; - justify-content: space-between; - align-items: center; - cursor: pointer; -} - -.download-options-container { - margin-top: 0.5rem; -} - -.secondary-options { - display: none; - flex-wrap: wrap; - gap: 0.5rem; - margin-top: 0.5rem; -} - -.secondary-options.expanded { - display: flex; -} - -.option-btn { - flex: 1; - background-color: #2a2a2a; - color: #fff; - padding: 0.4rem 0.6rem; - border: none; - border-radius: 4px; - font-size: 0.85rem; - cursor: pointer; - transition: background-color 0.2s ease; -} - -.option-btn:hover { - background-color: #3a3a3a; -} - -/* Mobile Responsiveness */ -@media (max-width: 600px) { - .results-grid { - justify-content: center; - } - .result-card { - width: 90%; - margin: 0 auto; - } -} \ No newline at end of file diff --git a/static/css/main/search-header.css b/static/css/main/search-header.css deleted file mode 100644 index e64dbf4..0000000 --- a/static/css/main/search-header.css +++ /dev/null @@ -1,68 +0,0 @@ -/* SEARCH HEADER COMPONENT */ -.search-header { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 30px; - position: sticky; - top: 0; - background-color: #121212; - padding: 20px 0; - z-index: 100; -} - -.search-input { - flex: 1; - padding: 12px 20px; - border: none; - border-radius: 25px; - background: #2a2a2a; - color: white; - font-size: 16px; -} - -.search-type { - padding: 12px 15px; - background: #2a2a2a; - border: none; - border-radius: 25px; - color: white; - cursor: pointer; -} - -.search-button { - padding: 12px 30px; - background-color: #1DB954; - border: none; - border-radius: 25px; - color: white; - font-weight: bold; - cursor: pointer; - transition: background-color 0.3s; -} - -.search-button:hover { - background-color: #1ed760; -} - -/* Mobile Responsiveness */ -@media (max-width: 600px) { - .search-header { - flex-wrap: wrap; - justify-content: center; - padding: 10px 0; - } - - .search-input, - .search-type, - .search-button { - flex: 1 1 100%; - margin-bottom: 10px; - } - - .search-type, - .search-button { - padding: 10px; - font-size: 15px; - } -} \ No newline at end of file diff --git a/static/css/playlist/playlist.css b/static/css/playlist/playlist.css index 1c7c111..076e250 100644 --- a/static/css/playlist/playlist.css +++ b/static/css/playlist/playlist.css @@ -1,325 +1,333 @@ /* Base Styles */ * { - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - } - - body { - background-color: #121212; - color: #ffffff; - min-height: 100vh; - line-height: 1.4; - } - - /* Main App Container */ - #app { - max-width: 1200px; - margin: 0 auto; - padding: 20px; - position: relative; - z-index: 1; - } - - /* Playlist Header */ + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +body { + background: linear-gradient(135deg, #121212, #1e1e1e); + color: #ffffff; + min-height: 100vh; + line-height: 1.4; +} + +/* Main App Container */ +#app { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + position: relative; + z-index: 1; +} + +/* Playlist Header */ +#playlist-header { + display: flex; + gap: 20px; + margin-bottom: 2rem; + align-items: center; + padding-bottom: 1.5rem; + border-bottom: 1px solid #2a2a2a; + flex-wrap: wrap; + transition: all 0.3s ease; +} + +#playlist-image { + width: 200px; + height: 200px; + object-fit: cover; + border-radius: 8px; + flex-shrink: 0; + box-shadow: 0 4px 8px rgba(0,0,0,0.3); + transition: transform 0.3s ease; +} +#playlist-image:hover { + transform: scale(1.02); +} + +#playlist-info { + flex: 1; + min-width: 0; +} + +#playlist-name { + font-size: 2.5rem; + margin-bottom: 0.5rem; + background: linear-gradient(90deg, #1db954, #17a44b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +#playlist-owner, +#playlist-stats, +#playlist-description { + font-size: 1.1rem; + color: #b3b3b3; + margin-bottom: 0.5rem; +} + +/* Tracks Container */ +#tracks-container { + margin-top: 2rem; +} + +#tracks-container h2 { + font-size: 1.75rem; + margin-bottom: 1rem; + border-bottom: 1px solid #2a2a2a; + padding-bottom: 0.5rem; +} + +/* Tracks List */ +#tracks-list { + display: flex; + flex-direction: column; + gap: 1rem; +} + +/* Individual Track Styling */ +.track { + display: flex; + align-items: center; + padding: 1rem; + background: #181818; + border-radius: 8px; + transition: background 0.3s ease; + flex-wrap: wrap; +} + +.track:hover { + background: #2a2a2a; +} + +.track-number { + width: 30px; + font-size: 1rem; + font-weight: 500; + text-align: center; + margin-right: 1rem; + flex-shrink: 0; +} + +.track-info { + flex: 1; + display: flex; + flex-direction: column; + min-width: 0; + align-items: flex-start; +} + +.track-name { + font-size: 1rem; + font-weight: bold; + word-wrap: break-word; +} + +.track-artist { + font-size: 0.9rem; + color: #b3b3b3; +} + +/* When displaying track album info on the side */ +.track-album { + max-width: 200px; + font-size: 0.9rem; + color: #b3b3b3; + margin-left: 1rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: right; +} + +.track-duration { + width: 60px; + text-align: right; + font-size: 0.9rem; + color: #b3b3b3; + margin-left: 1rem; + flex-shrink: 0; +} + +/* Loading and Error States */ +.loading, +.error { + width: 100%; + text-align: center; + font-size: 1rem; + padding: 1rem; +} + +.error { + color: #c0392b; +} + +/* Utility Classes */ +.hidden { + display: none !important; +} + +/* Unified Download Button Base Style */ +.download-btn { + background-color: #1db954; + color: #fff; + border: none; + border-radius: 4px; + padding: 0.6rem 1.2rem; + font-size: 1rem; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.2s ease; + display: inline-flex; + align-items: center; + justify-content: center; + margin: 0.5rem; +} + +.download-btn:hover { + background-color: #17a44b; +} + +.download-btn:active { + transform: scale(0.98); +} + +/* Circular Variant for Compact Areas (e.g., in a queue list) */ +.download-btn--circle { + width: 32px; + height: 32px; + padding: 0; + border-radius: 50%; + font-size: 0; +} + +.download-btn--circle::before { + content: "↓"; + font-size: 16px; + color: #fff; + display: inline-block; +} + +/* Icon next to text */ +.download-btn .btn-icon { + margin-right: 0.5rem; + display: inline-flex; + align-items: center; +} + +/* Back Button Styling */ +.back-btn { + background-color: #333; + color: #fff; + border: none; + border-radius: 4px; + padding: 0.6rem 1.2rem; + font-size: 1rem; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.2s ease; + margin-right: 1rem; +} + +.back-btn:hover { + background-color: #444; +} + +.back-btn:active { + transform: scale(0.98); +} + +/* Download Queue Toggle Button */ +.queue-toggle { + position: fixed; + bottom: 20px; + right: 20px; + background: #1db954; + color: #fff; + border: none; + border-radius: 50%; + width: 56px; + height: 56px; + cursor: pointer; + font-size: 1rem; + font-weight: bold; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + transition: background-color 0.3s ease, transform 0.2s ease; + z-index: 1002; +} + +.queue-toggle:hover { + background: #1ed760; + transform: scale(1.05); +} + +.queue-toggle:active { + transform: scale(1); +} + +/* Responsive Styles */ + +/* Medium Devices (Tablets) */ +@media (max-width: 768px) { #playlist-header { - display: flex; - gap: 20px; - margin-bottom: 2rem; + flex-direction: column; align-items: center; - padding-bottom: 1.5rem; - border-bottom: 1px solid #2a2a2a; - flex-wrap: wrap; /* Allow wrapping on narrow screens */ + text-align: center; } #playlist-image { - width: 200px; - height: 200px; - object-fit: cover; - border-radius: 8px; - flex-shrink: 0; + width: 180px; + height: 180px; + margin-bottom: 1rem; } - #playlist-info { - flex: 1; - min-width: 0; + .track { + flex-direction: column; + align-items: flex-start; + } + + .track-album, + .track-duration { + margin-left: 0; + margin-top: 0.5rem; + width: 100%; + text-align: left; + } +} + +/* Small Devices (Mobile Phones) */ +@media (max-width: 480px) { + #app { + padding: 10px; } #playlist-name { - font-size: 2rem; - margin-bottom: 0.5rem; + font-size: 1.75rem; } - #playlist-owner, - #playlist-stats, - #playlist-description { - font-size: 1rem; - color: #b3b3b3; - margin-bottom: 0.5rem; - } - - /* Tracks Container */ - #tracks-container { - margin-top: 2rem; - } - - #tracks-container h2 { - font-size: 1.5rem; - margin-bottom: 1rem; - border-bottom: 1px solid #2a2a2a; - padding-bottom: 0.5rem; - } - - /* Tracks List */ - #tracks-list { - display: flex; - flex-direction: column; - gap: 1rem; - } - - /* Individual Track Styling */ + /* Adjust track layout to vertical & centered */ .track { - display: flex; + padding: 0.8rem; + flex-direction: column; align-items: center; - padding: 1rem; - background: #181818; - border-radius: 8px; - transition: background 0.3s ease; - flex-wrap: wrap; - } - - .track:hover { - background: #2a2a2a; + text-align: center; } .track-number { - width: 30px; - font-size: 1rem; - font-weight: 500; - text-align: center; - margin-right: 1rem; - flex-shrink: 0; + font-size: 0.9rem; + margin-right: 0; + margin-bottom: 0.5rem; } .track-info { - flex: 1; - display: flex; - flex-direction: column; - min-width: 0; - align-items: flex-start; /* default left alignment */ - } - - .track-name { - font-size: 1rem; - font-weight: bold; - word-wrap: break-word; - } - - .track-artist { - font-size: 0.9rem; - color: #b3b3b3; - } - - .track-album { - max-width: 200px; - font-size: 0.9rem; - color: #b3b3b3; - margin-left: 1rem; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - text-align: right; + align-items: center; } + .track-album, .track-duration { - width: 60px; - text-align: right; - font-size: 0.9rem; - color: #b3b3b3; - margin-left: 1rem; - flex-shrink: 0; - } - - /* Loading and Error States */ - .loading, - .error { + margin-left: 0; + margin-top: 0.5rem; width: 100%; text-align: center; - font-size: 1rem; - padding: 1rem; } - - .error { - color: #c0392b; - } - - /* Utility Classes */ - .hidden { - display: none !important; - } - - /* Unified Download Button Base Style */ - .download-btn { - background-color: #1db954; - color: #fff; - border: none; - border-radius: 4px; - padding: 0.5rem 1rem; - font-size: 0.95rem; - cursor: pointer; - transition: background-color 0.2s ease, transform 0.2s ease; - display: inline-flex; - align-items: center; - justify-content: center; - margin: 0.5rem; - } - - .download-btn:hover { - background-color: #17a44b; - } - - .download-btn:active { - transform: scale(0.98); - } - - /* Circular Variant for Compact Areas (e.g., in a queue list) */ - .download-btn--circle { - width: 32px; - height: 32px; - padding: 0; - border-radius: 50%; - font-size: 0; - } - - .download-btn--circle::before { - content: "↓"; - font-size: 16px; - color: #fff; - display: inline-block; - } - - /* Icon next to text */ - .download-btn .btn-icon { - margin-right: 0.5rem; - display: inline-flex; - align-items: center; - } - - /* Back Button Styling */ - .back-btn { - background-color: #333; - color: #fff; - border: none; - border-radius: 4px; - padding: 0.5rem 1rem; - font-size: 0.95rem; - cursor: pointer; - transition: background-color 0.2s ease, transform 0.2s ease; - margin-right: 1rem; - } - - .back-btn:hover { - background-color: #444; - } - - .back-btn:active { - transform: scale(0.98); - } - - /* Download Queue Toggle Button */ - .queue-toggle { - position: fixed; - bottom: 20px; - right: 20px; - background: #1db954; - color: #fff; - border: none; - border-radius: 50%; - width: 56px; - height: 56px; - cursor: pointer; - font-size: 0.9rem; - font-weight: bold; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); - transition: background-color 0.3s ease, transform 0.2s ease; - z-index: 1002; - } - - .queue-toggle:hover { - background: #1ed760; - transform: scale(1.05); - } - - .queue-toggle:active { - transform: scale(1); - } - - /* Responsive Styles */ - - /* Medium Devices (Tablets) */ - @media (max-width: 768px) { - #playlist-header { - flex-direction: column; - align-items: flex-start; - } - - #playlist-image { - width: 100%; - height: auto; - margin-bottom: 1rem; - } - - .track { - flex-direction: column; - align-items: flex-start; - } - - .track-album, - .track-duration { - margin-left: 0; - margin-top: 0.5rem; - width: 100%; - text-align: left; - } - } - - /* Small Devices (Mobile Phones) */ - @media (max-width: 480px) { - #app { - padding: 10px; - } - - #playlist-name { - font-size: 1.5rem; - } - - /* Adjust track layout to vertical & centered */ - .track { - padding: 0.8rem; - flex-direction: column; - align-items: center; - text-align: center; - } - - .track-number { - font-size: 0.9rem; - margin-right: 0; - margin-bottom: 0.5rem; - } - - .track-info { - align-items: center; - } - - /* Center the album and duration info */ - .track-album, - .track-duration { - margin-left: 0; - margin-top: 0.5rem; - width: 100%; - text-align: center; - } - - } - \ No newline at end of file +} diff --git a/static/css/track/track.css b/static/css/track/track.css index e1b4ee5..44be4b6 100644 --- a/static/css/track/track.css +++ b/static/css/track/track.css @@ -7,12 +7,13 @@ } body { - background-color: #121212; + background: linear-gradient(135deg, #121212, #1e1e1e); color: #ffffff; min-height: 100vh; line-height: 1.4; } + /* App Container */ #app { max-width: 1200px; margin: 0 auto; @@ -24,37 +25,48 @@ /* Track Header */ #track-header { display: flex; + align-items: center; gap: 20px; margin-bottom: 2rem; - align-items: center; padding-bottom: 1.5rem; border-bottom: 1px solid #2a2a2a; flex-wrap: wrap; + transition: all 0.3s ease; } + /* Album Image with a subtle shadow and rounded corners */ #track-album-image { width: 200px; height: 200px; object-fit: cover; border-radius: 8px; flex-shrink: 0; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + transition: transform 0.3s ease; + } + #track-album-image:hover { + transform: scale(1.02); } + /* Track Info Styles */ #track-info { flex: 1; min-width: 0; } #track-name { - font-size: 2rem; + font-size: 2.5rem; margin-bottom: 0.5rem; + background: linear-gradient(90deg, #1db954, #17a44b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; } #track-artist, #track-album, #track-duration, #track-explicit { - font-size: 1rem; + font-size: 1.1rem; color: #b3b3b3; margin-bottom: 0.5rem; } @@ -78,8 +90,8 @@ color: #fff; border: none; border-radius: 4px; - padding: 0.5rem 1rem; - font-size: 0.95rem; + padding: 0.6rem 1.2rem; + font-size: 1rem; cursor: pointer; transition: background-color 0.2s ease, transform 0.2s ease; margin-right: 1rem; @@ -93,22 +105,22 @@ transform: scale(0.98); } - /* Download Button Base Style (same as in the playlist project) */ + /* Download Button */ .download-btn { background-color: #1db954; color: #fff; border: none; border-radius: 4px; - padding: 0.5rem 1rem; - font-size: 0.95rem; + padding: 0.6rem 1.2rem; + font-size: 1rem; cursor: pointer; transition: background-color 0.2s ease, transform 0.2s ease; - display: inline-flex; - align-items: center; - justify-content: center; - margin: 0.5rem; + display: block; /* Changed from inline-flex to block */ + margin: 0.5rem auto; /* Centers the button horizontally */ + text-align: center; } + .download-btn:hover { background-color: #17a44b; } @@ -127,4 +139,61 @@ /* Utility Classes */ .hidden { display: none !important; - } \ No newline at end of file + } + + /* Mobile Responsiveness */ + @media (max-width: 768px) { + #app { + padding: 15px; + } + + #track-header { + flex-direction: column; + align-items: center; + text-align: center; + } + + #track-album-image { + width: 180px; + height: 180px; + } + + #track-name { + font-size: 2rem; + } + + #track-artist, + #track-album, + #track-duration, + #track-explicit { + font-size: 1rem; + } + + .back-btn, + .download-btn { + padding: 0.5rem 1rem; + font-size: 0.9rem; + margin: 0.5rem 0; + display: block; /* Changed from inline-flex to block */ + margin: 0.5rem auto; /* Centers the button horizontally */ + } + } + + @media (max-width: 480px) { + #track-album-image { + width: 150px; + height: 150px; + } + + #track-name { + font-size: 1.75rem; + } + + #track-artist, + #track-album, + #track-duration, + #track-explicit { + font-size: 0.9rem; + } + } + \ No newline at end of file diff --git a/static/js/album.js b/static/js/album.js index 219e6f8..90a2073 100644 --- a/static/js/album.js +++ b/static/js/album.js @@ -1,26 +1,23 @@ -// Import the downloadQueue singleton from your working queue.js implementation. import { downloadQueue } from './queue.js'; document.addEventListener('DOMContentLoaded', () => { - // Parse artist ID from the URL (expected route: /artist/{id}) const pathSegments = window.location.pathname.split('/'); - const artistId = pathSegments[pathSegments.indexOf('artist') + 1]; + const albumId = pathSegments[pathSegments.indexOf('album') + 1]; - if (!artistId) { - showError('No artist ID provided.'); + if (!albumId) { + showError('No album ID provided.'); return; } - // Fetch the artist info (which includes a list of albums) - fetch(`/api/artist/info?id=${encodeURIComponent(artistId)}`) + fetch(`/api/album/info?id=${encodeURIComponent(albumId)}`) .then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.json(); }) - .then(data => renderArtist(data)) + .then(data => renderAlbum(data)) .catch(error => { console.error('Error:', error); - showError('Failed to load artist info.'); + showError('Failed to load album.'); }); const queueIcon = document.getElementById('queueIcon'); @@ -31,225 +28,132 @@ document.addEventListener('DOMContentLoaded', () => { } }); -/** - * Renders the artist header and groups the albums by type. - * - * The API response is expected to have the following structure: - * { - * "href": "...", - * "limit": 50, - * "next": null, - * "offset": 0, - * "previous": null, - * "total": 5, - * "items": [ { album object }, { album object }, ... ] - * } - */ -function renderArtist(artistData) { - // Hide loading and error messages +function renderAlbum(album) { document.getElementById('loading').classList.add('hidden'); document.getElementById('error').classList.add('hidden'); - // Use the first album to extract artist details - const firstAlbum = artistData.items[0]; - const artistName = firstAlbum?.artists[0]?.name || 'Unknown Artist'; - const artistImage = firstAlbum?.images[0]?.url || 'placeholder.jpg'; - document.getElementById('artist-name').textContent = artistName; - document.getElementById('artist-stats').textContent = `${artistData.total} albums`; - document.getElementById('artist-image').src = artistImage; + // Album header info + document.getElementById('album-name').textContent = album.name; + document.getElementById('album-artist').textContent = + `By ${album.artists.map(artist => artist.name).join(', ')}`; + + const releaseYear = new Date(album.release_date).getFullYear(); + document.getElementById('album-stats').textContent = + `${releaseYear} • ${album.total_tracks} songs • ${album.label}`; + + document.getElementById('album-copyright').textContent = + album.copyrights.map(c => c.text).join(' • '); - // --- Add Back Button --- + const image = album.images[0]?.url || 'placeholder.jpg'; + document.getElementById('album-image').src = image; + + // Back Button let backButton = document.getElementById('backButton'); if (!backButton) { backButton = document.createElement('button'); backButton.id = 'backButton'; backButton.textContent = 'Back'; backButton.className = 'back-btn'; - // Insert the back button at the beginning of the header container. - const headerContainer = document.getElementById('artist-header'); + const headerContainer = document.getElementById('album-header'); headerContainer.insertBefore(backButton, headerContainer.firstChild); } backButton.addEventListener('click', () => { - // Navigate to the site's base URL. window.location.href = window.location.origin; }); - // --- Add "Download Whole Artist" Button --- - let downloadArtistBtn = document.getElementById('downloadArtistBtn'); - if (!downloadArtistBtn) { - downloadArtistBtn = document.createElement('button'); - downloadArtistBtn.id = 'downloadArtistBtn'; - downloadArtistBtn.textContent = 'Download Whole Artist'; - downloadArtistBtn.className = 'download-btn download-btn--main'; - // Insert the button into the header container. - const headerContainer = document.getElementById('artist-header'); - headerContainer.appendChild(downloadArtistBtn); + // Download Album Button + let downloadAlbumBtn = document.getElementById('downloadAlbumBtn'); + if (!downloadAlbumBtn) { + downloadAlbumBtn = document.createElement('button'); + downloadAlbumBtn.id = 'downloadAlbumBtn'; + downloadAlbumBtn.textContent = 'Download Full Album'; + downloadAlbumBtn.className = 'download-btn download-btn--main'; + document.getElementById('album-header').appendChild(downloadAlbumBtn); } - downloadArtistBtn.addEventListener('click', () => { - // Remove individual album download buttons (but leave the whole artist button). + + downloadAlbumBtn.addEventListener('click', () => { document.querySelectorAll('.download-btn').forEach(btn => { - if (btn.id !== 'downloadArtistBtn') { - btn.remove(); - } + if (btn.id !== 'downloadAlbumBtn') btn.remove(); }); - // Disable the whole artist button to prevent repeated clicks. - downloadArtistBtn.disabled = true; - downloadArtistBtn.textContent = 'Queueing...'; + downloadAlbumBtn.disabled = true; + downloadAlbumBtn.textContent = 'Queueing...'; - // Initiate the artist download. - downloadWholeArtist(artistData).then(() => { - downloadArtistBtn.textContent = 'Queued!'; + downloadWholeAlbum(album).then(() => { + downloadAlbumBtn.textContent = 'Queued!'; }).catch(err => { - showError('Failed to queue artist download: ' + err.message); - downloadArtistBtn.disabled = false; + showError('Failed to queue album download: ' + err.message); + downloadAlbumBtn.disabled = false; }); }); - // Group albums by album type. - const albumGroups = {}; - artistData.items.forEach(album => { - // Normalize album type to lower-case for grouping. - const type = album.album_type.toLowerCase(); - if (!albumGroups[type]) { - albumGroups[type] = []; - } - albumGroups[type].push(album); - }); + // Render tracks + const tracksList = document.getElementById('tracks-list'); + tracksList.innerHTML = ''; - // Render groups into the #album-groups container. - const groupsContainer = document.getElementById('album-groups'); - groupsContainer.innerHTML = ''; // clear any previous content - - // For each album type, render a section header, a "Download All" button, and the album list. - for (const [groupType, albums] of Object.entries(albumGroups)) { - const groupSection = document.createElement('section'); - groupSection.className = 'album-group'; - - // Header for the album group with a download-all button. - const header = document.createElement('div'); - header.className = 'album-group-header'; - header.innerHTML = ` -