From bc232e060b3af516ac49410669e78debff481d68 Mon Sep 17 00:00:00 2001 From: manaswiniiyer Date: Wed, 20 May 2026 11:45:17 +0530 Subject: [PATCH] feat: add song card grid component (#41) --- static/css/style.css | 163 ++++++++++++++++++++++++++++++++++++++++++- static/js/script.js | 29 +++++++- templates/index.html | 123 ++++++++++++++++++++++---------- 3 files changed, 275 insertions(+), 40 deletions(-) diff --git a/static/css/style.css b/static/css/style.css index dfcd792..1e34cc4 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -251,4 +251,165 @@ body { .cover-art { width: 140px; height: 140px; font-size: 3rem; } .track-title { font-size: 1.4rem; } -} \ No newline at end of file +} + + + +.song-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: 1rem; +} + + +.song-card-grid { + background: var(--bg-elev); + border: 1px solid var(--border); + border-radius: 14px; + overflow: hidden; + cursor: pointer; + transition: border-color 0.2s, transform 0.2s; + display: flex; + flex-direction: column; +} + +.song-card-grid:hover { + border-color: var(--accent); + transform: translateY(-3px); +} + + +.song-card-grid__art { + position: relative; + aspect-ratio: 1 / 1; + background: linear-gradient(135deg, #3a2a4e, #2a1a3a); + display: flex; + align-items: center; + justify-content: center; + font-size: 2.5rem; + overflow: hidden; +} + + +.song-card-grid__art--orange { background: linear-gradient(135deg, var(--accent), var(--accent-2)); } +.song-card-grid__art--purple { background: linear-gradient(135deg, #7c3aed, #4f46e5); } +.song-card-grid__art--teal { background: linear-gradient(135deg, #0d9488, #0891b2); } +.song-card-grid__art--pink { background: linear-gradient(135deg, #ec4899, #a855f7); } + + +.song-card-grid__art img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + + +.song-card-grid__overlay { + position: absolute; + inset: 0; + background: rgba(0, 0, 0, 0.45); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.2s; +} + +.song-card-grid:hover .song-card-grid__overlay { + opacity: 1; +} + +.song-card-grid__play-btn { + width: 52px; + height: 52px; + border-radius: 50%; + background: var(--accent); + border: none; + color: #fff; + font-size: 1.2rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.15s, background 0.15s; + box-shadow: 0 4px 20px rgba(255, 107, 61, 0.45); +} + +.song-card-grid__play-btn:hover { + transform: scale(1.08); + background: var(--accent-2); +} + + +.song-card-grid--playing .song-card-grid__art::before { + content: ""; + position: absolute; + inset: -3px; + border-radius: inherit; + border: 2px solid var(--accent); + animation: pulse-ring 1.8s ease-out infinite; + pointer-events: none; +} + +@keyframes pulse-ring { + 0% { opacity: 0.9; transform: scale(1); } + 100% { opacity: 0; transform: scale(1.06); } +} + + +.song-card-grid__info { + padding: 0.75rem 0.875rem 0.875rem; + display: flex; + flex-direction: column; + gap: 0.2rem; + flex: 1; +} + +.song-card-grid__title { + font-size: 0.9rem; + font-weight: 600; + color: var(--text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.song-card-grid__genre { + font-size: 0.78rem; + color: var(--text-dim); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + + +.song-card-grid__footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 0.5rem; +} + +.song-card-grid__duration { + font-size: 0.78rem; + color: var(--text-dim); +} + +.song-card-grid__like { + background: none; + border: none; + cursor: pointer; + color: var(--text-dim); + font-size: 0.95rem; + padding: 0; + line-height: 1; + transition: color 0.15s, transform 0.15s; +} + +.song-card-grid__like:hover, +.song-card-grid__like--liked { + color: var(--accent) ; + transform: scale(1.15); +} + diff --git a/static/js/script.js b/static/js/script.js index 41ff1e9..a908908 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -1 +1,28 @@ -console.log("RustTune loaded"); \ No newline at end of file +console.log("RustTune loaded"); + + + +function toggleLike(btn) { + const liked = btn.classList.toggle("song-card-grid__like--liked"); + btn.textContent = liked ? "♥" : "♡"; + btn.setAttribute("aria-pressed", String(liked)); + const title = btn.closest(".song-card-grid").querySelector(".song-card-grid__title").textContent; + btn.setAttribute("aria-label", `${liked ? "Unlike" : "Like"} ${title}`); +} + +function playSong(btn) { + const card = btn.closest(".song-card-grid"); + document.querySelectorAll(".song-card-grid--playing") + .forEach(c => c.classList.remove("song-card-grid--playing")); + card.classList.add("song-card-grid--playing"); + document.getElementById("now-title").textContent = card.querySelector(".song-card-grid__title").textContent; + document.getElementById("now-artist").textContent = card.querySelector(".song-card-grid__genre").textContent + " • RustTune"; +} + +document.querySelectorAll(".song-card-grid__like").forEach(btn => { + btn.addEventListener("click", () => toggleLike(btn)); +}); + +document.querySelectorAll(".song-card-grid__play-btn").forEach(btn => { + btn.addEventListener("click", () => playSong(btn)); +}); \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index d35e008..7578b80 100644 --- a/templates/index.html +++ b/templates/index.html @@ -73,52 +73,99 @@

Feel The Music

-
+ -
-

Popular Songs

- See all -
- - +
- +