mirror of
https://github.com/dergigi/boris.git
synced 2026-01-24 17:24:41 +01:00
feat(tts): add TTSControls component with play/pause/stop and rate
This commit is contained in:
77
src/components/TTSControls.tsx
Normal file
77
src/components/TTSControls.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import React from 'react'
|
||||
import { useTextToSpeech } from '../hooks/useTextToSpeech'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faPlay, faPause, faStop } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
interface Props {
|
||||
text: string
|
||||
defaultLang?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
const TTSControls: React.FC<Props> = ({ text, defaultLang, className }) => {
|
||||
const {
|
||||
supported, speaking, paused,
|
||||
speak, pause, resume, stop,
|
||||
rate, setRate
|
||||
} = useTextToSpeech({ defaultLang })
|
||||
|
||||
const canPlay = supported && text?.trim().length > 0
|
||||
|
||||
const handlePlayPause = () => {
|
||||
if (!canPlay) return
|
||||
if (!speaking) {
|
||||
speak(text, defaultLang)
|
||||
} else if (paused) {
|
||||
resume()
|
||||
} else {
|
||||
pause()
|
||||
}
|
||||
}
|
||||
|
||||
const playLabel = !speaking ? 'Listen' : (paused ? 'Resume' : 'Pause')
|
||||
|
||||
if (!supported) return null
|
||||
|
||||
return (
|
||||
<div className={className || 'tts-controls'} style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<button
|
||||
type="button"
|
||||
className="article-menu-btn"
|
||||
onClick={handlePlayPause}
|
||||
title={playLabel}
|
||||
disabled={!canPlay}
|
||||
>
|
||||
<FontAwesomeIcon icon={!speaking ? faPlay : (paused ? faPlay : faPause)} />
|
||||
<span style={{ marginLeft: 6 }}>{playLabel}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="article-menu-btn"
|
||||
onClick={stop}
|
||||
title="Stop"
|
||||
disabled={!speaking && !paused}
|
||||
>
|
||||
<FontAwesomeIcon icon={faStop} />
|
||||
<span style={{ marginLeft: 6 }}>Stop</span>
|
||||
</button>
|
||||
<label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: '#aaa', fontSize: 12 }}>
|
||||
Speed
|
||||
<select
|
||||
value={rate}
|
||||
onChange={e => setRate(Number(e.target.value))}
|
||||
style={{ background: 'transparent', color: 'inherit', border: '1px solid #444', borderRadius: 4, padding: '2px 6px' }}
|
||||
>
|
||||
<option value={0.8}>0.8x</option>
|
||||
<option value={1}>1x</option>
|
||||
<option value={1.2}>1.2x</option>
|
||||
<option value={1.4}>1.4x</option>
|
||||
<option value={1.6}>1.6x</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TTSControls
|
||||
|
||||
Reference in New Issue
Block a user