search bar working with search results page

This commit is contained in:
BFlat committed 2023-12-21 11:07:56 +07:00
1 parent bf514840f6
commit aec96f4dfd
9 files changed
+805 -587

No files matched your search

@@ -81,6 +81,13 @@
}
}
.loading-results {
&:hover {
background-color: $panel-inner !important;
cursor: default !important;
}
}
@media (max-width: 992px) {
.search-bar-container {
width: 100%;
@@ -8,6 +8,8 @@ import {
import SearchResultsDropdown from "./SearchResultsDropdown";
import SearchField from "./SearchField";
import "./SearchBar.scss";
import { useHistory, useLocation } from "react-router-dom";
import { useSearch } from "context/SearchContext";
interface SearchBarProps {
autoFocus?: boolean;
@@ -22,13 +24,20 @@ export default function SearchBar({
onFocus,
isFocused,
}: SearchBarProps) {
const [searchTerm, setSearchTerm] = useState<string>("");
let history = useHistory();
let location = useLocation();
const { searchTerm, setSearchTerm } = useSearch();
const [foundTtsModels, setFoundTtsModels] = useState<TtsModel[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const isOnSearchPage = location.pathname.startsWith("/search");
const maybeSearch = useCallback(async (value: string) => {
setSearchTerm(value);
}, []);
const maybeSearch = useCallback(
async (value: string) => {
setSearchTerm(value);
},
[setSearchTerm]
);
const doSearch = useCallback(
async (value: string) => {
@@ -53,8 +62,34 @@ export default function SearchBar({
);
useEffect(() => {
doSearch(searchTerm);
}, [doSearch, searchTerm]);
if (isOnSearchPage) {
const query = new URLSearchParams(location.search).get("query");
if (query) {
setSearchTerm(query);
}
}
}, [isOnSearchPage, location.search, setSearchTerm]);
useEffect(() => {
if (isOnSearchPage) {
history.push(`/search/weights?query=${encodeURIComponent(searchTerm)}`);
} else {
doSearch(searchTerm);
}
}, [searchTerm, history, location.pathname, doSearch, isOnSearchPage]);
const handleSearchButtonClick = useCallback(() => {
history.push(`/search/weights?query=${encodeURIComponent(searchTerm)}`);
}, [searchTerm, history]);
const handleKeyPress = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
handleSearchButtonClick();
}
},
[handleSearchButtonClick]
);
return (
<div className="search-bar-container">
@@ -62,22 +97,24 @@ export default function SearchBar({
<SearchField
value={searchTerm}
onChange={maybeSearch}
onKeyPress={handleKeyPress}
onFocus={onFocus}
onBlur={onBlur}
autoFocus={autoFocus}
/>
{isFocused && (
{isFocused && !isOnSearchPage && (
<SearchResultsDropdown
data={foundTtsModels}
isNoResults={foundTtsModels.length === 0 && searchTerm !== ""}
isLoading={isLoading}
searchTerm={searchTerm}
/>
)}
</div>
<Button
icon={faSearch}
onClick={() => {}}
onClick={handleSearchButtonClick}
variant="secondary"
className="search-bar-button d-none d-lg-flex"
/>
@@ -7,6 +7,7 @@ interface SearchFieldProps {
onFocus?: () => void;
onBlur?: () => void;
autoFocus?: boolean;
onKeyPress?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
}
export default function SearchField({
@@ -14,6 +15,7 @@ export default function SearchField({
onChange,
onFocus,
onBlur,
onKeyPress,
autoFocus = false,
}: SearchFieldProps) {
return (
@@ -26,6 +28,7 @@ export default function SearchField({
onFocus={onFocus}
onBlur={onBlur}
autoFocus={autoFocus}
onKeyPress={onKeyPress}
/>
);
}
@@ -7,25 +7,34 @@ interface SearchResultsDropdownProps {
data: TtsModel[];
isNoResults?: boolean;
isLoading?: boolean;
searchTerm?: string;
}
export default function SearchResultsDropdown({
data,
isNoResults,
isLoading,
searchTerm,
}: SearchResultsDropdownProps) {
const history = useHistory();
const handleResultClick = (item: TtsModel, event: React.MouseEvent) => {
event.stopPropagation();
event.preventDefault();
history.push(`/weights/${item.model_token}`);
history.push(`/weight/${item.model_token}`);
};
const handleInnerClick = (event: any) => {
event.stopPropagation();
};
const handleUrlPush = (event: React.MouseEvent) => {
event.stopPropagation();
if (searchTerm) {
history.push(`/search/weights?query=${encodeURIComponent(searchTerm)}`);
}
};
return (
<>
{data.length !== 0 && (
@@ -56,30 +65,27 @@ export default function SearchResultsDropdown({
</div>
);
})}
<div className="search-results-dropdown-item view-more p-3">
<div
className="search-results-dropdown-item view-more p-3"
onClick={handleUrlPush}
>
View more results
</div>
</div>
)}
{data.length === 0 && !isLoading && isNoResults && (
<div className="search-results-dropdown">
<div
className="search-results-dropdown-item p-3 no-results"
onClick={handleInnerClick}
>
<div className="search-results-dropdown-item p-3 no-results">
No results found
</div>
</div>
)}
{isLoading && isNoResults && (
<div className="search-results-dropdown">
<div
className="search-results-dropdown-item p-3"
onClick={handleInnerClick}
>
<div className="search-results-dropdown-item p-3 loading-results">
<div className="text-center">
<div
className="spinner-border spinner-border-md opacity-50"
className="spinner-border spinner-border-md opacity-75"
role="status"
>
<span className="visually-hidden">Loading...</span>
@@ -15,7 +15,8 @@ interface PageHeaderProps {
back?: BackConfig;
titleIcon?: IconDefinition;
title: string | React.ReactNode;
subText: string | React.ReactNode;
titleH2?: boolean;
subText?: string | React.ReactNode;
full?: boolean;
showButton?: boolean;
extension?: React.ReactNode;
@@ -42,6 +43,7 @@ export default function PageHeader({
back,
titleIcon,
title,
titleH2 = false,
subText,
full,
showButton,
@@ -111,10 +113,15 @@ export default function PageHeader({
} justify-content-center gap-4 py-2`}
>
<div>
<h1 className="fw-bold">
{/* {icon} */}
{title}
</h1>
{titleH2 ? (
<h2 className="fw-bold">{title}</h2>
) : (
<h1 className="fw-bold">
{/* {icon} */}
{title}
</h1>
)}
<p className={typeof subText === "string" ? "opacity-75" : ""}>
{subText}
</p>
@@ -0,0 +1,23 @@
import React, { createContext, useContext, useState } from "react";
interface SearchContextType {
searchTerm: string;
setSearchTerm: (value: string) => void;
}
const SearchContext = createContext<SearchContextType>({
searchTerm: "",
setSearchTerm: () => {},
});
export const useSearch = () => useContext(SearchContext);
export const SearchProvider: React.FC = ({ children }) => {
const [searchTerm, setSearchTerm] = useState<string>("");
return (
<SearchContext.Provider value={{ searchTerm, setSearchTerm }}>
{children}
</SearchContext.Provider>
);
};
+1 -1
View File
@@ -1,4 +1,4 @@
import InferenceJobsContext from "./InferenceJobsContext";
import SessionContext from "./SessionContext";
export { InferenceJobsContext, SessionContext };
export { InferenceJobsContext, SessionContext };
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,111 @@
import React, { useCallback, useEffect, useState } from "react";
import Container from "components/common/Container";
import PageHeader from "components/layout/PageHeader";
import { faClock } from "@fortawesome/pro-solid-svg-icons";
import Panel from "components/common/Panel";
import ModelSearchResults from "components/common/ModelSearchResults";
import ModelTags from "components/common/ModelTags";
import Select from "components/common/Select";
import {
SearchTtsModels,
TtsModel,
} from "@storyteller/components/src/api/tts/SearchTtsModels";
import { useLocation } from "react-router-dom";
const allTags = [
"English",
"Spanish",
"Portuguese",
"High-pitched",
"Low-pitched",
"Character",
];
export default function SearchPage() {
const [foundTtsModels, setFoundTtsModels] = useState<TtsModel[]>([]);
const useQuery = () => {
return new URLSearchParams(useLocation().search);
};
const doSearch = useCallback(
async (value: string) => {
let request = {
search_term: value,
};
let response = await SearchTtsModels(request);
if (response.success) {
let models = [...response.models];
setFoundTtsModels(models);
} else {
setFoundTtsModels([]);
}
},
[setFoundTtsModels]
);
const query = useQuery();
const urlSearchTerm = query.get("query") || "";
useEffect(() => {
if (urlSearchTerm) {
doSearch(urlSearchTerm);
}
}, [urlSearchTerm, doSearch]);
let selectedTags: any = [];
let handleSelectTag = () => {};
const tags = (
<div className="d-flex flex-column gap-3">
<ModelTags
tags={allTags}
selectedTags={selectedTags}
onSelectTag={handleSelectTag}
/>
</div>
);
const sortOptions = [
{ value: "most liked", label: "Most Liked" },
{ value: "most used", label: "Most Used" },
{ value: "moset recent", label: "Most Recent" },
];
const sortTimeOptions = [
{ value: "all time", label: "All Time" },
{ value: "today", label: "Today" },
{ value: "this week", label: "This Week" },
{ value: "this month", label: "This Month" },
];
return (
<Container type="panel" className="mb-5">
<PageHeader
title={`${foundTtsModels.length || "0"} results for "${urlSearchTerm}"`}
titleH2={true}
extension={tags}
panel={false}
/>
<Panel padding={true}>
<div className="d-flex gap-2 mb-4">
<Select
small={true}
options={sortOptions}
defaultValue={sortOptions[0]}
/>
<Select
small={true}
icon={faClock}
options={sortTimeOptions}
defaultValue={sortTimeOptions[0]}
/>
</div>
{/*<ModelSearchResults data={filteredData} />*/}
<ModelSearchResults data={foundTtsModels} />
</Panel>
</Container>
);
}