mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-02-24 07:25:10 +00:00
CustomVoiceFilter: Refactored UIs
This commit is contained in:
parent
cff7492f37
commit
ba431e78b1
3 changed files with 216 additions and 211 deletions
|
@ -1,111 +1,113 @@
|
||||||
/*
|
/*
|
||||||
* Vencord, a Discord client mod
|
* Vencord, a Discord client mod
|
||||||
* Copyright (c) 2025 Vendicated and contributors
|
* Copyright (c) 2025 Vendicated and contributors
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { Button, Flex, Forms, Select, TextInput, useCallback, useMemo, UserStore, useState } from "@webpack/common";
|
import { Button, Flex, Forms, Select, TextInput, useCallback, useMemo, UserStore, useState } from "@webpack/common";
|
||||||
import { SelectOption } from "@webpack/types";
|
import { SelectOption } from "@webpack/types";
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
import { voices } from ".";
|
import { voices } from ".";
|
||||||
import { openErrorModal } from "./ErrorModal";
|
import { openErrorModal } from "./ErrorModal";
|
||||||
import { IVoiceFilter, useVoiceFiltersStore } from "./index";
|
import { openHelpModal } from "./HelpModal";
|
||||||
const requiredFields = ["name", "iconURL", "onnxFileUrl", "previewSoundURLs"] as const satisfies readonly (keyof IVoiceFilter)[];
|
import { IVoiceFilter, useVoiceFiltersStore } from "./index";
|
||||||
|
const requiredFields = ["name", "iconURL", "onnxFileUrl", "previewSoundURLs"] as const satisfies readonly (keyof IVoiceFilter)[];
|
||||||
|
|
||||||
export function openCreateVoiceModal(defaultValue?: Partial<IVoiceFilter>): string {
|
|
||||||
const key = openModal(modalProps => (
|
export function openCreateVoiceModal(defaultValue?: Partial<IVoiceFilter>): string {
|
||||||
<CreateVoiceFilterModal modalProps={modalProps} close={() => closeModal(key)} defaultValue={defaultValue} />
|
const key = openModal(modalProps => (
|
||||||
));
|
<CreateVoiceFilterModal modalProps={modalProps} close={() => closeModal(key)} defaultValue={defaultValue} />
|
||||||
return key;
|
));
|
||||||
}
|
return key;
|
||||||
|
}
|
||||||
interface CreateVoiceFilterModalProps {
|
|
||||||
modalProps: ModalProps;
|
interface CreateVoiceFilterModalProps {
|
||||||
close: () => void;
|
modalProps: ModalProps;
|
||||||
defaultValue?: Partial<IVoiceFilter>;
|
close: () => void;
|
||||||
}
|
defaultValue?: Partial<IVoiceFilter>;
|
||||||
|
}
|
||||||
|
|
||||||
// Create Voice Filter Modal
|
|
||||||
function CreateVoiceFilterModal({ modalProps, close, defaultValue }: CreateVoiceFilterModalProps): JSX.Element {
|
// Create Voice Filter Modal
|
||||||
const currentUser = useMemo(() => UserStore.getCurrentUser(), []);
|
function CreateVoiceFilterModal({ modalProps, close, defaultValue }: CreateVoiceFilterModalProps): JSX.Element {
|
||||||
const [voiceFilter, setVoiceFilter] = useState(() => (
|
const currentUser = useMemo(() => UserStore.getCurrentUser(), []);
|
||||||
{ author: currentUser.id, name: "", iconURL: "", styleKey: "", onnxFileUrl: "", ...defaultValue }
|
const [voiceFilter, setVoiceFilter] = useState(() => (
|
||||||
));
|
{ author: currentUser.id, name: "", iconURL: "", styleKey: "", onnxFileUrl: "", ...defaultValue }
|
||||||
|
));
|
||||||
const update = useCallback(<K extends keyof IVoiceFilter>(value: IVoiceFilter[K], key: K) => {
|
|
||||||
setVoiceFilter(prev => ({ ...prev, [key]: value }));
|
const update = useCallback(<K extends keyof IVoiceFilter>(value: IVoiceFilter[K], key: K) => {
|
||||||
}, []);
|
setVoiceFilter(prev => ({ ...prev, [key]: value }));
|
||||||
const submit = useCallback(() => {
|
}, []);
|
||||||
if (requiredFields.every(field => voiceFilter[field])) {
|
const submit = useCallback(() => {
|
||||||
useVoiceFiltersStore.getState().downloadVoicepack(JSON.stringify({
|
if (requiredFields.every(field => voiceFilter[field])) {
|
||||||
id: voiceFilter.author + "-" + voiceFilter.name.toLowerCase().replace(/ /g, "-"),
|
useVoiceFiltersStore.getState().downloadVoicepack(JSON.stringify({
|
||||||
available: true,
|
id: voiceFilter.author + "-" + voiceFilter.name.toLowerCase().replace(/ /g, "-"),
|
||||||
temporarilyAvailable: false,
|
available: true,
|
||||||
custom: true,
|
temporarilyAvailable: false,
|
||||||
splashGradient: "radial-gradient(circle, #d9a5a2 0%, rgba(0,0,0,0) 100%)",
|
custom: true,
|
||||||
baseColor: "#d9a5a2",
|
splashGradient: "radial-gradient(circle, #d9a5a2 0%, rgba(0,0,0,0) 100%)",
|
||||||
...voiceFilter
|
baseColor: "#d9a5a2",
|
||||||
} satisfies IVoiceFilter));
|
...voiceFilter
|
||||||
close();
|
} satisfies IVoiceFilter));
|
||||||
} else {
|
close();
|
||||||
openErrorModal("Please fill in all required fields");
|
} else {
|
||||||
}
|
openErrorModal("Please fill in all required fields");
|
||||||
}, [voiceFilter]);
|
}
|
||||||
|
}, [voiceFilter]);
|
||||||
const keyOptions: SelectOption[] = useMemo(() =>
|
|
||||||
[{ value: "", label: "(empty)" }, ...(voices ? Object.keys(voices).map(name => ({ value: name, label: name })) : [])],
|
const keyOptions: SelectOption[] = useMemo(() =>
|
||||||
[]);
|
[{ value: "", label: "(empty)" }, ...(voices ? Object.keys(voices).map(name => ({ value: name, label: name })) : [])],
|
||||||
|
[]);
|
||||||
return (
|
|
||||||
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
return (
|
||||||
<ModalHeader>
|
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||||
<Forms.FormTitle tag="h2" className="modalTitle">
|
<ModalHeader>
|
||||||
{voiceFilter.id ? "Edit a voice filter" : "Create a voice filter"}
|
<Forms.FormTitle tag="h2" className="modalTitle">
|
||||||
</Forms.FormTitle>
|
{voiceFilter.id ? "Edit a voice filter" : "Create a voice filter"}
|
||||||
<ModalCloseButton onClick={close} />
|
</Forms.FormTitle>
|
||||||
</ModalHeader>
|
<ModalCloseButton onClick={close} />
|
||||||
<ModalContent className="vc-voice-filters-modal">
|
</ModalHeader>
|
||||||
<Flex style={{ gap: "1rem" }} direction={Flex.Direction.VERTICAL}>
|
<ModalContent className="vc-voice-filters-modal">
|
||||||
<Forms.FormSection>
|
<Flex style={{ gap: "1rem" }} direction={Flex.Direction.VERTICAL}>
|
||||||
<Forms.FormTitle>Name<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
<Forms.FormSection>
|
||||||
<TextInput placeholder="Model" onChange={update} style={{ width: "100%" }} value={voiceFilter.name} name="name" required />
|
<Forms.FormTitle>Name<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
||||||
</Forms.FormSection>
|
<TextInput placeholder="Model" onChange={update} style={{ width: "100%" }} value={voiceFilter.name} name="name" required />
|
||||||
<Forms.FormSection>
|
</Forms.FormSection>
|
||||||
<Forms.FormTitle>Icon URL<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
<Forms.FormSection>
|
||||||
<TextInput placeholder="https://example.com/voicepacks/model/icon.png" onChange={update} style={{ width: "100%" }} value={voiceFilter.iconURL} name="iconURL" required />
|
<Forms.FormTitle>Icon URL<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
||||||
</Forms.FormSection>
|
<TextInput placeholder="https://example.com/voicepacks/model/icon.png" onChange={update} style={{ width: "100%" }} value={voiceFilter.iconURL} name="iconURL" required />
|
||||||
<Forms.FormSection>
|
</Forms.FormSection>
|
||||||
<Forms.FormTitle>Style Key</Forms.FormTitle>
|
<Forms.FormSection>
|
||||||
<Select
|
<Forms.FormTitle>Style Key</Forms.FormTitle>
|
||||||
options={keyOptions}
|
<Select
|
||||||
placeholder={"Select an option"}
|
options={keyOptions}
|
||||||
maxVisibleItems={5}
|
placeholder={"Select an option"}
|
||||||
closeOnSelect={true}
|
maxVisibleItems={5}
|
||||||
select={value => update(value, "styleKey")}
|
closeOnSelect={true}
|
||||||
isSelected={v => v === voiceFilter.styleKey}
|
select={value => update(value, "styleKey")}
|
||||||
serialize={String}
|
isSelected={v => v === voiceFilter.styleKey}
|
||||||
/>
|
serialize={String}
|
||||||
</Forms.FormSection>
|
/>
|
||||||
<Forms.FormSection>
|
</Forms.FormSection>
|
||||||
<Forms.FormTitle>ONNX File URL<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
<Forms.FormSection>
|
||||||
<TextInput placeholder="https://example.com/voicepacks/model/model.onnx" onChange={update} style={{ width: "100%" }} value={voiceFilter.onnxFileUrl} name="onnxFileUrl" required />
|
<Forms.FormTitle>ONNX File URL<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
||||||
</Forms.FormSection>
|
<TextInput placeholder="https://example.com/voicepacks/model/model.onnx" onChange={update} style={{ width: "100%" }} value={voiceFilter.onnxFileUrl} name="onnxFileUrl" required />
|
||||||
<Forms.FormSection>
|
</Forms.FormSection>
|
||||||
<Forms.FormTitle>Preview Sound URL<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
<Forms.FormSection>
|
||||||
<TextInput placeholder="https://example.com/voicepacks/model/preview.mp3" onChange={value => update(value ? [value] : undefined, "previewSoundURLs")} style={{ width: "100%" }} value={voiceFilter.previewSoundURLs?.[0] ?? ""} required />
|
<Forms.FormTitle>Preview Sound URL<span style={{ color: "var(--text-danger)" }}>*</span></Forms.FormTitle>
|
||||||
</Forms.FormSection>
|
<TextInput placeholder="https://example.com/voicepacks/model/preview.mp3" onChange={value => update(value ? [value] : undefined, "previewSoundURLs")} style={{ width: "100%" }} value={voiceFilter.previewSoundURLs?.[0] ?? ""} required />
|
||||||
</Flex>
|
</Forms.FormSection>
|
||||||
</ModalContent>
|
</Flex>
|
||||||
<ModalFooter>
|
</ModalContent>
|
||||||
<Flex style={{ gap: "0.5rem" }} justify={Flex.Justify.END} align={Flex.Align.CENTER}>
|
<ModalFooter>
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={close} >Cancel</Button>
|
<Flex style={{ gap: "0.5rem" }} justify={Flex.Justify.END} align={Flex.Align.CENTER}>
|
||||||
<Button color={Button.Colors.GREEN} onClick={submit}>{voiceFilter.id ? "Save" : "Create"}</Button>
|
<Button color={Button.Colors.TRANSPARENT} onClick={openHelpModal}>How to create a voicepack?</Button>
|
||||||
</Flex>
|
<Button color={Button.Colors.GREEN} onClick={submit}>{voiceFilter.id ? "Save" : "Create"}</Button>
|
||||||
</ModalFooter>
|
<Button color={Button.Colors.TRANSPARENT} onClick={close} >Cancel</Button>
|
||||||
</ModalRoot>
|
</Flex>
|
||||||
);
|
</ModalFooter>
|
||||||
}
|
</ModalRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,78 +1,93 @@
|
||||||
/*
|
/*
|
||||||
* Vencord, a Discord client mod
|
* Vencord, a Discord client mod
|
||||||
* Copyright (c) 2025 Vendicated and contributors
|
* Copyright (c) 2025 Vendicated and contributors
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { Button, Flex, Forms, Slider } from "@webpack/common";
|
import { PluginNative } from "@utils/types";
|
||||||
import { JSX } from "react";
|
import { Button, Flex, Forms, Slider } from "@webpack/common";
|
||||||
|
import { JSX } from "react";
|
||||||
import plugin, { settings } from "./index";
|
|
||||||
|
import plugin, { settings, useVoiceFiltersStore } from "./index";
|
||||||
|
|
||||||
export function openSettingsModal(): string {
|
const Native = VencordNative.pluginHelpers.CustomVoiceFilters as PluginNative<typeof import("./native")>;
|
||||||
const key = openModal(modalProps => (
|
export function openSettingsModal(): string {
|
||||||
<SettingsModal modalProps={modalProps} close={() => closeModal(key)} />
|
const key = openModal(modalProps => (
|
||||||
));
|
<SettingsModal modalProps={modalProps} close={() => closeModal(key)} />
|
||||||
return key;
|
));
|
||||||
}
|
return key;
|
||||||
|
}
|
||||||
interface SettingsModalProps {
|
|
||||||
modalProps: ModalProps;
|
interface SettingsModalProps {
|
||||||
close: () => void;
|
modalProps: ModalProps;
|
||||||
}
|
close: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
// Create Voice Filter Modal
|
function openModelFolder() {
|
||||||
function SettingsModal({ modalProps, close }: SettingsModalProps): JSX.Element {
|
const { modulePath } = useVoiceFiltersStore.getState();
|
||||||
const settingsState = settings.use();
|
Native.openFolder(modulePath);
|
||||||
const { settings: { def } } = plugin;
|
}
|
||||||
|
|
||||||
return (
|
// Create Voice Filter Modal
|
||||||
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
function SettingsModal({ modalProps, close }: SettingsModalProps): JSX.Element {
|
||||||
<ModalHeader>
|
const settingsState = settings.use();
|
||||||
<Forms.FormTitle tag="h2" className="modalTitle">
|
const { settings: { def } } = plugin;
|
||||||
Settings
|
const { deleteAll, exportVoiceFilters, importVoiceFilters } = useVoiceFiltersStore();
|
||||||
</Forms.FormTitle>
|
return (
|
||||||
<ModalCloseButton onClick={close} />
|
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||||
</ModalHeader>
|
<ModalHeader>
|
||||||
<ModalContent className="vc-voice-filters-modal">
|
<Forms.FormTitle tag="h2" className="modalTitle">
|
||||||
<Flex style={{ gap: "1rem" }} direction={Flex.Direction.VERTICAL}>
|
Settings
|
||||||
<Forms.FormSection>
|
</Forms.FormTitle>
|
||||||
<Forms.FormTitle>Pitch</Forms.FormTitle>
|
<ModalCloseButton onClick={close} />
|
||||||
<Forms.FormText className={Margins.bottom20} type="description">{def.pitch.description}</Forms.FormText>
|
</ModalHeader>
|
||||||
<Slider
|
<ModalContent className="vc-voice-filters-modal">
|
||||||
markers={def.pitch.markers}
|
<Flex style={{ gap: "1rem" }} direction={Flex.Direction.VERTICAL}>
|
||||||
minValue={def.pitch.markers[0]}
|
<Forms.FormSection>
|
||||||
maxValue={def.pitch.markers.at(-1)}
|
<Forms.FormTitle>Pitch</Forms.FormTitle>
|
||||||
initialValue={settingsState.pitch ?? def.pitch.default}
|
<Forms.FormText className={Margins.bottom20} type="description">{def.pitch.description}</Forms.FormText>
|
||||||
onValueChange={value => settingsState.pitch = value}
|
<Slider
|
||||||
onValueRender={value => `${value}`}
|
markers={def.pitch.markers}
|
||||||
stickToMarkers={true}
|
minValue={def.pitch.markers[0]}
|
||||||
/>
|
maxValue={def.pitch.markers.at(-1)}
|
||||||
</Forms.FormSection>
|
initialValue={settingsState.pitch ?? def.pitch.default}
|
||||||
<Forms.FormSection>
|
onValueChange={value => settingsState.pitch = value}
|
||||||
<Forms.FormTitle>Frequency</Forms.FormTitle>
|
onValueRender={value => `${value}`}
|
||||||
<Forms.FormText className={Margins.bottom20} type="description">{def.frequency.description}</Forms.FormText>
|
stickToMarkers={true}
|
||||||
<Slider
|
/>
|
||||||
markers={def.frequency.markers}
|
</Forms.FormSection>
|
||||||
minValue={def.frequency.markers[0]}
|
<Forms.FormSection>
|
||||||
maxValue={def.frequency.markers.at(-1)}
|
<Forms.FormTitle>Frequency</Forms.FormTitle>
|
||||||
initialValue={settingsState.frequency ?? def.frequency.default}
|
<Forms.FormText className={Margins.bottom20} type="description">{def.frequency.description}</Forms.FormText>
|
||||||
onValueChange={value => settingsState.frequency = value}
|
<Slider
|
||||||
onValueRender={value => `${value}Hz`}
|
markers={def.frequency.markers}
|
||||||
stickToMarkers={true}
|
minValue={def.frequency.markers[0]}
|
||||||
/>
|
maxValue={def.frequency.markers.at(-1)}
|
||||||
</Forms.FormSection>
|
initialValue={settingsState.frequency ?? def.frequency.default}
|
||||||
</Flex>
|
onValueChange={value => settingsState.frequency = value}
|
||||||
</ModalContent>
|
onValueRender={value => `${value}Hz`}
|
||||||
<ModalFooter>
|
stickToMarkers={true}
|
||||||
<Flex style={{ gap: "0.5rem" }} justify={Flex.Justify.END} align={Flex.Align.CENTER}>
|
/>
|
||||||
<Button color={Button.Colors.GREEN} onClick={close} >Save & Exit</Button>
|
</Forms.FormSection>
|
||||||
</Flex>
|
<Forms.FormSection>
|
||||||
</ModalFooter>
|
<Forms.FormTitle>Voicepacks:</Forms.FormTitle>
|
||||||
</ModalRoot>
|
<Forms.FormText type="description">Here you can manage your voicepacks.</Forms.FormText>
|
||||||
);
|
<Flex style={{ gap: "0.5rem" }}>
|
||||||
}
|
<Button onClick={deleteAll} color={Button.Colors.RED}>Delete all voicepacks</Button>
|
||||||
|
<Button onClick={openModelFolder} color={Button.Colors.TRANSPARENT}>Open Models Folder</Button>
|
||||||
|
<Button onClick={exportVoiceFilters} color={Button.Colors.GREEN}>Export</Button>
|
||||||
|
<Button onClick={importVoiceFilters} color={Button.Colors.GREEN}>Import</Button>
|
||||||
|
</Flex>
|
||||||
|
</Forms.FormSection>
|
||||||
|
</Flex>
|
||||||
|
</ModalContent>
|
||||||
|
<ModalFooter>
|
||||||
|
<Flex style={{ gap: "0.5rem" }} justify={Flex.Justify.END} align={Flex.Align.CENTER}>
|
||||||
|
<Button color={Button.Colors.GREEN} onClick={close} >Save & Exit</Button>
|
||||||
|
</Flex>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import { Button, Flex, Forms, Text, TextInput, Tooltip, useEffect, useState } fr
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
import { openCreateVoiceModal } from "./CreateVoiceFilterModal";
|
import { openCreateVoiceModal } from "./CreateVoiceFilterModal";
|
||||||
import { openHelpModal } from "./HelpModal";
|
|
||||||
import { DownloadIcon, DownloadingIcon, PauseIcon, PlayIcon, RefreshIcon, TrashIcon } from "./Icons";
|
import { DownloadIcon, DownloadingIcon, PauseIcon, PlayIcon, RefreshIcon, TrashIcon } from "./Icons";
|
||||||
import { downloadCustomVoiceModel, getClient, IVoiceFilter, useVoiceFiltersStore, VoiceFilterStyles } from "./index";
|
import { downloadCustomVoiceModel, getClient, IVoiceFilter, useVoiceFiltersStore, VoiceFilterStyles } from "./index";
|
||||||
import { openSettingsModal } from "./SettingsModal";
|
import { openSettingsModal } from "./SettingsModal";
|
||||||
|
@ -20,11 +19,6 @@ import { openWikiHomeModal } from "./WikiHomeModal";
|
||||||
|
|
||||||
const Native = VencordNative.pluginHelpers.CustomVoiceFilters as PluginNative<typeof import("./native")>;
|
const Native = VencordNative.pluginHelpers.CustomVoiceFilters as PluginNative<typeof import("./native")>;
|
||||||
|
|
||||||
function openModelFolder() {
|
|
||||||
const { modulePath } = useVoiceFiltersStore.getState();
|
|
||||||
const modelFolder = Native.openFolder(modulePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function openVoiceFiltersModal(): string {
|
export function openVoiceFiltersModal(): string {
|
||||||
const key = openModal(modalProps => (
|
const key = openModal(modalProps => (
|
||||||
<VoiceFiltersModal
|
<VoiceFiltersModal
|
||||||
|
@ -47,7 +41,7 @@ interface VoiceFiltersModalProps {
|
||||||
|
|
||||||
function VoiceFiltersModal({ modalProps, close, accept }: VoiceFiltersModalProps): JSX.Element {
|
function VoiceFiltersModal({ modalProps, close, accept }: VoiceFiltersModalProps): JSX.Element {
|
||||||
const [url, setUrl] = useState("");
|
const [url, setUrl] = useState("");
|
||||||
const { downloadVoicepack, deleteAll, exportVoiceFilters, importVoiceFilters, voiceFilters } = useVoiceFiltersStore();
|
const { downloadVoicepack, exportVoiceFilters, importVoiceFilters, voiceFilters } = useVoiceFiltersStore();
|
||||||
const { client } = getClient();
|
const { client } = getClient();
|
||||||
const voiceComponents = Object.values(voiceFilters).map(voice =>
|
const voiceComponents = Object.values(voiceFilters).map(voice =>
|
||||||
<VoiceFilter {...voice} key={voice.id} />
|
<VoiceFilter {...voice} key={voice.id} />
|
||||||
|
@ -64,20 +58,15 @@ function VoiceFiltersModal({ modalProps, close, accept }: VoiceFiltersModalProps
|
||||||
<ModalContent className="vc-voice-filters-modal">
|
<ModalContent className="vc-voice-filters-modal">
|
||||||
<Flex style={{ gap: "1rem" }} direction={Flex.Direction.VERTICAL}>
|
<Flex style={{ gap: "1rem" }} direction={Flex.Direction.VERTICAL}>
|
||||||
<Text>Download a voicepack from a url or paste a voicepack data here:</Text>
|
<Text>Download a voicepack from a url or paste a voicepack data here:</Text>
|
||||||
<TextInput
|
<Flex style={{ display: "grid", gridTemplateColumns: "89% 10%", gap: "0.5rem" }}>
|
||||||
value={url}
|
<TextInput
|
||||||
placeholder="( e.g. https://fox3000foxy.com/voicepacks/agents.json )"
|
value={url}
|
||||||
onChange={setUrl}
|
placeholder="( e.g. https://fox3000foxy.com/voicepacks/agents.json )"
|
||||||
onKeyDown={e => { if (e.key === "Enter") downloadVoicepack(url); }}
|
onChange={setUrl}
|
||||||
style={{ width: "100%" }}
|
onKeyDown={e => { if (e.key === "Enter") downloadVoicepack(url); }}
|
||||||
/>
|
style={{ width: "100%" }}
|
||||||
<Flex style={{ gap: "0.5rem" }}>
|
/>
|
||||||
<Button onClick={() => downloadVoicepack(url)}>Download</Button>
|
<Button onClick={() => downloadVoicepack(url || "https://fox3000foxy.com/voicepacks/agents.json")}>Download</Button>
|
||||||
<Button onClick={deleteAll} color={Button.Colors.RED}>Delete all</Button>
|
|
||||||
<Button onClick={exportVoiceFilters} color={Button.Colors.TRANSPARENT}>Export</Button>
|
|
||||||
<Button onClick={importVoiceFilters} color={Button.Colors.TRANSPARENT}>Import</Button>
|
|
||||||
<Button onClick={() => downloadVoicepack("https://fox3000foxy.com/voicepacks/agents.json")} color={Button.Colors.TRANSPARENT}>Download Default</Button>
|
|
||||||
<Button onClick={openModelFolder} color={Button.Colors.TRANSPARENT}>Open Model Folder</Button>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Text>Voice filters list:</Text>
|
<Text>Voice filters list:</Text>
|
||||||
|
@ -94,7 +83,6 @@ function VoiceFiltersModal({ modalProps, close, accept }: VoiceFiltersModalProps
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Flex style={{ gap: "0.5rem" }} justify={Flex.Justify.END} align={Flex.Align.CENTER}>
|
<Flex style={{ gap: "0.5rem" }} justify={Flex.Justify.END} align={Flex.Align.CENTER}>
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={openSettingsModal}>Settings</Button>
|
<Button color={Button.Colors.TRANSPARENT} onClick={openSettingsModal}>Settings</Button>
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={openHelpModal}>Learn how to build your own voicepack</Button>
|
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={() => openCreateVoiceModal()}>Create Voicepack</Button>
|
<Button color={Button.Colors.TRANSPARENT} onClick={() => openCreateVoiceModal()}>Create Voicepack</Button>
|
||||||
<Button color={Button.Colors.GREEN} onClick={openWikiHomeModal}>Wiki</Button>
|
<Button color={Button.Colors.GREEN} onClick={openWikiHomeModal}>Wiki</Button>
|
||||||
<Button color={Button.Colors.RED} onClick={accept}>Close</Button>
|
<Button color={Button.Colors.RED} onClick={accept}>Close</Button>
|
||||||
|
|
Loading…
Add table
Reference in a new issue