Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>SoundWave HTMX 🎶 - Spotify-like Music Player</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <link rel="stylesheet" href="style.css"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/htmx.org@1.9.10"></script> | |
| <script src="https://unpkg.com/htmx.org/dist/ext/sse.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <style> | |
| :root { | |
| --primary-color: #1DB954; | |
| --secondary-color: #191414; | |
| --background-color: #121212; | |
| --sidebar-color: #000000; | |
| --player-color: #181818; | |
| --card-bg: rgba(255, 255, 255, 0.05); | |
| --card-hover: rgba(255, 255, 255, 0.1); | |
| } | |
| body { | |
| background: linear-gradient(135deg, #121212 0%, #1a1a1a 100%); | |
| color: white; | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | |
| height: 100vh; | |
| overflow: hidden; | |
| } | |
| .glass-card { | |
| background: var(--card-bg); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 12px; | |
| } | |
| .track-item { | |
| transition: all 0.3s ease; | |
| border-radius: 8px; | |
| margin: 2px 0; | |
| } | |
| .track-item:hover { | |
| background: var(--card-hover); | |
| transform: translateY(-1px); | |
| } | |
| .track-item.active { | |
| background: linear-gradient(90deg, rgba(29, 185, 84, 0.2), transparent); | |
| border-left: 3px solid var(--primary-color); | |
| } | |
| .track-item.dragging { | |
| opacity: 0.8; | |
| background: rgba(29, 185, 84, 0.3); | |
| transform: rotate(2deg); | |
| z-index: 1000; | |
| } | |
| .track-item.drag-over { | |
| border-top: 2px solid var(--primary-color); | |
| } | |
| .progress-bar { | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 4px; | |
| height: 4px; | |
| outline: none; | |
| appearance: none; | |
| cursor: pointer; | |
| } | |
| .progress-bar::-webkit-slider-thumb { | |
| appearance: none; | |
| width: 12px; | |
| height: 12px; | |
| border-radius: 50%; | |
| background: var(--primary-color); | |
| cursor: pointer; | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| } | |
| .progress-bar:hover::-webkit-slider-thumb { | |
| opacity: 1; | |
| } | |
| .volume-slider { | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 4px; | |
| height: 4px; | |
| outline: none; | |
| appearance: none; | |
| } | |
| .volume-slider::-webkit-slider-thumb { | |
| appearance: none; | |
| width: 14px; | |
| height: 14px; | |
| border-radius: 50%; | |
| background: white; | |
| cursor: pointer; | |
| border: 2px solid var(--primary-color); | |
| } | |
| .sidebar-gradient { | |
| background: linear-gradient(180deg, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.9)); | |
| } | |
| .player-gradient { | |
| background: linear-gradient(90deg, rgba(24, 24, 24, 0.95), rgba(18, 18, 18, 0.95)); | |
| } | |
| .button-spotify { | |
| background: var(--primary-color); | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 15px rgba(29, 185, 84, 0.3); | |
| } | |
| .button-spotify:hover { | |
| background: #1ed760; | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 20px rgba(29, 185, 84, 0.4); | |
| } | |
| .scrollbar-custom::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| .scrollbar-custom::-webkit-scrollbar-track { | |
| background: rgba(255, 255, 255, 0.05); | |
| border-radius: 4px; | |
| } | |
| .scrollbar-custom::-webkit-scrollbar-thumb { | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 4px; | |
| } | |
| .scrollbar-custom::-webkit-scrollbar-thumb:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| } | |
| .pulse-playing { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .playlist-container { | |
| max-height: calc(100vh - 320px); | |
| overflow-y: auto; | |
| } | |
| .drag-handle { | |
| cursor: grab; | |
| opacity: 0.5; | |
| transition: opacity 0.2s; | |
| } | |
| .track-item:hover .drag-handle { | |
| opacity: 1; | |
| } | |
| .drag-handle:active { | |
| cursor: grabbing; | |
| } | |
| </style> | |
| </head> | |
| <body class="h-screen flex flex-col"> | |
| <!-- Header --> | |
| <header class="p-4 glass-card mx-4 mt-4 rounded-xl"> | |
| <div class="flex justify-between items-center"> | |
| <div class="flex items-center space-x-4"> | |
| <button class="rounded-full p-2 hover:bg-white hover:bg-opacity-10 transition-colors"> | |
| <i data-feather="arrow-left"></i> | |
| </button> | |
| <button class="rounded-full p-2 hover:bg-white hover:bg-opacity-10 transition-colors"> | |
| <i data-feather="arrow-right"></i> | |
| </button> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button class="bg-white bg-opacity-10 hover:bg-opacity-20 px-4 py-2 rounded-full text-sm font-medium transition-all"> | |
| Explore Premium | |
| </button> | |
| <button class="rounded-full p-2 hover:bg-white hover:bg-opacity-10 transition-colors"> | |
| <i data-feather="user"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="flex flex-1 overflow-hidden px-4 pb-4"> | |
| <!-- Sidebar --> | |
| <aside class="w-72 sidebar-gradient rounded-xl mr-4 p-6 flex flex-col"> | |
| <div class="mb-8"> | |
| <h1 class="text-2xl font-bold flex items-center bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent"> | |
| <i data-feather="music" class="mr-3 text-green-400"></i> | |
| SoundWave HTMX | |
| </h1> | |
| </div> | |
| <nav class="space-y-2 mb-8"> | |
| <a href="#" class="flex items-center space-x-4 p-3 rounded-lg bg-white bg-opacity-10 hover:bg-opacity-20 transition-all"> | |
| <i data-feather="home"></i> | |
| <span class="font-medium">Home</span> | |
| </a> | |
| <a href="#" class="flex items-center space-x-4 p-3 rounded-lg hover:bg-white hover:bg-opacity-10 transition-all"> | |
| <i data-feather="search"></i> | |
| <span class="font-medium">Search</span> | |
| </a> | |
| <a href="#" class="flex items-center space-x-4 p-3 rounded-lg hover:bg-white hover:bg-opacity-10 transition-all"> | |
| <i data-feather="book-open"></i> | |
| <span class="font-medium">Your Library</span> | |
| </a> | |
| </nav> | |
| <div class="mt-auto space-y-4"> | |
| <button class="w-full flex items-center space-x-3 p-3 rounded-lg hover:bg-white hover:bg-opacity-10 transition-all"> | |
| <i data-feather="plus-square"></i> | |
| <span class="font-medium">Create Playlist</span> | |
| </button> | |
| <button class="w-full flex items-center space-x-3 p-3 rounded-lg hover:bg-white hover:bg-opacity-10 transition-all"> | |
| <i data-feather="heart"></i> | |
| <span class="font-medium">Liked Songs</span> | |
| </button> | |
| <hr class="border-white border-opacity-20"> | |
| <div class="space-y-2"> | |
| <button class="w-full flex items-center space-x-3 p-2 rounded hover:bg-white hover:bg-opacity-10 transition-all"> | |
| <i data-feather="download"></i> | |
| <span class="text-sm">Install App</span> | |
| </button> | |
| <button class="w-full flex items-center space-x-3 p-2 rounded hover:bg-white hover:bg-opacity-10 transition-all"> | |
| <i data-feather="settings"></i> | |
| <span class="text-sm">Settings</span> | |
| </button> | |
| </div> | |
| </div> | |
| </aside> | |
| <!-- Main Content --> | |
| <main class="flex-1 overflow-auto"> | |
| <div class="glass-card rounded-xl p-8 h-full"> | |
| <div class="mb-8"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-4xl font-bold bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent"> | |
| Good afternoon | |
| </h2> | |
| <div class="flex space-x-3"> | |
| <button class="p-2 rounded-full hover:bg-white hover:bg-opacity-10 transition-colors"> | |
| <i data-feather="grid-3x3"></i> | |
| </button> | |
| <button class="p-2 rounded-full hover:bg-white hover:bg-opacity-10 transition-colors"> | |
| <i data-feather="list"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="flex items-center mb-8"> | |
| <button id="select-folder-btn" class="button-spotify px-6 py-3 rounded-full flex items-center font-medium"> | |
| <i data-feather="folder" class="mr-3"></i> | |
| Select Music Folder | |
| </button> | |
| <input type="file" id="folder-input" webkitdirectory directory multiple class="hidden"> | |
| <div id="track-count" class="ml-6 text-sm text-gray-400"> | |
| No tracks loaded | |
| </div> | |
| </div> | |
| </div> | |
| <div class="glass-card rounded-xl p-6"> | |
| <div id="playlist-header" class="grid grid-cols-12 gap-4 px-4 py-3 text-gray-400 border-b border-white border-opacity-20 text-sm font-medium"> | |
| <div class="col-span-1 flex items-center"> | |
| <span>#</span> | |
| <i data-feather="move" class="ml-2 w-4 h-4 drag-handle"></i> | |
| </div> | |
| <div class="col-span-5">Title</div> | |
| <div class="col-span-3">Album</div> | |
| <div class="col-span-2">Duration</div> | |
| <div class="col-span-1"></div> | |
| </div> | |
| <div id="tracks-list" class="scrollbar-custom divide-y divide-white divide-opacity-10 playlist-container"> | |
| <!-- Tracks will be populated here --> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <!-- Player --> | |
| <div id="player" class="player-gradient border-t border-white border-opacity-10 p-4"> | |
| <div class="max-w-7xl mx-auto grid grid-cols-3 gap-6 items-center"> | |
| <!-- Current Track Info --> | |
| <div class="flex items-center space-x-4"> | |
| <div id="current-track-cover" class="bg-gradient-to-br from-purple-500 to-pink-500 w-16 h-16 rounded-lg shadow-lg flex items-center justify-center"> | |
| <i data-feather="music" class="text-white"></i> | |
| </div> | |
| <div class="min-w-0 flex-1"> | |
| <div id="current-track-title" class="font-semibold truncate">No track selected</div> | |
| <div id="current-track-artist" class="text-sm text-gray-400 truncate">Unknown artist</div> | |
| </div> | |
| <button id="favorite-btn" class="text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="heart"></i> | |
| </button> | |
| </div> | |
| <!-- Player Controls --> | |
| <div class="flex flex-col items-center"> | |
| <div class="flex items-center space-x-6 mb-3"> | |
| <button id="shuffle-btn" class="text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="shuffle"></i> | |
| </button> | |
| <button id="prev-btn" class="text-white hover:text-green-400 transition-colors"> | |
| <i data-feather="skip-back"></i> | |
| </button> | |
| <button id="play-pause-btn" class="bg-white text-black rounded-full p-3 hover:bg-green-400 hover:text-white transition-all transform hover:scale-105"> | |
| <i data-feather="play" class="w-5 h-5"></i> | |
| </button> | |
| <button id="next-btn" class="text-white hover:text-green-400 transition-colors"> | |
| <i data-feather="skip-forward"></i> | |
| </button> | |
| <button id="repeat-btn" class="text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="repeat"></i> | |
| </button> | |
| </div> | |
| <div class="w-full flex items-center space-x-3"> | |
| <span id="current-time" class="text-xs text-gray-400 min-w-[40px]">0:00</span> | |
| <input type="range" id="progress-bar" class="progress-bar flex-1" value="0" min="0" max="100"> | |
| <span id="total-time" class="text-xs text-gray-400 min-w-[40px]">0:00</span> | |
| </div> | |
| </div> | |
| <!-- Volume Control --> | |
| <div class="flex items-center justify-end space-x-4"> | |
| <button id="lyrics-btn" class="text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="align-left"></i> | |
| </button> | |
| <button id="queue-btn" class="text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="list"></i> | |
| </button> | |
| <div class="flex items-center space-x-3"> | |
| <button id="volume-btn" class="text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="volume-2"></i> | |
| </button> | |
| <input type="range" id="volume-slider" class="volume-slider w-24" value="80" min="0" max="100"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- HTMX for dynamic updates --> | |
| <script src="script.js"></script> | |
| <script> | |
| // Enhanced feather icons replacement | |
| feather.replace(); | |
| // Smooth transitions for interactive elements | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Add subtle animation to buttons | |
| const buttons = document.querySelectorAll('button'); | |
| buttons.forEach(button => { | |
| button.addEventListener('mouseenter', () => { | |
| button.style.transform = 'translateY(-1px)'; | |
| }); | |
| button.addEventListener('mouseleave', () => { | |
| button.style.transform = 'translateY(0)'; | |
| }); | |
| }); | |
| }); | |
| </script> | |
| <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script> | |
| </body> | |
| </html> | |