|
|
<!DOCTYPE html> |
|
|
<html lang="es"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Sherlock Music - Tu Estación de Música</title> |
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
|
|
<style> |
|
|
* { |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
box-sizing: border-box; |
|
|
} |
|
|
|
|
|
:root { |
|
|
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
|
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
|
|
--dark-bg: #0f0f23; |
|
|
--card-bg: rgba(255, 255, 255, 0.05); |
|
|
--glass-bg: rgba(255, 255, 255, 0.1); |
|
|
--text-primary: #ffffff; |
|
|
--text-secondary: #b0b3b8; |
|
|
--accent: #ff6b6b; |
|
|
--success: #51cf66; |
|
|
} |
|
|
|
|
|
body { |
|
|
font-family: 'Inter', sans-serif; |
|
|
background: var(--dark-bg); |
|
|
color: var(--text-primary); |
|
|
overflow-x: hidden; |
|
|
min-height: 100vh; |
|
|
} |
|
|
|
|
|
|
|
|
.bg-animation { |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
z-index: -1; |
|
|
background: radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), |
|
|
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%), |
|
|
radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.2) 0%, transparent 50%); |
|
|
animation: float 20s ease-in-out infinite; |
|
|
} |
|
|
|
|
|
@keyframes float { |
|
|
0%, 100% { transform: translateY(0px) rotate(0deg); } |
|
|
50% { transform: translateY(-20px) rotate(1deg); } |
|
|
} |
|
|
|
|
|
|
|
|
.header { |
|
|
position: fixed; |
|
|
top: 0; |
|
|
width: 100%; |
|
|
padding: 1rem 2rem; |
|
|
backdrop-filter: blur(20px); |
|
|
background: var(--glass-bg); |
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
|
|
z-index: 1000; |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
.logo { |
|
|
font-size: 1.8rem; |
|
|
font-weight: 700; |
|
|
background: var(--primary-gradient); |
|
|
-webkit-background-clip: text; |
|
|
-webkit-text-fill-color: transparent; |
|
|
background-clip: text; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 0.5rem; |
|
|
} |
|
|
|
|
|
.header-actions { |
|
|
display: flex; |
|
|
gap: 1rem; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
.theme-toggle { |
|
|
background: var(--card-bg); |
|
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
|
color: var(--text-primary); |
|
|
padding: 0.8rem; |
|
|
border-radius: 50%; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s ease; |
|
|
font-size: 1.1rem; |
|
|
} |
|
|
|
|
|
.theme-toggle:hover { |
|
|
background: var(--glass-bg); |
|
|
transform: scale(1.05); |
|
|
} |
|
|
|
|
|
|
|
|
.main-content { |
|
|
margin-top: 80px; |
|
|
padding: 2rem; |
|
|
max-width: 1400px; |
|
|
margin-left: auto; |
|
|
margin-right: auto; |
|
|
} |
|
|
|
|
|
|
|
|
.hero { |
|
|
text-align: center; |
|
|
margin-bottom: 4rem; |
|
|
padding: 2rem; |
|
|
} |
|
|
|
|
|
.hero h1 { |
|
|
font-size: clamp(2.5rem, 5vw, 4rem); |
|
|
font-weight: 700; |
|
|
margin-bottom: 1rem; |
|
|
background: var(--primary-gradient); |
|
|
-webkit-background-clip: text; |
|
|
-webkit-text-fill-color: transparent; |
|
|
background-clip: text; |
|
|
} |
|
|
|
|
|
.hero p { |
|
|
font-size: 1.3rem; |
|
|
color: var(--text-secondary); |
|
|
max-width: 600px; |
|
|
margin: 0 auto; |
|
|
} |
|
|
|
|
|
|
|
|
.music-player { |
|
|
background: var(--card-bg); |
|
|
backdrop-filter: blur(20px); |
|
|
border-radius: 24px; |
|
|
padding: 2.5rem; |
|
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
|
margin-bottom: 3rem; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.music-player::before { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
right: 0; |
|
|
height: 4px; |
|
|
background: var(--primary-gradient); |
|
|
border-radius: 24px 24px 0 0; |
|
|
} |
|
|
|
|
|
.album-art { |
|
|
width: 200px; |
|
|
height: 200px; |
|
|
border-radius: 20px; |
|
|
margin: 0 auto 2rem; |
|
|
background: var(--primary-gradient); |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 4rem; |
|
|
color: white; |
|
|
animation: rotate 20s linear infinite paused; |
|
|
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3); |
|
|
} |
|
|
|
|
|
.album-art.playing { |
|
|
animation-play-state: running; |
|
|
} |
|
|
|
|
|
@keyframes rotate { |
|
|
from { transform: rotate(0deg); } |
|
|
to { transform: rotate(360deg); } |
|
|
} |
|
|
|
|
|
.track-info h2 { |
|
|
font-size: 1.8rem; |
|
|
margin-bottom: 0.5rem; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.track-artist { |
|
|
color: var(--text-secondary); |
|
|
text-align: center; |
|
|
margin-bottom: 2rem; |
|
|
} |
|
|
|
|
|
.progress-container { |
|
|
margin-bottom: 2rem; |
|
|
} |
|
|
|
|
|
.progress-bar { |
|
|
width: 100%; |
|
|
height: 6px; |
|
|
background: rgba(255, 255, 255, 0.1); |
|
|
border-radius: 3px; |
|
|
overflow: hidden; |
|
|
cursor: pointer; |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.progress { |
|
|
height: 100%; |
|
|
background: var(--primary-gradient); |
|
|
width: 0%; |
|
|
border-radius: 3px; |
|
|
transition: width 0.1s ease; |
|
|
} |
|
|
|
|
|
.time-display { |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
margin-bottom: 2rem; |
|
|
font-size: 0.9rem; |
|
|
color: var(--text-secondary); |
|
|
} |
|
|
|
|
|
.controls { |
|
|
display: flex; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
gap: 2rem; |
|
|
margin-bottom: 1rem; |
|
|
} |
|
|
|
|
|
.control-btn { |
|
|
width: 60px; |
|
|
height: 60px; |
|
|
border-radius: 50%; |
|
|
border: none; |
|
|
background: var(--glass-bg); |
|
|
color: var(--text-primary); |
|
|
font-size: 1.3rem; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s ease; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
} |
|
|
|
|
|
.control-btn:hover { |
|
|
background: var(--primary-gradient); |
|
|
transform: scale(1.1); |
|
|
} |
|
|
|
|
|
.play-pause { |
|
|
width: 80px; |
|
|
height: 80px; |
|
|
font-size: 1.8rem; |
|
|
background: var(--primary-gradient); |
|
|
} |
|
|
|
|
|
.play-pause:hover { |
|
|
transform: scale(1.05); |
|
|
} |
|
|
|
|
|
.volume-container { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 1rem; |
|
|
justify-content: center; |
|
|
} |
|
|
|
|
|
.volume-bar { |
|
|
width: 120px; |
|
|
height: 4px; |
|
|
background: rgba(255, 255, 255, 0.1); |
|
|
border-radius: 2px; |
|
|
cursor: pointer; |
|
|
} |
|
|
|
|
|
|
|
|
.playlist-section { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); |
|
|
gap: 2rem; |
|
|
margin-bottom: 3rem; |
|
|
} |
|
|
|
|
|
.playlist-card { |
|
|
background: var(--card-bg); |
|
|
backdrop-filter: blur(20px); |
|
|
border-radius: 20px; |
|
|
padding: 2rem; |
|
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
|
transition: all 0.3s ease; |
|
|
cursor: pointer; |
|
|
} |
|
|
|
|
|
.playlist-card:hover { |
|
|
transform: translateY(-10px); |
|
|
border-color: rgba(255, 255, 255, 0.2); |
|
|
} |
|
|
|
|
|
.playlist-card.playing { |
|
|
border-color: var(--accent); |
|
|
box-shadow: 0 20px 40px rgba(255, 107, 107, 0.3); |
|
|
} |
|
|
|
|
|
.playlist-icon { |
|
|
width: 60px; |
|
|
height: 60px; |
|
|
border-radius: 12px; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 1.5rem; |
|
|
margin-bottom: 1rem; |
|
|
} |
|
|
|
|
|
.playlist-1 .playlist-icon { background: var(--primary-gradient); } |
|
|
.playlist-2 .playlist-icon { background: var(--secondary-gradient); } |
|
|
.playlist-3 .playlist-icon { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); } |
|
|
|
|
|
.playlist-title { |
|
|
font-size: 1.3rem; |
|
|
font-weight: 600; |
|
|
margin-bottom: 0.5rem; |
|
|
} |
|
|
|
|
|
.playlist-tracks { |
|
|
font-size: 0.9rem; |
|
|
color: var(--text-secondary); |
|
|
} |
|
|
|
|
|
|
|
|
.recently-section { |
|
|
margin-top: 3rem; |
|
|
} |
|
|
|
|
|
.section-title { |
|
|
font-size: 2rem; |
|
|
margin-bottom: 2rem; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 1rem; |
|
|
} |
|
|
|
|
|
.tracks-grid { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); |
|
|
gap: 1.5rem; |
|
|
} |
|
|
|
|
|
.track-item { |
|
|
background: var(--card-bg); |
|
|
border-radius: 16px; |
|
|
padding: 1.5rem; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s ease; |
|
|
border: 1px solid transparent; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.track-item::before { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
right: 0; |
|
|
height: 3px; |
|
|
background: var(--primary-gradient); |
|
|
transform: scaleX(0); |
|
|
transition: transform 0.3s ease; |
|
|
} |
|
|
|
|
|
.track-item:hover::before { |
|
|
transform: scaleX(1); |
|
|
} |
|
|
|
|
|
.track-item:hover { |
|
|
transform: translateY(-5px); |
|
|
border-color: rgba(255, 255, 255, 0.2); |
|
|
} |
|
|
|
|
|
.track-item.active { |
|
|
border-color: var(--accent); |
|
|
} |
|
|
|
|
|
.track-thumb { |
|
|
width: 50px; |
|
|
height: 50px; |
|
|
border-radius: 8px; |
|
|
background: var(--primary-gradient); |
|
|
margin-bottom: 1rem; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 1.2rem; |
|
|
} |
|
|
|
|
|
.track-title { |
|
|
font-weight: 500; |
|
|
margin-bottom: 0.3rem; |
|
|
} |
|
|
|
|
|
.track-duration { |
|
|
color: var(--text-secondary); |
|
|
font-size: 0.9rem; |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 768px) { |
|
|
.main-content { |
|
|
padding: 1rem; |
|
|
margin-top: 100px; |
|
|
} |
|
|
|
|
|
.header { |
|
|
padding: 1rem; |
|
|
} |
|
|
|
|
|
.controls { |
|
|
gap: 1rem; |
|
|
} |
|
|
|
|
|
.playlist-section { |
|
|
grid-template-columns: 1fr; |
|
|
} |
|
|
|
|
|
.tracks-grid { |
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
::-webkit-scrollbar { |
|
|
width: 8px; |
|
|
} |
|
|
|
|
|
::-webkit-scrollbar-track { |
|
|
background: rgba(255, 255, 255, 0.05); |
|
|
} |
|
|
|
|
|
::-webkit-scrollbar-thumb { |
|
|
background: var(--primary-gradient); |
|
|
border-radius: 4px; |
|
|
} |
|
|
|
|
|
|
|
|
@keyframes pulse { |
|
|
0%, 100% { opacity: 1; } |
|
|
50% { opacity: 0.7; } |
|
|
} |
|
|
|
|
|
.pulse { |
|
|
animation: pulse 2s infinite; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="bg-animation"></div> |
|
|
|
|
|
<header class="header"> |
|
|
<div class="logo"> |
|
|
<i class="fas fa-music"></i> |
|
|
Sherlock Music |
|
|
</div> |
|
|
<div class="header-actions"> |
|
|
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" |
|
|
style="color: var(--text-primary); text-decoration: none; font-weight: 500;"> |
|
|
Built with anycoder |
|
|
</a> |
|
|
<div class="theme-toggle" id="themeToggle"> |
|
|
<i class="fas fa-moon"></i> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
<main class="main-content"> |
|
|
<section class="hero"> |
|
|
<h1>Tu Estación de Música</h1> |
|
|
<p>Descubre nueva música, crea tus listas personalizadas y disfruta de una experiencia única con nuestro reproductor premium.</p> |
|
|
</section> |
|
|
|
|
|
<section class="music-player" id="musicPlayer"> |
|
|
<div class="album-art" id="albumArt"> |
|
|
<i class="fas fa-music"></i> |
|
|
</div> |
|
|
<div class="track-info"> |
|
|
<h2 id="trackTitle">Canción Actual</h2> |
|
|
<p class="track-artist" id="trackArtist">Artista Desconocido</p> |
|
|
</div> |
|
|
|
|
|
<div class="progress-container"> |
|
|
<div class="progress-bar" id="progressBar"> |
|
|
<div class="progress" id="progress"></div> |
|
|
</div> |
|
|
<div class="time-display"> |
|
|
<span id="currentTime">0:00</span> |
|
|
<span id="duration">0:00</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="controls"> |
|
|
<button class="control-btn" id="prevBtn"> |
|
|
<i class="fas fa-step-backward"></i> |
|
|
</button> |
|
|
<button class="control-btn play-pause" id="playPauseBtn"> |
|
|
<i class="fas fa-play"></i> |
|
|
</button> |
|
|
<button class="control-btn" id="nextBtn"> |
|
|
<i class="fas fa-step-forward"></i> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div class="volume-container"> |
|
|
<i class="fas fa-volume-up"></i> |
|
|
<div class="volume-bar" id="volumeBar"></div> |
|
|
</div> |
|
|
</section> |
|
|
|
|
|
<section class="playlist-section"> |
|
|
<div class="playlist-card playlist-1" data-playlist="1"> |
|
|
<div class="playlist-icon"> |
|
|
<i class="fas fa-guitar"></i> |
|
|
</div> |
|
|
<div class="playlist-title">Pop Hits 2024</div> |
|
|
<div class="playlist-tracks">12 canciones • 45 min</div> |
|
|
</div> |
|
|
<div class="playlist-card playlist-2" data-playlist="2"> |
|
|
<div class="playlist-icon"> |
|
|
<i class="fas fa-drum"></i> |
|
|
</div> |
|
|
<div class="playlist-title">Rock Clásico</div> |
|
|
<div class="playlist-tracks">15 canciones • 1h 2min</div> |
|
|
</div> |
|
|
<div class="playlist-card playlist-3" data-playlist="3"> |
|
|
<div class="playlist-icon"> |
|
|
<i class="fas fa-headphones"></i> |
|
|
</div> |
|
|
<div class="playlist-title">Chill Vibes</div> |
|
|
<div class="playlist-tracks">20 canciones • 1h 30min</div> |
|
|
</div> |
|
|
</section> |
|
|
|
|
|
<section class="recently-section"> |
|
|
<h2 class="section-title"> |
|
|
<i class="fas fa-history"></i> |
|
|
Reproducidas Recientemente |
|
|
</h2> |
|
|
<div class="tracks-grid" id="tracksGrid"> |
|
|
|
|
|
</div> |
|
|
</section> |
|
|
</main> |
|
|
|
|
|
<script> |
|
|
class MusicPlayer { |
|
|
constructor() { |
|
|
this.audio = new Audio(); |
|
|
this.audio.volume = 0.5; |
|
|
this.isPlaying = false; |
|
|
this.currentTrack = 0; |
|
|
this.tracks = [ |
|
|
{ title: "Noche Estelar", artist: "Luna Vargas", duration: "3:45", color: "#667eea" }, |
|
|
{ title: "Ritmo Urbano", artist: "DJ Flow", duration: "2:58", color: "#f093fb" }, |
|
|
{ title: "Sueños Rotos", artist: "Marta Sol", duration: "4:12", color: "#4facfe" }, |
|
|
{ title: "Fuego en la Pista", artist: "Carlos Rey", duration: "3:22", color: "#ff6b6b" }, |
|
|
{ title: "Alma Libre", artist: "Sofía Luna", duration: "4:01", color: "#51cf66" }, |
|
|
{ title: "Eco del Tiempo", artist: "Raúl Mendoza", duration: "3:37", color: "#764ba2" } |
|
|
]; |
|
|
|
|
|
this.playlists = { |
|
|
1: ["Noche Estelar", "Ritmo Urbano", "Sueños Rotos"], |
|
|
2: ["Fuego en la Pista", "Eco del Tiempo"], |
|
|
3: ["Alma Libre", "Sueños Rotos"] |
|
|
}; |
|
|
|
|
|
this.init(); |
|
|
} |
|
|
|
|
|
init() { |
|
|
this.bindEvents(); |
|
|
this.loadTrack(0); |
|
|
this.renderTracks(); |
|
|
this.updateVolumeBar(); |
|
|
} |
|
|
|
|
|
bindEvents() { |
|
|
|
|
|
document.getElementById('playPauseBtn').addEventListener('click', () => this.togglePlay()); |
|
|
document.getElementById('prevBtn').addEventListener('click', () => this.prevTrack()); |
|
|
document.getElementById('nextBtn').addEventListener('click', () => this.nextTrack()); |
|
|
|
|
|
|
|
|
const progressBar = document.getElementById('progressBar'); |
|
|
progressBar.addEventListener('click', (e) => this.setProgress(e)); |
|
|
|
|
|
|
|
|
const volumeBar = document.getElementById('volumeBar'); |
|
|
volumeBar.addEventListener('click', (e) => this.setVolume(e)); |
|
|
|
|
|
|
|
|
this.audio.addEventListener('timeupdate', () => this.updateProgress()); |
|
|
this.audio.addEventListener('loadedmetadata', () => this.updateDuration()); |
|
|
this.audio.addEventListener('ended', () => this.nextTrack()); |
|
|
|
|
|
|
|
|
document.querySelectorAll('.playlist-card').forEach(card => { |
|
|
card.addEventListener('click', (e) => this.playPlaylist(card.dataset.playlist)); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
|
if (e.target.closest('.track-item')) { |
|
|
const index = parseInt(e.target.closest('.track-item').dataset.index); |
|
|
this.loadTrack(index); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (e) => { |
|
|
if (e.code === 'Space') { |
|
|
e.preventDefault(); |
|
|
this.togglePlay(); |
|
|
} else if (e.code === 'ArrowLeft') { |
|
|
this.prevTrack(); |
|
|
} else if (e.code === 'ArrowRight') { |
|
|
this.nextTrack(); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
loadTrack(index) { |
|
|
this.currentTrack = index; |
|
|
const track = this.tracks[index]; |
|
|
|
|
|
document.getElementById('trackTitle').textContent = track.title; |
|
|
document.getElementById('trackArtist').textContent = track.artist; |
|
|
|
|
|
|
|
|
const albumArt = document.getElementById('albumArt'); |
|
|
albumArt.style.background = track.color; |
|
|
|
|
|
|
|
|
this.audio.currentTime = 0; |
|
|
this.audio.pause(); |
|
|
this.isPlaying = false; |
|
|
|
|
|
this.updateActiveTrack(); |
|
|
this.updatePlayButton(); |
|
|
} |
|
|
|
|
|
togglePlay() { |
|
|
if (this.isPlaying) { |
|
|
this.audio.pause(); |
|
|
} else { |
|
|
this.audio.play(); |
|
|
document.getElementById('albumArt').classList.add('playing'); |
|
|
} |
|
|
this.isPlaying = !this.isPlaying; |
|
|
this.updatePlayButton(); |
|
|
} |
|
|
|
|
|
nextTrack() { |
|
|
this.loadTrack((this.currentTrack + 1) % this.tracks.length); |
|
|
if (this.isPlaying) { |
|
|
this.audio.play(); |
|
|
document.getElementById('albumArt').classList.add('playing'); |
|
|
} |
|
|
} |
|
|
|
|
|
prevTrack() { |
|
|
this.loadTrack((this.currentTrack - 1 + this.tracks.length) % this.tracks.length); |
|
|
if (this.isPlaying) { |
|
|
this.audio.play(); |
|
|
document.getElementById('albumArt').classList.add('playing'); |
|
|
} |
|
|
} |
|
|
|
|
|
playPlaylist(playlistId) { |
|
|
const playlistTracks = this.playlists[playlistId]; |
|
|
const firstTrackIndex = this.tracks.findIndex(track => |
|
|
playlistTracks.includes(track.title) |
|
|
); |
|
|
this.loadTrack(firstTrackIndex); |
|
|
this.togglePlay(); |
|
|
} |
|
|
|
|
|
updatePlayButton() { |
|
|
const btn = document.getElementById('playPauseBtn'); |
|
|
const icon = btn.querySelector('i'); |
|
|
icon.className = this.isPlaying ? 'fas fa-pause' : 'fas fa-play'; |
|
|
} |
|
|
|
|
|
updateProgress() { |
|
|
if (this.audio.duration) { |
|
|
const progress = (this.audio.currentTime / this.audio.duration) * 100; |
|
|
document.getElementById('progress').style.width = progress + '%'; |
|
|
document.getElementById('currentTime').textContent = |
|
|
this.formatTime(this.audio.currentTime); |
|
|
} |
|
|
} |
|
|
|
|
|
updateDuration() { |
|
|
document.getElementById('duration').textContent = |
|
|
this.formatTime(this.audio.duration); |
|
|
} |
|
|
|
|
|
setProgress(e) { |
|
|
const progressBar = document.getElementById('progressBar'); |
|
|
const rect = progressBar.getBoundingClientRect(); |
|
|
const pos = (e.clientX - rect.left) / rect.width; |
|
|
this.audio.currentTime = pos * this.audio.duration; |
|
|
} |
|
|
|
|
|
setVolume(e) { |
|
|
const volumeBar = document.getElementById('volumeBar'); |
|
|
const rect = volumeBar.getBoundingClientRect(); |
|
|
const pos = (e.clientX - rect.left) / rect.width; |
|
|
this.audio.volume = Math.max(0, Math.min(1, pos)); |
|
|
this.updateVolumeBar(); |
|
|
} |
|
|
|
|
|
updateVolumeBar() { |
|
|
const volumeBar = document.getElementById('volumeBar'); |
|
|
const progress = document.createElement('div'); |
|
|
progress.style.width = (this.audio.volume * 100) + '%'; |
|
|
progress.style.height = '100%'; |
|
|
progress.style.background = 'var(--primary-gradient)'; |
|
|
progress.style.borderRadius = '2px'; |
|
|
progress.style.transition = 'width 0.1s ease'; |
|
|
volumeBar.innerHTML = ''; |
|
|
volumeBar.appendChild(progress); |
|
|
} |
|
|
|
|
|
formatTime(seconds) { |
|
|
const mins = Math.floor(seconds / 60); |
|
|
const secs = Math.floor(seconds % 60); |
|
|
return `${mins}:${secs.toString().padStart(2, '0')}`; |
|
|
} |
|
|
|
|
|
renderTracks() { |
|
|
const container = document.getElementById('tracksGrid'); |
|
|
container.innerHTML = this.tracks.map((track, index) => ` |
|
|
<div class="track-item" data-index="${index}"> |
|
|
<div class="track-thumb" style="background: ${track.color}"> |
|
|
<i class="fas fa-music"></i> |
|
|
</div> |
|
|
<div class="track-title">${track.title}</div> |
|
|
<div class="track-duration">${track.artist} • ${track.duration}</div> |
|
|
</div> |
|
|
`).join(''); |
|
|
} |
|
|
|
|
|
updateActiveTrack() { |
|
|
document.querySelectorAll('.track-item').forEach((item, index) => { |
|
|
item.classList.toggle('active', index === this.currentTrack); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
new MusicPlayer(); |
|
|
}); |
|
|
|
|
|
|
|
|
setInterval(() => { |
|
|
if (document.getElementById('albumArt').classList.contains('playing')) { |
|
|
const albumArt = document.getElementById('albumArt'); |
|
|
const scale = 1 + Math.sin(Date.now() / 200) * 0.05; |
|
|
albumArt.style.transform = `scale(${scale})`; |
|
|
} |
|
|
}, 100); |
|
|
</script> |
|
|
</body> |
|
|
</html> |