dramaling-vocab-learning/frontend/components/media/AudioPlayer.tsx

91 lines
2.2 KiB
TypeScript

import React, { useState, useRef } from 'react'
import { Play, Pause, Volume2 } from 'lucide-react'
interface AudioPlayerProps {
text: string
className?: string
autoPlay?: boolean
voice?: 'us' | 'uk'
speed?: number
}
export default function AudioPlayer({
text,
className = '',
autoPlay = false,
voice = 'us',
speed = 1.0
}: AudioPlayerProps) {
const [isPlaying, setIsPlaying] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const audioRef = useRef<HTMLAudioElement>(null)
const handlePlay = async () => {
if (!text.trim()) return
try {
setIsLoading(true)
// 簡單的TTS模擬 - 實際應該調用TTS API
const utterance = new SpeechSynthesisUtterance(text)
utterance.lang = voice === 'us' ? 'en-US' : 'en-GB'
utterance.rate = speed
utterance.onstart = () => {
setIsPlaying(true)
setIsLoading(false)
}
utterance.onend = () => {
setIsPlaying(false)
}
utterance.onerror = () => {
setIsPlaying(false)
setIsLoading(false)
}
window.speechSynthesis.speak(utterance)
} catch (error) {
console.error('TTS Error:', error)
setIsLoading(false)
setIsPlaying(false)
}
}
const handleStop = () => {
window.speechSynthesis.cancel()
setIsPlaying(false)
}
return (
<button
onClick={isPlaying ? handleStop : handlePlay}
disabled={isLoading}
className={`
inline-flex items-center gap-2 px-3 py-1.5
bg-blue-50 hover:bg-blue-100
border border-blue-200 rounded-lg
text-blue-700 text-sm font-medium
transition-colors duration-200
disabled:opacity-50 disabled:cursor-not-allowed
${className}
`}
>
{isLoading ? (
<div className="w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
) : isPlaying ? (
<Pause size={16} />
) : (
<Play size={16} />
)}
<Volume2 size={14} />
<span>
{isLoading ? '載入中...' : isPlaying ? '播放中' : '播放'}
</span>
</button>
)
}