forked from samuellawerentz/style-guide
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #58 from contacto-io/feature/CNTO-6850-audio-playe…
…r-improvements [CNTO-6850] - New Audio Player
- Loading branch information
Showing
11 changed files
with
366 additions
and
3 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
"cascader", | ||
"contacto", | ||
"datepicker", | ||
"listbox" | ||
"listbox", | ||
"wavesurfer" | ||
] | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* eslint-disable max-len */ | ||
import React from 'react' | ||
|
||
export default function PlayPauseIcon({ isPlaying = false, size = 32 }) { | ||
if (!isPlaying) { | ||
return ( | ||
<svg | ||
width={size} | ||
height={size} | ||
viewBox={`0 0 32 32`} | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
d="M16.0001 2.6665C8.64008 2.6665 2.66675 8.63984 2.66675 15.9998C2.66675 23.3598 8.64008 29.3332 16.0001 29.3332C23.3601 29.3332 29.3334 23.3598 29.3334 15.9998C29.3334 8.63984 23.3601 2.6665 16.0001 2.6665ZM12.6667 19.5598V12.4398C12.6667 11.3865 13.8401 10.7465 14.7201 11.3198L20.2534 14.8798C21.0667 15.3998 21.0667 16.5998 20.2534 17.1198L14.7201 20.6798C13.8401 21.2532 12.6667 20.6132 12.6667 19.5598Z" | ||
fill="#0040E4" | ||
/> | ||
</svg> | ||
) | ||
} | ||
|
||
return ( | ||
<svg | ||
width={size} | ||
height={size} | ||
viewBox={`0 0 32 32`} | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
d="M15.9998 2.6665C8.63984 2.6665 2.6665 8.63984 2.6665 15.9998C2.6665 23.3598 8.63984 29.3332 15.9998 29.3332C23.3598 29.3332 29.3332 23.3598 29.3332 15.9998C29.3332 8.63984 23.3598 2.6665 15.9998 2.6665ZM13.3332 21.3332C12.5998 21.3332 11.9998 20.7332 11.9998 19.9998V11.9998C11.9998 11.2665 12.5998 10.6665 13.3332 10.6665C14.0665 10.6665 14.6665 11.2665 14.6665 11.9998V19.9998C14.6665 20.7332 14.0665 21.3332 13.3332 21.3332ZM18.6665 21.3332C17.9332 21.3332 17.3332 20.7332 17.3332 19.9998V11.9998C17.3332 11.2665 17.9332 10.6665 18.6665 10.6665C19.3998 10.6665 19.9998 11.2665 19.9998 11.9998V19.9998C19.9998 20.7332 19.3998 21.3332 18.6665 21.3332Z" | ||
fill="#0040E4" | ||
/> | ||
</svg> | ||
) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React, { useEffect, useState } from 'react' | ||
import { Popover } from 'antd' | ||
import { Button } from '../../Button/index' | ||
|
||
const speeds = [0.8, 1, 1.2, 1.5, 1.7, 2, 2.5] | ||
export default function PlaybackSpeed({ waveSurfer }) { | ||
const [speed, setSpeed] = useState(waveSurfer?.getPlaybackRate()) | ||
|
||
const handleSpeedChange = (speed) => { | ||
setSpeed(speed) | ||
waveSurfer?.setPlaybackRate(speed) | ||
} | ||
|
||
useEffect(() => { | ||
setSpeed(waveSurfer?.getPlaybackRate()) | ||
}, [waveSurfer]) | ||
|
||
return ( | ||
<Popover | ||
overlayClassName="contacto-player-speed" | ||
title="Playback Speed" | ||
content={() => ( | ||
<div> | ||
{speeds.map((speed) => ( | ||
<Button | ||
key={speed} | ||
className="contacto-player-speed" | ||
type={speed === waveSurfer?.getPlaybackRate() ? 'secondary' : 'table-action-link'} | ||
onClick={() => handleSpeedChange(speed)} | ||
> | ||
{speed}x | ||
</Button> | ||
))} | ||
</div> | ||
)} | ||
> | ||
<Button className="contacto-player-speed-trigger" type="secondary"> | ||
{speed}x | ||
</Button> | ||
</Popover> | ||
) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { useLayoutEffect, useRef, useState } from 'react' | ||
|
||
import WaveSurfer from 'wavesurfer.js' | ||
import { generateId } from './utils' | ||
|
||
const defaultPlayerConfig = (playerId) => ({ | ||
id: playerId, | ||
isPlaying: false, | ||
loading: true, | ||
}) | ||
const defaultDurationConfig = () => ({ | ||
totalDuration: 0, | ||
currentDuration: 0, | ||
}) | ||
export default function useWaveSurfer(url) { | ||
const playerId = useRef(generateId('contacto-player-wave-')).current | ||
const [playerConfig, setPlayerConfig] = useState(defaultPlayerConfig(playerId)) | ||
const [durationConfig, setDurationConfig] = useState(defaultDurationConfig()) | ||
const [waveSurfer, setWaveSurfer] = useState(null) | ||
|
||
useLayoutEffect(() => { | ||
let wave = null | ||
if (url) { | ||
wave = WaveSurfer.create({ | ||
container: `#${playerId}`, | ||
url: url, | ||
waveColor: '#C3D2FF', | ||
progressColor: '#0040E4', | ||
cursorColor: '#0040E4', | ||
responsive: true, | ||
height: 24, | ||
barHeight: 3, | ||
barMinHeight: 1, | ||
barWidth: 1, | ||
barGap: 4, | ||
hideScrollbar: true, | ||
closeAudioContext: true, | ||
partialRender: true, | ||
}) | ||
wave.on('load', () => { | ||
setPlayerConfig((prevConfig) => ({ ...prevConfig, loading: true })) | ||
}) | ||
wave.on('ready', () => { | ||
setDurationConfig((prevConfig) => ({ | ||
...prevConfig, | ||
totalDuration: parseInt(wave.getDuration()), | ||
})) | ||
setPlayerConfig((prevConfig) => ({ ...prevConfig, loading: false })) | ||
}) | ||
wave.on('audioprocess', () => { | ||
const duration = parseInt(wave.getCurrentTime()) | ||
if (durationConfig.currentDuration !== duration) { | ||
setDurationConfig((prevConfig) => ({ | ||
...prevConfig, | ||
currentDuration: duration, | ||
})) | ||
} | ||
}) | ||
wave.on('play', () => { | ||
setPlayerConfig((prevConfig) => ({ ...prevConfig, isPlaying: true })) | ||
}) | ||
wave.on('pause', () => { | ||
setPlayerConfig((prevConfig) => ({ ...prevConfig, isPlaying: false })) | ||
}) | ||
wave.on('finish', () => { | ||
setPlayerConfig((prevConfig) => ({ ...prevConfig, isPlaying: false })) | ||
}) | ||
|
||
setWaveSurfer(wave) | ||
} | ||
|
||
return () => { | ||
wave?.stop() | ||
wave?.destroy() | ||
setWaveSurfer(null) | ||
setPlayerConfig(defaultPlayerConfig(playerId)) | ||
setDurationConfig(defaultDurationConfig()) | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [playerId, url]) | ||
|
||
return { waveSurfer, playerConfig, durationConfig } | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export const getDisplayTime = (seconds) => { | ||
const int = +seconds / 60 | ||
let minutes = parseInt(int) | ||
seconds = seconds % 60 | ||
minutes = (minutes < 10 ? '0' : '') + minutes | ||
seconds = (seconds < 10 ? '0' : '') + seconds | ||
return minutes + ':' + seconds | ||
} | ||
|
||
export const generateId = (prefix) => { | ||
return `${prefix}${Math.random().toString(36).slice(2)}` | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React from 'react' | ||
import Text from 'antd/lib/typography/Text' | ||
import { forwardRef } from 'react' | ||
import PlayPauseIcon from './components/PlayPauseIcon' | ||
import useWaveSurfer from './helpers/useWaveSurfer' | ||
import PlaybackSpeed from './components/PlaybackSpeed' | ||
import { Button } from '../Button/index' | ||
import { Icon } from '../Icon/index' | ||
import { getDisplayTime } from './helpers/utils' | ||
import './styles.scss' | ||
|
||
const AudioPlayer = forwardRef((props, ref) => { | ||
const { className, url } = props | ||
const { waveSurfer, playerConfig, durationConfig } = useWaveSurfer(url) | ||
|
||
const { isPlaying, loading } = playerConfig | ||
const { totalDuration, currentDuration } = durationConfig | ||
|
||
return ( | ||
<div | ||
className={`contacto-audio-player ${className ?? ''} ${loading ? 'loading' : ''}`} | ||
ref={ref} | ||
> | ||
<div className="audio-controls"> | ||
<Button | ||
className="audio-controls-play-pause" | ||
type="default" | ||
onClick={() => !loading && waveSurfer?.playPause()} | ||
icon={loading ? <Icon.Loading size={30} /> : <PlayPauseIcon isPlaying={isPlaying} />} | ||
/> | ||
<div className="audio-controls-time left"> | ||
<Text type="caption">{getDisplayTime(currentDuration)}</Text> | ||
</div> | ||
<div id={playerConfig.id} className="audio-controls-wave-bar" /> | ||
<div className="audio-controls-time right"> | ||
<Text type="caption">{getDisplayTime(totalDuration)}</Text> | ||
</div> | ||
<PlaybackSpeed waveSurfer={waveSurfer} /> | ||
</div> | ||
</div> | ||
) | ||
}) | ||
|
||
AudioPlayer.displayName = 'AudioPlayer' | ||
export { AudioPlayer } |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import React from 'react' | ||
import { AudioPlayer } from './' | ||
|
||
export default { | ||
title: 'Components/Audio Player', | ||
component: AudioPlayer, | ||
} | ||
|
||
const Template = (args) => <AudioPlayer {...args} /> | ||
|
||
export const Default = Template.bind({}) | ||
Default.args = { | ||
url: 'https://wavesurfer-js.org/wavesurfer-code/examples/audio/mono.mp3', | ||
} |
Oops, something went wrong.