mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 22:07:52 +00:00
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import { useSpeechRecognition } from '../hooks/useSpeechRecognition';
|
|
import { Mic, Waves } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
import { useEffect } from 'react';
|
|
|
|
interface VoiceCommandButtonProps {
|
|
className?: string;
|
|
onTranscriptUpdate: (transcript: string) => void;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export function VoiceCommandButton({
|
|
className,
|
|
onTranscriptUpdate,
|
|
disabled = false
|
|
}: VoiceCommandButtonProps) {
|
|
const {
|
|
transcript,
|
|
start,
|
|
stop,
|
|
status,
|
|
error,
|
|
isSupported
|
|
} = useSpeechRecognition();
|
|
|
|
useEffect(() => {
|
|
if (transcript) {
|
|
onTranscriptUpdate(transcript);
|
|
}
|
|
}, [transcript, onTranscriptUpdate]);
|
|
|
|
useEffect(() => {
|
|
if (status === 'recording') {
|
|
onTranscriptUpdate(''); // Limpar contexto ao iniciar nova gravação
|
|
}
|
|
}, [status, onTranscriptUpdate]);
|
|
|
|
if (!isSupported) {
|
|
return (
|
|
<div className="p-3 bg-yellow-50 text-yellow-700 rounded-lg text-sm">
|
|
Seu navegador não suporta gravação por voz
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="relative group">
|
|
<button
|
|
onClick={status === 'recording' ? stop : start}
|
|
className={cn(
|
|
'flex items-center gap-3 px-4 py-2 rounded-lg transition-all',
|
|
status === 'recording'
|
|
? 'bg-red-100 text-red-600 hover:bg-red-200 shadow-sm'
|
|
: 'bg-gray-100 text-gray-600 hover:bg-gray-200',
|
|
disabled && 'opacity-50 cursor-not-allowed',
|
|
className
|
|
)}
|
|
aria-label={status === 'recording' ? "Parar gravação" : "Iniciar gravação"}
|
|
disabled={disabled}
|
|
>
|
|
<div className="relative">
|
|
<Mic className="h-5 w-5" />
|
|
{status === 'recording' && (
|
|
<Waves className="absolute -top-2 -right-2 h-4 w-4 animate-pulse text-red-500" />
|
|
)}
|
|
</div>
|
|
<span className="text-sm font-medium">
|
|
{status === 'recording' ? 'Gravando...' : 'Gravar por Voz'}
|
|
</span>
|
|
</button>
|
|
|
|
{error && (
|
|
<div className="absolute top-full mt-2 p-2 bg-red-50 text-red-600 text-sm rounded-lg shadow-lg border border-red-100">
|
|
{error}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|