From f7ef338d7e544812a11d06bf874d05d1bff2a193 Mon Sep 17 00:00:00 2001 From: schuemRPI <143740215+schuemRPI@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:07:17 -0500 Subject: [PATCH 1/3] Add UI for song info and lyrics with play and pause buttons --- src/components/NowPlaying.tsx | 112 +++++++++++++- src/styles/now-playing.css | 271 ++++++++++++++++++++++++++++++++++ 2 files changed, 380 insertions(+), 3 deletions(-) create mode 100644 src/styles/now-playing.css diff --git a/src/components/NowPlaying.tsx b/src/components/NowPlaying.tsx index 07ea116..ab3ea92 100644 --- a/src/components/NowPlaying.tsx +++ b/src/components/NowPlaying.tsx @@ -1,7 +1,113 @@ +import { useState } from 'react'; +import '../styles/now-playing.css'; + +// Mock lyrics data - replace with actual lyrics from API +const mockLyrics = [ + 'Cruising through the city lights', + 'Neon signs reflecting in the rain', + 'Midnight drive, no destination', + 'Lost in the rhythm of the night', +]; + +interface Song { + title: string; + artist: string; + album: string; + duration: number; + coverUrl: string; +} + +const mockSong: Song = { + title: 'Midnight Drive', + artist: 'Neon Pulse', + album: 'Frequency', + duration: 245, // 4:05 in seconds + coverUrl: 'https://i.scdn.co/image/ab67616d00001e02f1f915cc84f06ebe2d4b8746', +}; + export default function NowPlaying() { + const [isPlaying, setIsPlaying] = useState(false); + const [currentTime, setCurrentTime] = useState(30); // 0:30 seconds + const [currentLyricIndex, setCurrentLyricIndex] = useState(0); + + const handlePlay = () => { + setIsPlaying(true); + }; + + const handlePause = () => { + setIsPlaying(false); + }; + + const formatTime = (seconds: number) => { + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs.toString().padStart(2, '0')}`; + }; + + const progressPercent = (currentTime / mockSong.duration) * 100; + return ( -
-

Now Playing

