Created
October 10, 2023 16:54
-
-
Save Janith-Umeda/c6046ac1e18ed025c857a1eb44b4c7cb to your computer and use it in GitHub Desktop.
A Simple Audio Player with Modern UI using Tailwind, Material and React js.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FastForward, FastRewind, Pause, PlayArrow, Repeat, VolumeDown, VolumeOff, VolumeUp } from "@mui/icons-material"; | |
import { useEffect, useRef, useState } from "react"; | |
const AudioPlayer = ({src})=> { | |
const Player = useRef(); | |
const [VolumeShow,setVolumeShow] = useState(false); | |
const [isMute,setMute] = useState(false); | |
const [volumeLevel,setVolumeLvl] = useState(50); | |
const [isPlay,setPlay] = useState(false); | |
const [isLoop,setLoop] = useState(false); | |
const [duration,setDuration] = useState('0:00'); | |
const [current,setCurrent] = useState('0:00'); | |
const [currentProg,setCurrProg] = useState(0); | |
useEffect(()=>{ | |
if(isPlay){ | |
Player.current.play(); | |
}else{ | |
Player.current.pause(); | |
} | |
},[isPlay]); | |
const timeFormat = (currentTime)=>{ | |
const minutes = Math.floor(currentTime / 60); | |
let seconds = Math.floor(currentTime % 60); | |
seconds = (seconds >= 10) ? seconds : "0" + seconds % 60; | |
const formatTime = minutes + ":" + seconds; | |
return formatTime; | |
}; | |
useEffect(()=>{ | |
if(isPlay){ | |
setDuration(timeFormat(Player.current.duration)); | |
Player.current.addEventListener("timeupdate",(e)=>{ | |
setCurrent(timeFormat(Player.current?.currentTime)); | |
setCurrProg(((Player.current?.currentTime/Player.current?.duration)*100).toFixed()); | |
}); | |
} | |
},[isPlay]); | |
useEffect(()=>{ | |
const player = Player.current; | |
player?.addEventListener('play',()=>setPlay(true)); | |
player?.addEventListener('pause',()=>setPlay(false)); | |
return ()=>{ | |
player.removeEventListener('play',()=>setPlay(true)); | |
player.removeEventListener('pause',()=>setPlay(false)); | |
} | |
}); | |
useEffect(()=>{ | |
Player.current.volume = Number(volumeLevel)/100; | |
},[volumeLevel]); | |
const RewindSeek = ()=>{ | |
Player.current.currentTime = Player.current.currentTime - 10; | |
} | |
const ForwardSeek = ()=>{ | |
Player.current.currentTime = Player.current.currentTime + 10; | |
} | |
return ( | |
<div className="bg-slate-100 w-full rounded mb-3"> | |
<div className="flex items-center justify-between w-full p-2 gap-3 h-16"> | |
<div className="w-7">{current}</div> | |
<div className="bg-slate-400 w-full h-2 rounded relative overflow-clip"> | |
<div className="absolute h-2 top-0 z-1 bg-red-400" style={{width:`${currentProg}%`}}></div> | |
</div> | |
<div className="w-7">{duration}</div> | |
</div> | |
<div className="bg-slate-300 h-16 flex items-center justify-around"> | |
<div | |
className={`p-2 rounded-full ${isLoop?'bg-gray-400':''} hover:bg-gray-200 cursor-pointer`} | |
onClick={()=>setLoop((prev)=>!prev)} | |
> | |
<Repeat /> | |
</div> | |
<div className="flex items-center gap-2"> | |
<div | |
className="p-2 rounded-full hover:bg-gray-200 cursor-pointer active:bg-gray-100" | |
onClick={RewindSeek} | |
> | |
<FastRewind style={{fontSize:'28px'}}/> | |
</div> | |
<div | |
className="rounded-full bg-white w-14 h-14 flex items-center justify-center shadow-md hover:bg-green-300 cursor-pointer" | |
onClick={()=>setPlay((prev)=>!prev)} | |
> | |
{isPlay ? <Pause style={{fontSize:'40px'}}/> : <PlayArrow style={{fontSize:'40px'}}/>} | |
</div> | |
<div | |
className="p-2 rounded-full hover:bg-gray-200 cursor-pointer active:bg-gray-100" | |
onClick={ForwardSeek} | |
> | |
<FastForward style={{fontSize:'28px'}}/> | |
</div> | |
</div> | |
<div | |
className="p-2 rounded-full hover:bg-gray-200 cursor-pointer relative" | |
onMouseEnter={()=>setVolumeShow(true)} | |
// onMouseLeave={()=>setVolumeShow(false)} | |
> | |
<span> | |
{isMute || volumeLevel <= 0 ? <VolumeOff /> :( volumeLevel > 50 ? <VolumeUp /> : <VolumeDown />)} | |
</span> | |
<div | |
className={`${VolumeShow ? 'flex' : 'hidden'} flex-col items-center justify-center absolute w-[40px] h-[145px] bg-slate-400 top-[-150px] left-0 z-40 rounded-md shadow-md`} | |
// onMouseEnter={()=>setVolumeShow(true)} | |
onMouseLeave={()=>setVolumeShow(false)} | |
> | |
<input | |
type="range" | |
className="rotate-[270deg]" | |
min={0} max={100} | |
value={isMute ? 0 : volumeLevel} | |
onChange={(e)=>setVolumeLvl(e.target.value)} | |
onWheel={(e)=>{setVolumeLvl((prev)=>(e.deltaY < 0 ?(prev<100?prev+5:100):(prev>0?prev-5:0)))}} | |
/> | |
{/* <span className="absolute bottom-0"><VolumeOff style={{fontSize:'20px'}} /></span> */} | |
</div> | |
</div> | |
</div> | |
<audio className="hidden" src={src} ref={Player} muted={isMute} loop={isLoop} controls={true}></audio> | |
</div> | |
); | |
} | |
export default AudioPlayer; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment