Skip to content

Instantly share code, notes, and snippets.

@gestisch2025
Created June 10, 2025 08:25
Show Gist options
  • Save gestisch2025/e35c634c78bb8d17cfffbd6b131e2b64 to your computer and use it in GitHub Desktop.
Save gestisch2025/e35c634c78bb8d17cfffbd6b131e2b64 to your computer and use it in GitHub Desktop.
Untitled
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Audio Player</title>
<script src="https://cdn.tailwindcss.com"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
/>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="w-[320px] h-[320px] rounded-lg border-2 border-[#4a2f3a] shadow-lg bg-white flex flex-col">
<!-- Top bar -->
<div class="flex items-center justify-between bg-[#c18db0] rounded-t-lg border-b-2 border-[#4a2f3a] h-10 px-3">
<span class="text-white font-bold text-sm">Audio Player</span>
<button class="w-6 h-6 flex items-center justify-center border-2 border-white rounded-full text-white" aria-label="Close">×</button>
</div>
<!-- Main content -->
<div class="p-2 flex flex-col h-full justify-between">
<!-- File input for audio selection -->
<input type="file" id="audio-upload" accept="audio/*" class="mb-2 w-full border-2 border-[#4a2f3a] rounded-md p-1 text-sm" />
<!-- Progress bar with star as progress indicator -->
<div class="relative h-6 w-full bg-gray-200 border-2 border-[#4a2f3a] rounded-md mb-2">
<div id="progress-fill" class="absolute top-0 left-0 h-full bg-[#f9d9a7] rounded-md" style="width: 0%;"></div>
<button id="progress-star" class="absolute top-0 left-0 w-6 h-6 bg-[#f9d9a7] rounded-md border-2 border-[#4a2f3a] flex items-center justify-center cursor-pointer" aria-label="Seek">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3 text-[#4a2f3a]" fill="none" viewBox="0 0 24 24" stroke="#4a2f3a" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round">
<path stroke-linejoin="round" d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
</svg>
</button>
</div>
<!-- Controls -->
<div class="flex justify-between text-[#4a2f3a] mt-auto mb-4">
<button id="prev-btn" aria-label="Previous" class="w-8 h-10 flex items-center justify-center border-2 border-[#4a2f3a] rounded-md">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="#4a2f3a" stroke-width="2" stroke-linejoin="round" stroke-linecap="round">
<polygon points="15 19 8 12 15 5 15 19" />
</svg>
</button>
<button id="play-pause-btn" aria-label="Play" class="w-10 h-10 flex items-center justify-center border-2 border-[#4a2f3a] rounded-full bg-[#c18db0]">
<svg id="play-icon" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-[#4a2f3a]" fill="none" viewBox="0 0 24 24" stroke="#4a2f3a" stroke-width="2" stroke-linejoin="round" stroke-linecap="round">
<polygon points="5 3 19 12 5 21 5 3" />
</svg>
<svg id="pause-icon" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-[#4a2f3a] hidden" fill="none" viewBox="0 0 24 24" stroke="#4a2f3a" stroke-width="2" stroke-linejoin="round" stroke-linecap="round">
<rect x="6" y="5" width="4" height="14" rx="1" />
<rect x="14" y="5" width="4" height="14" rx="1" />
</svg>
</button>
<button id="next-btn" aria-label="Next" class="w-8 h-10 flex items-center justify-center border-2 border-[#4a2f3a] rounded-md">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="#4a2f3a" stroke-width="2" stroke-linejoin="round" stroke-linecap="round">
<polygon points="9 5 16 12 9 19 9 5" />
</svg>
</button>
</div>
<!-- Platz unter den Steuerelementen -->
<div class="flex-grow"></div>
</div>
</div>
<audio id="audio" src=""></audio>
<script>
const audio = document.getElementById('audio');
const playPauseBtn = document.getElementById('play-pause-btn');
const playIcon = document.getElementById('play-icon');
const pauseIcon = document.getElementById('pause-icon');
const progressFill = document.getElementById('progress-fill');
const progressStar = document.getElementById('progress-star');
const prevBtn = document.getElementById('prev-btn');
const nextBtn = document.getElementById('next-btn');
const audioUpload = document.getElementById('audio-upload');
// Load selected audio from file input
audioUpload.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
const fileURL = URL.createObjectURL(file);
audio.src = fileURL;
audio.currentTime = 0; // Reset to start
audio.play(); // Play the new track if a file is selected
}
});
// Play/pause toggle
playPauseBtn.addEventListener('click', () => {
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
});
audio.addEventListener('play', () => {
playIcon.classList.add('hidden');
pauseIcon.classList.remove('hidden');
playPauseBtn.setAttribute('aria-label', 'Pause');
});
audio.addEventListener('pause', () => {
playIcon.classList.remove('hidden');
pauseIcon.classList.add('hidden');
playPauseBtn.setAttribute('aria-label', 'Play');
});
// Update progress bar and star position
audio.addEventListener('timeupdate', () => {
if (!audio.duration) return;
const progressPercent = (audio.currentTime / audio.duration) * 100;
progressFill.style.width = progressPercent + '%';
const containerWidth = progressFill.parentElement.clientWidth;
const starWidth = progressStar.clientWidth;
let leftPos = (progressPercent / 100) * containerWidth - starWidth / 2;
if (leftPos < 0) leftPos = 0;
if (leftPos > containerWidth - starWidth) leftPos = containerWidth - starWidth;
progressStar.style.left = leftPos + 'px';
});
// Seek audio by clicking or dragging star
let isDragging = false;
function seekAudio(clientX) {
const rect = progressFill.parentElement.getBoundingClientRect();
let offsetX = clientX - rect.left;
if (offsetX < 0) offsetX = 0;
if (offsetX > rect.width) offsetX = rect.width;
const seekTime = (offsetX / rect.width) * audio.duration;
audio.currentTime = seekTime;
}
progressStar.addEventListener('mousedown', (e) => {
isDragging = true;
e.preventDefault();
});
window.addEventListener('mouseup', () => {
if (isDragging) isDragging = false;
});
window.addEventListener('mousemove', (e) => {
if (isDragging) {
seekAudio(e.clientX);
}
});
// Also allow clicking on progress bar to seek
progressStar.parentElement.addEventListener('click', (e) => {
seekAudio(e.clientX);
});
// Dummy prev/next buttons (no playlist)
prevBtn.addEventListener('click', () => {
audio.currentTime = 0;
});
nextBtn.addEventListener('click', () => {
audio.currentTime = audio.duration || 0;
audio.pause();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment