tahamajs/IE / Projects /front /src /components /voice /VoiceMessageButton.tsx
tahamajs's picture
download
raw
2.46 kB
// src/components/voice/VoiceMessageButton.tsx
import { useState, useCallback } from "react";
import { useSpeechRecognition } from "@/hooks/useSpeechRecognition";
import { Mic, X } from "lucide-react";
import { toast } from "react-toastify";
interface VoiceMessageButtonProps {
onTranscript: (text: string) => void;
placeholder?: string;
className?: string;
}
export function VoiceMessageButton({
onTranscript,
placeholder = "Speak your message...",
className = "",
}: VoiceMessageButtonProps) {
const [dictating, setDictating] = useState(false);
const stt = useSpeechRecognition({
language: "en-US",
continuous: false,
onResult: (transcript: string, isFinal: boolean) => {
if (isFinal) {
onTranscript(transcript);
setDictating(false);
stt.stopListening();
toast.success("Voice message transcribed!");
}
},
onError: (err: any) => {
console.error("Speech recognition error", err);
toast.error("Could not hear you. Please try again.");
setDictating(false);
},
});
const startDictation = useCallback(() => {
setDictating(true);
stt.resetTranscript();
stt.startListening();
}, [stt]);
const cancelDictation = useCallback(() => {
stt.abortListening?.() ?? stt.stopListening?.();
setDictating(false);
}, [stt]);
if (!stt.browserSupportsSpeechRecognition) {
return null;
}
if (dictating) {
return (
<div className={`flex items-center gap-2 bg-red-50 dark:bg-red-900/20 rounded-full px-4 py-2 ${className}`}>
<div className="flex gap-0.5 items-end h-4">
{[1, 2, 3, 4].map((i) => (
<div
key={i}
className="w-0.5 bg-red-500 rounded-full animate-pulse"
style={{ height: `${Math.max(3, Math.random() * 16)}px` }}
/>
))}
</div>
<span className="text-sm text-red-600 dark:text-red-400 flex-1">
{stt.interimTranscript || "Listening..."}
</span>
<button onClick={cancelDictation} className="p-1 text-red-400 hover:text-red-600">
<X className="w-4 h-4" />
</button>
</div>
);
}
return (
<button
onClick={startDictation}
className={`p-2 text-gray-400 hover:text-primary transition rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 ${className}`}
title="Voice input"
>
<Mic className="w-5 h-5" />
</button>
);
}

Xet Storage Details

Size:
2.46 kB
·
Xet hash:
7ccb6fbf30af9164908b1dafa2010ae66e3e324a26eb04ab321cf69c186524f8

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.