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 */}
+
+

+
+
+ {/* 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);