Files
ViGent2/frontend/src/features/home/ui/VoiceSelector.tsx
Kevin Wong 1717635bfd 更新
2026-02-25 17:51:58 +08:00

85 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { ReactNode } from "react";
import { Mic, Volume2 } from "lucide-react";
interface VoiceOption {
id: string;
name: string;
}
interface VoiceSelectorProps {
ttsMode: "edgetts" | "voiceclone";
onSelectTtsMode: (mode: "edgetts" | "voiceclone") => void;
voices: VoiceOption[];
voice: string;
onSelectVoice: (id: string) => void;
voiceCloneSlot: ReactNode;
embedded?: boolean;
}
export function VoiceSelector({
ttsMode,
onSelectTtsMode,
voices,
voice,
onSelectVoice,
voiceCloneSlot,
embedded = false,
}: VoiceSelectorProps) {
const content = (
<>
<div className="flex gap-2 mb-4">
<button
onClick={() => onSelectTtsMode("edgetts")}
className={`flex-1 py-2 px-2 sm:px-4 rounded-lg text-sm sm:text-base font-medium transition-all flex items-center justify-center gap-1.5 sm:gap-2 ${ttsMode === "edgetts"
? "bg-purple-600 text-white"
: "bg-white/10 text-gray-300 hover:bg-white/20"
}`}
>
<Volume2 className="h-4 w-4 shrink-0" />
</button>
<button
onClick={() => onSelectTtsMode("voiceclone")}
className={`flex-1 py-2 px-2 sm:px-4 rounded-lg text-sm sm:text-base font-medium transition-all flex items-center justify-center gap-1.5 sm:gap-2 ${ttsMode === "voiceclone"
? "bg-purple-600 text-white"
: "bg-white/10 text-gray-300 hover:bg-white/20"
}`}
>
<Mic className="h-4 w-4 shrink-0" />
</button>
</div>
{ttsMode === "edgetts" && (
<div className="grid grid-cols-2 gap-3">
{voices.map((v) => (
<button
key={v.id}
onClick={() => onSelectVoice(v.id)}
className={`p-3 rounded-xl border-2 transition-all text-left ${voice === v.id
? "border-purple-500 bg-purple-500/20"
: "border-white/10 bg-white/5 hover:border-white/30"
}`}
>
<span className="text-white text-sm">{v.name}</span>
</button>
))}
</div>
)}
{ttsMode === "voiceclone" && voiceCloneSlot}
</>
);
if (embedded) return content;
return (
<div className="bg-white/5 rounded-2xl p-6 border border-white/10 backdrop-blur-sm">
<h2 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
🎙
</h2>
{content}
</div>
);
}