neuroread/components/KokoroReader.tsx

90 lines
2.6 KiB
TypeScript

"use client";
import { useRef, useState, useEffect } from "react";
import { Button } from "./ui/button";
import { Loader, Pause, Play } from "lucide-react";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "./ui/accordion";
import { Label } from "./ui/label";
import { useTTS } from "./TTSProvider";
export default function KokoroReader({ pages }: { pages: any[] }) {
const {
voices,
selectedSpeaker,
setSelectedSpeaker,
skipToSentence,
currentSentence,
setCurrentSentence,
playSentence,
playInOrder,
status,
} = useTTS();
const [playing, setPlaying] = useState(false);
useEffect(() => {
setCurrentSentence(0); // this might just jumpstart the audio
}, [status === "ready"]);
const play = () => {
if (playing) {
setPlaying(false);
return;
}
setPlaying(true);
playInOrder(currentSentence || 0);
};
return (
<div className="flex flex-col items-center justify-center pt-4 relative overflow-hidden font-sans">
<div className="max-w-3xl w-full relative z-[2]">
<div className="items-center justify-center text-center">
<Button
variant="ghost"
size="icon"
className="h-10 w-10"
onClick={play}
disabled={status === null}
>
{status === "running" ? (
<Loader className="animate-spin" />
) : (
<span className="sr-only">Play</span>
)}
{playing ? <Pause /> : <Play />}
</Button>
</div>
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger className="text-white pb-2">
Settings
</AccordionTrigger>
<AccordionContent className="pb-2">
<Label>Voice</Label>
<select
value={selectedSpeaker}
onChange={(e) => setSelectedSpeaker(e.target.value)}
className="w-full bg-gray-700/50 backdrop-blur-sm border-2 border-gray-600 rounded-md text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
{Object.entries(voices).map(([id, voice]) => (
<option key={id} value={id}>
{voice.name} (
{voice.language === "en-us" ? "American" : "British"}{" "}
{voice.gender})
</option>
))}
</select>
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</div>
);
}