cetirizine

An experimental matrix client written in reactjs utilizing tailwind and storybook
git clone git://archive.git.mtrnord.blog/MTRNord/cetirizine.git
Log | Files | Refs | README | LICENSE

Waveform.tsx (3622B)


      1 import { FC, memo, useEffect, useRef, useState } from "react";
      2 import { Pause, Play } from 'lucide-react';
      3 import WaveSurfer from 'wavesurfer.js';
      4 
      5 type WaveformProps = {
      6     /**
      7      * The media url to render
      8      */
      9     src_url: string;
     10 };
     11 
     12 const Waveform: FC<WaveformProps> = memo(({ src_url }) => {
     13     const [playing, setPlaying] = useState(false);
     14     const [duration, setDuration] = useState(0);
     15     const [waveform, setWaveform] = useState<WaveSurfer | undefined>(undefined);
     16     const waveformRef = useRef<HTMLDivElement>(null);
     17 
     18     useEffect(() => {
     19         if (waveformRef.current) {
     20             if (waveformRef.current.children.length > 0) {
     21                 if (waveform) {
     22                     setWaveform(prev => {
     23                         prev?.destroy();
     24                         if (waveformRef.current) {
     25                             for (const child of waveformRef.current.children) {
     26                                 child.remove();
     27                             }
     28                         }
     29                         return undefined;
     30                     });
     31                 }
     32             }
     33             if (waveformRef.current.children.length === 0) {
     34                 setWaveform(WaveSurfer.create({
     35                     barWidth: 5,
     36                     cursorWidth: 1,
     37                     container: waveformRef.current,
     38                     backend: 'WebAudio',
     39                     height: 45,
     40                     progressColor: '#f59e0b',
     41                     responsive: true,
     42                     waveColor: '#cbd5e1',
     43                     cursorColor: 'transparent',
     44                     barRadius: 5,
     45                     hideScrollbar: true,
     46                     normalize: true,
     47                 }));
     48             }
     49         }
     50     }, []);
     51 
     52 
     53     useEffect(() => {
     54         if (waveform) {
     55             waveform.load(src_url);
     56             waveform.on('ready', () => {
     57                 setDuration(waveform.getDuration());
     58             });
     59         }
     60     }, [waveform])
     61 
     62     const handlePlay = () => {
     63         if (waveform) {
     64             setPlaying((prev) => !prev);
     65             waveform.playPause();
     66         }
     67     };
     68 
     69     return (
     70         <div className="flex w-[min-content] flex-row h-full items-start justify-start gap-3 bg-slate-200 rounded border-2 border-slate-500 p-1">
     71             <button aria-label={!playing ? "Play" : "Pause"} className="text-center flex justify-center items-center w-12 h-12 min-w-12 min-h-12 rounded-full outline-none cursor-pointer pb-1 bg-orange-500 border-orange-600 border hover:bg-orange-600 group" onClick={handlePlay}>
     72                 {!playing ? <Play viewBox="0 0 21 24" className="stroke-slate-50 group-hover:stroke-slate-100" /> : <Pause size={24} className="stroke-slate-700 group-hover:stroke-slate-600" />}
     73             </button>
     74             <div className="flex flex-col w-96 gap-2 justify-between">
     75                 <div className="w-full h-12" id="waveform" ref={waveformRef}></div>
     76                 <span className="w-full text-sm font-medium text-slate-600 text-right">{secondsToHms(duration)}</span>
     77             </div>
     78         </div>
     79     );
     80 })
     81 
     82 function secondsToHms(d?: number) {
     83     if (!d) {
     84         return "00:00";
     85     }
     86     const h = Math.floor(d / 3600);
     87     const m = Math.floor(d % 3600 / 60);
     88     const s = Math.floor(d % 3600 % 60);
     89 
     90     if (h === 0 && m === 0 && s === 0) {
     91         return "00:00";
     92     } else if (h === 0 && m === 0) {
     93         return `00:${s.toString().padStart(2, "0")}`;
     94     } else if (h === 0) {
     95         return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
     96     }
     97     return `${h}:${m}:${s}`;
     98 }
     99 
    100 export default Waveform;