mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-02 16:38:14 +00:00
explore slide from top
This commit is contained in:
1 parent
b3e9e4aceb
commit
ec4e5f77ca
4 files changed
+97
-89
No files matched your search
@@ -834,7 +834,7 @@ styles with important tags:
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
transition-property: none !important;
|
||||
transition: all 0.05s !important;
|
||||
transition: all 0.1s !important;
|
||||
transition-timing-function: ease !important;
|
||||
}
|
||||
.sliding-content.open {
|
||||
@@ -842,7 +842,7 @@ styles with important tags:
|
||||
opacity: 1;
|
||||
height: 100%;
|
||||
transition-property: none !important;
|
||||
transition: all 0.2s !important;
|
||||
transition: all 0.4s !important;
|
||||
transition-timing-function: ease !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,11 +150,9 @@ function TtsModelListPage(props: Props) {
|
||||
return () => clearTimeout(timeout);
|
||||
}, []);
|
||||
|
||||
const [isSliding, setIsSliding] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const handleClick = () => {
|
||||
setIsSliding(!isSliding);
|
||||
const handleClickExplore = () => {
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
@@ -523,60 +521,10 @@ function TtsModelListPage(props: Props) {
|
||||
className="w-100 d-flex flex-column"
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<div className="pb-4">
|
||||
<div className="d-flex gap-2">
|
||||
<label className="sub-title">
|
||||
{t("tts.TtsModelListPage.form.searchBarLabel")}
|
||||
</label>
|
||||
{/*<a href="/" className="ms-1">
|
||||
<FontAwesomeIcon icon={faShuffle} />
|
||||
</a>*/}
|
||||
</div>
|
||||
|
||||
<div className="d-flex flex-column flex-lg-row gap-3 ">
|
||||
<div className="flex-grow-1">
|
||||
<SelectSearch
|
||||
allTtsCategories={props.allTtsCategories}
|
||||
allTtsModels={props.ttsModels}
|
||||
allTtsModelsByTokenMap={props.allTtsModelsByTokenMap}
|
||||
dropdownCategories={props.dropdownCategories}
|
||||
setDropdownCategories={props.setDropdownCategories}
|
||||
selectedCategories={props.selectedCategories}
|
||||
setSelectedCategories={props.setSelectedCategories}
|
||||
maybeSelectedTtsModel={props.maybeSelectedTtsModel}
|
||||
setMaybeSelectedTtsModel={
|
||||
props.setMaybeSelectedTtsModel
|
||||
}
|
||||
selectedTtsLanguageScope={
|
||||
props.selectedTtsLanguageScope
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleClick}
|
||||
// onClick={() => {
|
||||
// Analytics.ttsOpenExploreVoicesModal();
|
||||
// }}
|
||||
className="btn btn-primary rounded-50"
|
||||
type="button"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={isOpen ? faChevronUp : faChevronDown}
|
||||
className="me-2"
|
||||
/>
|
||||
{t(
|
||||
"tts.TtsModelListPage.exploreModal.exploreModalOpenButton"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Explore Modal */}
|
||||
|
||||
{/* Explore Rollout */}
|
||||
<div
|
||||
className={`sliding-content ${
|
||||
isSliding ? "open pb-4 mt-2 mb-3" : "closed"
|
||||
isOpen ? "open pb-4" : "closed"
|
||||
}`}
|
||||
>
|
||||
<ExploreVoicesModal
|
||||
@@ -600,6 +548,57 @@ function TtsModelListPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pb-4">
|
||||
<div className="d-flex gap-2">
|
||||
<label className="sub-title">
|
||||
{t("tts.TtsModelListPage.form.searchBarLabel")}
|
||||
</label>
|
||||
{/*<a href="/" className="ms-1">
|
||||
<FontAwesomeIcon icon={faShuffle} />
|
||||
</a>*/}
|
||||
</div>
|
||||
|
||||
<div className="d-flex flex-column flex-lg-row gap-3 zi-2">
|
||||
<div className="flex-grow-1">
|
||||
<SelectSearch
|
||||
allTtsCategories={props.allTtsCategories}
|
||||
allTtsModels={props.ttsModels}
|
||||
allTtsModelsByTokenMap={props.allTtsModelsByTokenMap}
|
||||
dropdownCategories={props.dropdownCategories}
|
||||
setDropdownCategories={props.setDropdownCategories}
|
||||
selectedCategories={props.selectedCategories}
|
||||
setSelectedCategories={props.setSelectedCategories}
|
||||
maybeSelectedTtsModel={props.maybeSelectedTtsModel}
|
||||
setMaybeSelectedTtsModel={
|
||||
props.setMaybeSelectedTtsModel
|
||||
}
|
||||
selectedTtsLanguageScope={
|
||||
props.selectedTtsLanguageScope
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{}
|
||||
|
||||
<button
|
||||
onClick={handleClickExplore}
|
||||
// onClick={() => {
|
||||
// Analytics.ttsOpenExploreVoicesModal();
|
||||
// }}
|
||||
className="btn btn-primary rounded-50"
|
||||
type="button"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={isOpen ? faChevronUp : faChevronDown}
|
||||
className="me-2"
|
||||
/>
|
||||
{t(
|
||||
"tts.TtsModelListPage.exploreModal.exploreModalOpenButton"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{directViewLink}
|
||||
|
||||
<div className="row gx-5 gy-5">
|
||||
|
||||
+16
-1
@@ -5,7 +5,7 @@ import { LanguageOptions } from "./LanguageOptions";
|
||||
import { TtsCategoryType } from "../../../../../../AppWrapper";
|
||||
import { TtsModelListItem } from "@storyteller/components/src/api/tts/ListTtsModels";
|
||||
import { CategoryOptions } from "./CategoryOptions";
|
||||
// import { ScopedVoiceModelOptions } from "./ScopedVoiceModelOptions";
|
||||
import { ScopedVoiceModelOptions } from "./ScopedVoiceModelOptions";
|
||||
import { t } from "i18next";
|
||||
|
||||
interface Props {
|
||||
@@ -108,6 +108,7 @@ export function ExploreVoicesModal(props: Props) {
|
||||
onClick={() => {
|
||||
handleChangeCategory(0, "*");
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<FontAwesomeIcon icon={faEraser} className="me-2" />
|
||||
{t("tts.TtsModelListPage.exploreModal.clearCategoryFilterButton")}
|
||||
@@ -131,6 +132,20 @@ export function ExploreVoicesModal(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<ScopedVoiceModelOptions
|
||||
allTtsCategories={props.allTtsCategories}
|
||||
allTtsModels={props.allTtsModels}
|
||||
allTtsCategoriesByTokenMap={props.allTtsCategoriesByTokenMap}
|
||||
allTtsModelsByTokenMap={props.allTtsModelsByTokenMap}
|
||||
ttsModelsByCategoryToken={props.ttsModelsByCategoryToken}
|
||||
dropdownCategories={props.dropdownCategories}
|
||||
selectedCategories={props.selectedCategories}
|
||||
maybeSelectedTtsModel={props.maybeSelectedTtsModel}
|
||||
setMaybeSelectedTtsModel={props.setMaybeSelectedTtsModel}
|
||||
selectedTtsLanguageScope={props.selectedTtsLanguageScope}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+25
-31
@@ -1,8 +1,6 @@
|
||||
import React from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faMicrophone,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faMicrophone } from "@fortawesome/free-solid-svg-icons";
|
||||
import { TtsModelListItem } from "@storyteller/components/src/api/tts/ListTtsModels";
|
||||
import { TtsCategoryType } from "../../../../../../AppWrapper";
|
||||
import { Trans } from "react-i18next";
|
||||
@@ -25,7 +23,7 @@ interface Props {
|
||||
maybeSelectedTtsModel?: TtsModelListItem;
|
||||
setMaybeSelectedTtsModel: (maybeSelectedTtsModel: TtsModelListItem) => void;
|
||||
|
||||
selectedTtsLanguageScope: string,
|
||||
selectedTtsLanguageScope: string;
|
||||
}
|
||||
|
||||
export function ScopedVoiceModelOptions(props: Props) {
|
||||
@@ -44,17 +42,16 @@ export function ScopedVoiceModelOptions(props: Props) {
|
||||
if (maybeNewTtsModel !== undefined) {
|
||||
props.setMaybeSelectedTtsModel(maybeNewTtsModel);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const leafiestCategory = selectedCategories[selectedCategories.length - 1];
|
||||
|
||||
let leafiestCategoryModels: Array<TtsModelListItem> = [];
|
||||
|
||||
if (leafiestCategory !== undefined) {
|
||||
leafiestCategoryModels =
|
||||
Array.from(
|
||||
ttsModelsByCategoryToken.get(leafiestCategory.category_token) ||
|
||||
new Set());
|
||||
leafiestCategoryModels = Array.from(
|
||||
ttsModelsByCategoryToken.get(leafiestCategory.category_token) || new Set()
|
||||
);
|
||||
} else {
|
||||
leafiestCategoryModels = Array.from(new Set(allTtsModels));
|
||||
}
|
||||
@@ -65,16 +62,20 @@ export function ScopedVoiceModelOptions(props: Props) {
|
||||
if (props.selectedTtsLanguageScope === "*") {
|
||||
return true; // NB: Sentinel value of "*" means all languages.
|
||||
}
|
||||
return ttsModel.ietf_primary_language_subtag === props.selectedTtsLanguageScope;
|
||||
return (
|
||||
ttsModel.ietf_primary_language_subtag === props.selectedTtsLanguageScope
|
||||
);
|
||||
})
|
||||
.map((ttsModel) => {
|
||||
return {
|
||||
label: ttsModel.title,
|
||||
value: ttsModel.model_token,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let selectedOption = options.find((option) => option.value === maybeSelectedTtsModel?.model_token);
|
||||
let selectedOption = options.find(
|
||||
(option) => option.value === maybeSelectedTtsModel?.model_token
|
||||
);
|
||||
|
||||
if (selectedOption === undefined && options.length > 0) {
|
||||
// NB: We shouldn't select the first item in the list since that won't update the currently
|
||||
@@ -84,9 +85,9 @@ export function ScopedVoiceModelOptions(props: Props) {
|
||||
selectedOption = {
|
||||
label: "Select voice...",
|
||||
value: "*",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const voiceCount = options.length;
|
||||
|
||||
let isLoading = false;
|
||||
@@ -101,27 +102,18 @@ export function ScopedVoiceModelOptions(props: Props) {
|
||||
selectedOption = {
|
||||
label: "Loading...",
|
||||
value: "*",
|
||||
}
|
||||
};
|
||||
} else if (options.length === 0) {
|
||||
// NB: Perhaps the user has refined their search to be too narrow (langauge + category)
|
||||
selectedOption = {
|
||||
label: "No results (remove some filters)",
|
||||
value: "*",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="col">
|
||||
<label className="sub-title">
|
||||
<Trans
|
||||
i18nKey="tts.TtsModelListPage.form.voicesLabel"
|
||||
count={voiceCount}
|
||||
>
|
||||
Voice ({voiceCount} to choose from)
|
||||
</Trans>
|
||||
</label>
|
||||
|
||||
<div className="input-icon-search">
|
||||
<span className="form-control-feedback">
|
||||
<FontAwesomeIcon icon={faMicrophone} />
|
||||
@@ -132,18 +124,20 @@ export function ScopedVoiceModelOptions(props: Props) {
|
||||
options={options}
|
||||
classNames={SearchFieldClass}
|
||||
onChange={handleChange}
|
||||
onMenuOpen={() => { Analytics.ttsOpenScopedVoiceSelectMenu() } }
|
||||
onMenuOpen={() => {
|
||||
Analytics.ttsOpenScopedVoiceSelectMenu();
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
// On mobile, we don't want the onscreen keyboard to take up half the UI.
|
||||
autoFocus={false}
|
||||
isSearchable={false}
|
||||
// NB: The following settings improve upon performance.
|
||||
// NB: The following settings improve upon performance.
|
||||
// See: https://github.com/JedWatson/react-select/issues/3128
|
||||
filterOption={createFilter({ignoreAccents: false})}
|
||||
components={{Option: FastReactSelectOption} as any}
|
||||
/>
|
||||
filterOption={createFilter({ ignoreAccents: false })}
|
||||
components={{ Option: FastReactSelectOption } as any}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user