diff --git a/packages/fakeyou.com/src/v2/view/_common/FastReactSelectOption.tsx b/packages/fakeyou.com/src/v2/view/_common/react_select/FastReactSelectOption.tsx similarity index 100% rename from packages/fakeyou.com/src/v2/view/_common/FastReactSelectOption.tsx rename to packages/fakeyou.com/src/v2/view/_common/react_select/FastReactSelectOption.tsx diff --git a/packages/fakeyou.com/src/v2/view/_common/react_select/FixedSingleValueSelectOption.tsx b/packages/fakeyou.com/src/v2/view/_common/react_select/FixedSingleValueSelectOption.tsx new file mode 100644 index 0000000000..5c3a2aa3ff --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/_common/react_select/FixedSingleValueSelectOption.tsx @@ -0,0 +1,14 @@ +import React, { Fragment } from "react"; +import { components } from "react-select"; + +// Problem - search label isn't present when searching, confusing users that don't realize it's +// a text search box. +// Ticket: https://github.com/JedWatson/react-select/issues/1351 +// Solution from: https://codesandbox.io/s/hide-selected-on-focus-react-select-n05yi2?file=/src/App.js:531-774 + +export function FixedSingleValueSelectOption(props: any) { + const { children, ...rest } = props; + const { selectProps } = props; + if (selectProps.menuIsOpen) return ; + return {children}; +} \ No newline at end of file diff --git a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/TtsModelListPage.tsx b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/TtsModelListPage.tsx index fc53d53da1..9a15879046 100644 --- a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/TtsModelListPage.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/TtsModelListPage.tsx @@ -30,7 +30,6 @@ import { ListTtsCategoriesIsOk, } from "@storyteller/components/src/api/category/ListTtsCategories"; import { TtsCategoryType } from "../../../../../AppWrapper"; -import { SelectSearch } from "./search/SelectSearch"; import { LanguageNotice } from "./notices/LanguageNotice"; import { Language } from "@storyteller/components/src/i18n/Language"; import { TwitchTtsNotice } from "./notices/TwitchTtsNotice"; @@ -39,8 +38,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faArrowRight, faBarsStaggered, - faChevronDown, - faChevronUp, faDeleteLeft, faGlobe, faVolumeHigh, @@ -69,7 +66,7 @@ import { WebUrl } from "../../../../../common/WebUrl"; import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle"; import { RatingButtons } from "../../../_common/ratings/RatingButtons"; import { RatingStats } from "../../../_common/ratings/RatingStats"; -import { ExploreVoicesModal } from "./explore/ExploreVoicesModal"; +import { SearchOmnibar } from "./search/SearchOmnibar"; export interface EnqueueJobResponsePayload { success: boolean; @@ -150,12 +147,6 @@ function TtsModelListPage(props: Props) { return () => clearTimeout(timeout); }, []); - const [isOpen, setIsOpen] = useState(false); - - const handleClickExplore = () => { - setIsOpen(!isOpen); - }; - let { setTtsModels, setAllTtsCategories, @@ -522,82 +513,29 @@ function TtsModelListPage(props: Props) { onSubmit={handleFormSubmit} > {/* Explore Rollout */} -
- -
-
-
- - {/* - - */} -
+ -
-
- -
- - {} - - -
-
+ {/* + + + EXPLORE OMNIBAR GOES HERE TODO + + */} {directViewLink} diff --git a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SearchOmnibar.tsx b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SearchOmnibar.tsx new file mode 100644 index 0000000000..b3a8a7bc55 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SearchOmnibar.tsx @@ -0,0 +1,117 @@ +import React, { useState } from "react"; +import { t } from "i18next"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { TtsCategoryType } from "../../../../../../AppWrapper"; +import { TtsModelListItem } from "@storyteller/components/src/api/tts/ListTtsModels"; +import { ExploreVoicesTray } from "./components/ExploreVoicesTray"; +import { faChevronDown, faChevronUp } from "@fortawesome/pro-duotone-svg-icons"; +import { ScopedVoiceModelOptions } from "./components/ScopedVoiceModelOptions"; +import { VoiceCountLabel } from "./components/VoiceCountLabel"; +import { Analytics } from "../../../../../../common/Analytics"; + +interface Props { + allTtsCategories: TtsCategoryType[]; + allTtsModels: TtsModelListItem[]; + + allTtsCategoriesByTokenMap: Map; + allTtsModelsByTokenMap: Map; + ttsModelsByCategoryToken: Map>; + + dropdownCategories: TtsCategoryType[][]; + setDropdownCategories: (dropdownCategories: TtsCategoryType[][]) => void; + + selectedCategories: TtsCategoryType[]; + setSelectedCategories: (selectedCategories: TtsCategoryType[]) => void; + + maybeSelectedTtsModel?: TtsModelListItem; + setMaybeSelectedTtsModel: (maybeSelectedTtsModel: TtsModelListItem) => void; + + selectedTtsLanguageScope: string; + setSelectedTtsLanguageScope: (selectedTtsLanguageScope: string) => void; +} + +export function SearchOmnibar(props: Props) { + const [isOpen, setIsOpen] = useState(false); + + const handleClickExplore = () => { + setIsOpen(!isOpen); + }; + + const canSearchVoices = !isOpen; // TODO: Perhaps only set false on mobile. + + return ( + <> +
+ +
+ +
+ + +
+
+ +
+ + {} + + +
+
+ + ) +} diff --git a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SelectSearch.tsx b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SelectSearch.tsx index d3d7e58a8d..066f207a44 100644 --- a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SelectSearch.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/SelectSearch.tsx @@ -1,13 +1,14 @@ -import React, { Fragment } from "react"; +import React from "react"; import { TtsModelListItem } from "@storyteller/components/src/api/tts/ListTtsModels"; import { TtsCategoryType } from "../../../../../../AppWrapper"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSearch } from "@fortawesome/free-solid-svg-icons"; -import Select, { ActionMeta, createFilter, components } from "react-select"; +import Select, { ActionMeta, createFilter } from "react-select"; import Option from "react-select"; import { SearchFieldClass } from "./SearchFieldClass"; -import { FastReactSelectOption } from "../../../../_common/FastReactSelectOption"; +import { FastReactSelectOption } from "../../../../_common/react_select/FastReactSelectOption"; import { Analytics } from "../../../../../../common/Analytics"; +import { FixedSingleValueSelectOption } from "../../../../_common/react_select/FixedSingleValueSelectOption"; interface Props { allTtsCategories: TtsCategoryType[]; @@ -92,21 +93,9 @@ export function SelectSearch(props: Props) { // NB: The following settings improve upon performance. // See: https://github.com/JedWatson/react-select/issues/3128 filterOption={createFilter({ignoreAccents: false})} - components={{SingleValue: FixedSingleValue, Option: FastReactSelectOption} as any} + components={{SingleValue: FixedSingleValueSelectOption, Option: FastReactSelectOption} as any} /> ); } - -// Problem - search label isn't present when searching, confusing users that don't realize it's -// a text search box. -// Ticket: https://github.com/JedWatson/react-select/issues/1351 -// Solution from: https://codesandbox.io/s/hide-selected-on-focus-react-select-n05yi2?file=/src/App.js:531-774 - -function FixedSingleValue(props: any) { - const { children, ...rest } = props; - const { selectProps } = props; - if (selectProps.menuIsOpen) return ; - return {children}; -} diff --git a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/explore/ExploreVoicesModal.tsx b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/components/ExploreVoicesTray.tsx similarity index 82% rename from packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/explore/ExploreVoicesModal.tsx rename to packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/components/ExploreVoicesTray.tsx index f7b65e8895..aeb262cffc 100644 --- a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/explore/ExploreVoicesModal.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/components/ExploreVoicesTray.tsx @@ -1,11 +1,10 @@ import React from "react"; import { faEraser } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { LanguageOptions } from "./LanguageOptions"; -import { TtsCategoryType } from "../../../../../../AppWrapper"; +import { LanguageOptions } from "../filters/LanguageOptions"; +import { TtsCategoryType } from "../../../../../../../AppWrapper"; import { TtsModelListItem } from "@storyteller/components/src/api/tts/ListTtsModels"; -import { CategoryOptions } from "./CategoryOptions"; -import { ScopedVoiceModelOptions } from "./ScopedVoiceModelOptions"; +import { CategoryOptions } from "../filters/CategoryOptions"; import { t } from "i18next"; interface Props { @@ -29,7 +28,7 @@ interface Props { setSelectedTtsLanguageScope: (selectedTtsLanguageScope: string) => void; } -export function ExploreVoicesModal(props: Props) { +export function ExploreVoicesTray(props: Props) { const { allTtsCategories, allTtsCategoriesByTokenMap, @@ -132,20 +131,6 @@ export function ExploreVoicesModal(props: Props) { /> -
- -
); } diff --git a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/explore/ScopedVoiceModelOptions.tsx b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/components/ScopedVoiceModelOptions.tsx similarity index 67% rename from packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/explore/ScopedVoiceModelOptions.tsx rename to packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/components/ScopedVoiceModelOptions.tsx index 385a82fc40..5e171f3e69 100644 --- a/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/explore/ScopedVoiceModelOptions.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/tts/tts_model_list/search/components/ScopedVoiceModelOptions.tsx @@ -2,12 +2,12 @@ import React from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 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"; +import { TtsCategoryType } from "../../../../../../../AppWrapper"; import Select, { createFilter } from "react-select"; -import { SearchFieldClass } from "../search/SearchFieldClass"; -import { FastReactSelectOption } from "../../../../_common/FastReactSelectOption"; -import { Analytics } from "../../../../../../common/Analytics"; +import { SearchFieldClass } from "../SearchFieldClass"; +import { FastReactSelectOption } from "../../../../../_common/react_select/FastReactSelectOption"; +import { Analytics } from "../../../../../../../common/Analytics"; +import { FixedSingleValueSelectOption } from "../../../../../_common/react_select/FixedSingleValueSelectOption"; interface Props { allTtsCategories: TtsCategoryType[]; @@ -24,6 +24,8 @@ interface Props { setMaybeSelectedTtsModel: (maybeSelectedTtsModel: TtsModelListItem) => void; selectedTtsLanguageScope: string; + + canSearchVoices: boolean; } export function ScopedVoiceModelOptions(props: Props) { @@ -88,8 +90,6 @@ export function ScopedVoiceModelOptions(props: Props) { }; } - const voiceCount = options.length; - let isLoading = false; if (props.allTtsModels.length === 0) { @@ -111,40 +111,56 @@ export function ScopedVoiceModelOptions(props: Props) { }; } + let select; + + if (props.canSearchVoices) { + select = ( + { + 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. + // See: https://github.com/JedWatson/react-select/issues/3128 + filterOption={createFilter({ ignoreAccents: false })} + components={{ Option: FastReactSelectOption } as any} + /> + ); + } + return ( <>
- -
-