Audio Log
This component allows you to make a Styled Quote div that contains audio.
There are a few options to customize the block so it can work for you.
Component
Audio Log…
Text goes in here! Wow…
HTML Code
<div id="audio-player-container"> <audio src="https://assets.codepen.io/4358584/Anitek_-_Komorebi.mp3" preload="metadata" loop></audio> <button id="play-icon" class="icon-btn">▶</button> <span id="current-time" class="time">0:00</span> <input type="range" id="seek-slider" max="100" value="0"> <span id="duration" class="time">0:00</span> <output id="volume-output">100</output> <input type="range" id="volume-slider" max="100" value="100"> <button id="mute-icon" class="icon-btn">🔊</button> </div> <style> #audio-player-container { --seek-before-width: 0%; --volume-before-width: 100%; --buffered-width: 0%; width: 100vw; height: 48px; background: #fff; display: flex; align-items: center; gap: 8px; padding: 0 10px; box-sizing: border-box; } .icon-btn { width: 28px; height: 28px; font-size: 20px; line-height: 28px; text-align: center; border: none; background: transparent; cursor: pointer; } .time { font-size: 14px; width: 40px; text-align: center; } #audio-player-container input[type="range"] { -webkit-appearance: none; height: 4px; background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width)); position: relative; flex-grow: 1; } #audio-player-container input[type="range"]::before { content: ""; position: absolute; left: 0; top: 0; height: 4px; width: var(--seek-before-width); background: #007db5; } #audio-player-container input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; background: #fff; border: 1px solid #007db5; border-radius: 50%; margin-top: -4px; } #volume-slider { max-width: 120px; } output { width: 32px; font-size: 14px; text-align: center; } </style> <script type="module"> /* Implementation of the presentation of the audio player */ import lottieWeb from 'https://cdn.skypack.dev/lottie-web'; const playIconContainer = document.getElementById('play-icon'); const audioPlayerContainer = document.getElementById('audio-player-container'); const seekSlider = document.getElementById('seek-slider'); const volumeSlider = document.getElementById('volume-slider'); const muteIconContainer = document.getElementById('mute-icon'); let playState = 'play'; let muteState = 'unmute'; const playAnimation = lottieWeb.loadAnimation({ container: playIconContainer, path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/pause/pause.json', renderer: 'svg', loop: false, autoplay: false, name: "Play Animation", }); const muteAnimation = lottieWeb.loadAnimation({ container: muteIconContainer, path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/mute/mute.json', renderer: 'svg', loop: false, autoplay: false, name: "Mute Animation", }); playAnimation.goToAndStop(14, true); playIconContainer.addEventListener('click', () => { if(playState === 'play') { audio.play(); playAnimation.playSegments([14, 27], true); requestAnimationFrame(whilePlaying); playState = 'pause'; } else { audio.pause(); playAnimation.playSegments([0, 14], true); cancelAnimationFrame(raf); playState = 'play'; } }); muteIconContainer.addEventListener('click', () => { if(muteState === 'unmute') { muteAnimation.playSegments([0, 15], true); audio.muted = true; muteState = 'mute'; } else { muteAnimation.playSegments([15, 25], true); audio.muted = false; muteState = 'unmute'; } }); const showRangeProgress = (rangeInput) => { if(rangeInput === seekSlider) audioPlayerContainer.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%'); else audioPlayerContainer.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%'); } seekSlider.addEventListener('input', (e) => { showRangeProgress(e.target); }); volumeSlider.addEventListener('input', (e) => { showRangeProgress(e.target); }); /* Implementation of the functionality of the audio player */ const audio = document.querySelector('audio'); const durationContainer = document.getElementById('duration'); const currentTimeContainer = document.getElementById('current-time'); const outputContainer = document.getElementById('volume-output'); let raf = null; const calculateTime = (secs) => { const minutes = Math.floor(secs / 60); const seconds = Math.floor(secs % 60); const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`; return `${minutes}:${returnedSeconds}`; } const displayDuration = () => { durationContainer.textContent = calculateTime(audio.duration); } const setSliderMax = () => { seekSlider.max = Math.floor(audio.duration); } const displayBufferedAmount = () => { const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1)); audioPlayerContainer.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`); } const whilePlaying = () => { seekSlider.value = Math.floor(audio.currentTime); currentTimeContainer.textContent = calculateTime(seekSlider.value); audioPlayerContainer.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`); raf = requestAnimationFrame(whilePlaying); } if (audio.readyState > 0) { displayDuration(); setSliderMax(); displayBufferedAmount(); } else { audio.addEventListener('loadedmetadata', () => { displayDuration(); setSliderMax(); displayBufferedAmount(); }); } audio.addEventListener('progress', displayBufferedAmount); seekSlider.addEventListener('input', () => { currentTimeContainer.textContent = calculateTime(seekSlider.value); if(!audio.paused) { cancelAnimationFrame(raf); } }); seekSlider.addEventListener('change', () => { audio.currentTime = seekSlider.value; if(!audio.paused) { requestAnimationFrame(whilePlaying); } }); volumeSlider.addEventListener('input', (e) => { const value = e.target.value; outputContainer.textContent = value; audio.volume = value / 100; }); /* Implementation of the Media Session API */ if('mediaSession' in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ title: 'Komorebi', artist: 'Anitek', album: 'MainStay', artwork: [ { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '96x96', type: 'image/png' }, { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '128x128', type: 'image/png' }, { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '192x192', type: 'image/png' }, { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '256x256', type: 'image/png' }, { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '384x384', type: 'image/png' }, { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '512x512', type: 'image/png' } ] }); navigator.mediaSession.setActionHandler('play', () => { if(playState === 'play') { audio.play(); playAnimation.playSegments([14, 27], true); requestAnimationFrame(whilePlaying); playState = 'pause'; } else { audio.pause(); playAnimation.playSegments([0, 14], true); cancelAnimationFrame(raf); playState = 'play'; } }); navigator.mediaSession.setActionHandler('pause', () => { if(playState === 'play') { audio.play(); playAnimation.playSegments([14, 27], true); requestAnimationFrame(whilePlaying); playState = 'pause'; } else { audio.pause(); playAnimation.playSegments([0, 14], true); cancelAnimationFrame(raf); playState = 'play'; } }); navigator.mediaSession.setActionHandler('seekbackward', (details) => { audio.currentTime = audio.currentTime - (details.seekOffset || 10); }); navigator.mediaSession.setActionHandler('seekforward', (details) => { audio.currentTime = audio.currentTime + (details.seekOffset || 10); }); navigator.mediaSession.setActionHandler('seekto', (details) => { if (details.fastSeek && 'fastSeek' in audio) { audio.fastSeek(details.seekTime); return; } audio.currentTime = details.seekTime; }); navigator.mediaSession.setActionHandler('stop', () => { audio.currentTime = 0; seekSlider.value = 0; audioPlayerContainer.style.setProperty('--seek-before-width', '0%'); currentTimeContainer.textContent = '0:00'; if(playState === 'pause') { playAnimation.playSegments([0, 14], true); cancelAnimationFrame(raf); playState = 'play'; } }); } </script>
.styled-quote.audio-log { padding: 0; } .audio-log-head { display: grid; grid-template-columns: auto 1fr; } .audio-log-head--text { height: 48px; font-family: var(--header-font); font-size: 20px; display: flex; align-items: center; padding: 0 68px 0 20px; border-radius: 0 0 3px 0; background: red; } .audio-log-head--iframe { width: calc(100% + 58px); } .audio-log-head--iframe iframe { width: 100%; border: none; outline: none !important; height: 48px; margin-left: -58px; } .audio-log-text { padding: 0 1rem; }
page revision: 6, last edited: 25 Nov 2025 00:58