+
+
+ {/* Album Cover */} +
+ {`${mockSong.album} +
+ + {/* Main Section */} +
+ {/* Song Info Header */} +
+

{mockSong.title}

+

{mockSong.artist}

+
+ + {/* Progress Bar */} +
+ {formatTime(currentTime)} +
+
+
+ {formatTime(mockSong.duration)} +
+ + {/* Lyrics Section */} +
+ {mockLyrics.map((lyric, index) => ( +
+ {lyric} +
+ ))} +
+ + {/* Controls */} +
+ + +
+
+
- ) + ); } diff --git a/src/styles/now-playing.css b/src/styles/now-playing.css new file mode 100644 index 0000000..4f88170 --- /dev/null +++ b/src/styles/now-playing.css @@ -0,0 +1,271 @@ +/* Now Playing Component Styles */ +@import './design-system.css'; + +.now-playing-container { + width: 40vw; + background: linear-gradient(135deg, #0a0e27 0%, #0f1829 100%); + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + box-sizing: border-box; + border: 2px solid red; +} + +.np-content { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + gap: var(--space-2); + padding: var(--space-3); +} + +/* Album Cover */ +.np-album-cover-wrapper { + width: 100px; + height: 100px; + border-radius: var(--br-lg); + overflow: hidden; + border: 2px solid #00cc88; + box-shadow: 0 0 20px rgba(0, 204, 136, 0.4); + margin-top: 0; + flex-shrink: 0; +} + +.np-album-cover { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +/* Main Content */ +.np-main { + width: 100%; + display: flex; + flex-direction: column; + gap: var(--space-2); + align-items: center; + flex: 1; + min-height: 0; +} + +/* Song Header */ +.np-header { + text-align: center; + width: 100%; +} + +.np-title { + font-size: var(--fs-lg); + font-weight: var(--fw-bold); + color: #ffffff; + margin: 0; +} + +.np-artist { + font-size: var(--fs-sm); + font-weight: var(--fw-normal); + color: #888888; + margin: 0; +} + +/* Progress Bar Section */ +.np-progress-section { + width: 100%; + display: flex; + align-items: center; + gap: var(--space-3); + padding: 0 var(--space-2); +} + +.np-time { + font-size: var(--fs-xs); + color: #888888; + min-width: 35px; + text-align: center; + font-family: var(--font-mono); +} + +.np-progress-bar { + flex: 1; + height: 6px; + background-color: #333333; + border-radius: var(--br-full); + overflow: hidden; + cursor: pointer; + transition: height var(--transition-base); +} + +.np-progress-bar:hover { + height: 8px; +} + +.np-progress-fill { + height: 100%; + background: linear-gradient(90deg, #00cc88, #00ff99); + border-radius: var(--br-full); + transition: width 0.1s linear; +} + +/* Lyrics Section */ +.np-lyrics-section { + width: 100%; + flex: 1; + display: flex; + flex-direction: column; + gap: var(--space-1); + padding: var(--space-3); + background-color: rgba(0, 0, 0, 0.5); + border-radius: var(--br-lg); + border: 1px solid #222222; + overflow-y: auto; + min-height: 0; + max-height: 200px; +} + +.np-lyrics-section::-webkit-scrollbar { + width: 6px; +} + +.np-lyrics-section::-webkit-scrollbar-track { + background: transparent; +} + +.np-lyrics-section::-webkit-scrollbar-thumb { + background: #00cc88; + border-radius: var(--br-full); +} + +.np-lyrics-section::-webkit-scrollbar-thumb:hover { + background: #00ff99; +} + +.np-lyric-line { + font-size: var(--fs-xs); + font-weight: var(--fw-normal); + line-height: 1.3; + transition: all var(--transition-base); + padding: var(--space-1) var(--space-2); + border-radius: var(--br-sm); + cursor: default; +} + +/* Past lyrics - hidden */ +.np-lyric-line.past { + color: #444444; + opacity: 0.3; + display: none; +} + +/* Upcoming lyrics - less prominent */ +.np-lyric-line.upcoming { + color: #666666; + opacity: 0.5; +} + +/* Current lyric - highlighted in green */ +.np-lyric-line.current { + color: #00ff99; + font-weight: var(--fw-bold); + font-size: var(--fs-xs); + background: linear-gradient( + 90deg, + rgba(0, 204, 136, 0.15) 0%, + rgba(0, 255, 153, 0.25) 50%, + rgba(0, 204, 136, 0.15) 100% + ); + border-left: 3px solid #00cc88; + padding-left: calc(var(--space-2) - 1px); + animation: highlight-pulse 0.6s ease-out; + box-shadow: 0 0 15px rgba(0, 204, 136, 0.3); +} + +@keyframes highlight-pulse { + 0% { + transform: translateX(-10px); + opacity: 0.8; + } + 100% { + transform: translateX(0); + opacity: 1; + } +} + +/* Controls */ +.np-controls { + display: flex; + gap: var(--space-3); + width: 100%; + justify-content: center; + padding-top: var(--space-2); + border-top: 1px solid #222222; + flex-shrink: 0; +} + +.np-btn { + padding: var(--space-1) var(--space-3); + font-size: var(--fs-xs); + font-weight: var(--fw-semibold); + border: 2px solid #00cc88; + border-radius: var(--br-md); + background-color: transparent; + color: #00cc88; + cursor: pointer; + transition: all var(--transition-base); + font-family: var(--font-primary); + min-width: 85px; +} + +.np-btn:hover { + background-color: #00cc88; + color: #000000; + box-shadow: 0 0 20px rgba(0, 204, 136, 0.3); + transform: translateY(-2px); +} + +.np-btn.active { + background-color: #00cc88; + color: #000000; + box-shadow: 0 0 15px rgba(0, 204, 136, 0.5); +} + +/* Responsive Design */ +@media (max-width: 1200px) { + .now-playing-container { + width: 40vw; + } + + .np-title { + font-size: var(--fs-xl); + } +} + +@media (max-width: 768px) { + .now-playing-container { + width: 100%; + height: auto; + padding: var(--space-4); + } + + .np-music-icon { + font-size: 1.5rem; + } + + .np-title { + font-size: var(--fs-lg); + } + + .np-artist { + font-size: var(--fs-sm); + } + + .np-btn { + padding: var(--space-1) var(--space-3); + font-size: var(--fs-xs); + min-width: 80px; + } +} From 5fcaad1cae458132cacdc8916de8d422af4b00cf Mon Sep 17 00:00:00 2001 From: Rafi Khan Date: Tue, 24 Feb 2026 14:41:37 -0500 Subject: [PATCH 2/3] commented unused variables --- src/components/NowPlaying.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/NowPlaying.tsx b/src/components/NowPlaying.tsx index ab3ea92..38f37bc 100644 --- a/src/components/NowPlaying.tsx +++ b/src/components/NowPlaying.tsx @@ -27,8 +27,8 @@ const mockSong: Song = { export default function NowPlaying() { const [isPlaying, setIsPlaying] = useState(false); - const [currentTime, setCurrentTime] = useState(30); // 0:30 seconds - const [currentLyricIndex, setCurrentLyricIndex] = useState(0); + // const [currentTime, setCurrentTime] = useState(30); // 0:30 seconds + // const [currentLyricIndex, setCurrentLyricIndex] = useState(0); const handlePlay = () => { setIsPlaying(true); From 3e52b3ecb3eb8fd1a6e2e9aa0ecc29e9153b31a3 Mon Sep 17 00:00:00 2001 From: Rafiuzzaman Khan Date: Tue, 24 Feb 2026 14:51:34 -0500 Subject: [PATCH 3/3] removed CurrentTime and CurrentLyricIndex --- src/components/NowPlaying.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/NowPlaying.tsx b/src/components/NowPlaying.tsx index 38f37bc..56f6d12 100644 --- a/src/components/NowPlaying.tsx +++ b/src/components/NowPlaying.tsx @@ -27,8 +27,8 @@ const mockSong: Song = { export default function NowPlaying() { const [isPlaying, setIsPlaying] = useState(false); - // const [currentTime, setCurrentTime] = useState(30); // 0:30 seconds - // const [currentLyricIndex, setCurrentLyricIndex] = useState(0); + const [currentTime] = useState(0); // 0:30 seconds + const [currentLyricIndex] = useState(0); const handlePlay = () => { setIsPlaying(true);