| <!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> |