Sameer Banchhor
added everything
7faea5c
'use client';
import { useActionState, useEffect, useRef, useState, type FC } from 'react';
import { useFormStatus } from 'react-dom';
import { convertTextToSpeech, type TtsState } from '@/app/actions';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Textarea } from '@/components/ui/textarea';
import { useToast } from '@/hooks/use-toast';
import { Volume2, LoaderCircle, Copy, Mic } from 'lucide-react';
const WindowControls = () => (
<div className="flex space-x-1.5">
<div className="w-3 h-3 rounded-full bg-muted-foreground/50"></div>
<div className="w-3 h-3 rounded-full bg-muted-foreground/50"></div>
<div className="w-3 h-3 rounded-full bg-muted-foreground/50"></div>
</div>
);
interface TtsFormProps {
examplePhrases: string[];
}
function SubmitButton() {
const { pending } = useFormStatus();
return (
<Button type="submit" disabled={pending} className="w-full" size="lg">
{pending ? (
<>
<LoaderCircle className="animate-spin" />
Generating...
</>
) : (
<>
<Volume2 />
Generate Speech
</>
)}
</Button>
);
}
export const TtsForm: FC<TtsFormProps> = ({ examplePhrases }) => {
const initialState: TtsState = { success: false };
const [state, formAction] = useActionState(convertTextToSpeech, initialState);
const { toast } = useToast();
const formRef = useRef<HTMLFormElement>(null);
const [text, setText] = useState('');
useEffect(() => {
if (state.error) {
toast({
variant: 'destructive',
title: 'Oops! Something went wrong.',
description: state.error,
});
}
}, [state, toast]);
const handleExampleClick = (phrase: string) => {
setText(phrase);
};
const handleCopyUrl = (url: string) => {
navigator.clipboard.writeText(url).then(() => {
toast({
title: 'Copied to clipboard!',
description: 'Audio URL is ready to be shared.',
});
});
};
return (
<div className="space-y-4 md:space-y-6">
<Card>
<CardHeader>
<CardTitle>Text Input</CardTitle>
<WindowControls />
</CardHeader>
<CardContent>
<form ref={formRef} action={formAction} className="space-y-4 pt-4">
<Textarea
name="text"
placeholder="इहाँ अपन छत्तीसगढ़ी सब्द लिखव..."
className="min-h-[100px] sm:min-h-[140px] resize-none"
value={text}
onChange={(e) => setText(e.target.value)}
required
/>
<SubmitButton />
</form>
</CardContent>
</Card>
{state.success && state.audioUrl && (
<Card>
<CardHeader>
<CardTitle>Audio Output</CardTitle>
<WindowControls />
</CardHeader>
<CardContent className="space-y-4 pt-4">
<audio key={state.key} controls src={state.audioUrl} className="w-full">
Your browser does not support the audio element.
</audio>
<Button
variant="outline"
className="w-full"
onClick={() => handleCopyUrl(state.audioUrl!)}
>
<Copy />
Copy Audio URL
</Button>
</CardContent>
</Card>
)}
{examplePhrases.length > 0 && (
<Card>
<CardHeader>
<CardTitle>Examples</CardTitle>
<WindowControls />
</CardHeader>
<CardContent className="pt-4">
<div className="flex flex-wrap gap-2">
{examplePhrases.map((phrase, index) => (
<Button
key={index}
variant="secondary"
size="sm"
className="h-auto items-start text-left font-body font-normal whitespace-normal text-xs sm:text-sm"
onClick={() => handleExampleClick(phrase)}>
<Mic className="mr-1 mt-0.5 h-4 w-4 shrink-0" />
<span>{phrase}</span>
</Button>
))}
</div>
</CardContent>
</Card>
)}
</div>
);
};