diff --git a/public/assets/common/icons/arrow-right.svg b/public/assets/common/icons/arrow-right.svg new file mode 100644 index 0000000000..923e82bb1a --- /dev/null +++ b/public/assets/common/icons/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/common/icons/download.svg b/public/assets/common/icons/download.svg new file mode 100644 index 0000000000..896b5c8414 --- /dev/null +++ b/public/assets/common/icons/download.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/components/elements/SearchInputs.tsx b/src/app/components/elements/SearchInputs.tsx index 96361418d3..ab7f268e22 100644 --- a/src/app/components/elements/SearchInputs.tsx +++ b/src/app/components/elements/SearchInputs.tsx @@ -1,6 +1,60 @@ -import React, {ChangeEvent} from "react"; -import {Button, Input, InputGroup, Label} from "reactstrap"; -import {siteSpecific, withSearch} from "../../services"; +import React, {ChangeEvent, FormEvent, useEffect, useRef, useState} from "react"; +import {Button, Form, Input, InputGroup, InputProps, Label} from "reactstrap"; +import {ifKeyIsEnter, pushSearchToHistory, SEARCH_CHAR_LENGTH_LIMIT, siteSpecific} from "../../services"; +import classNames from "classnames"; +import { useHistory, useLocation } from "react-router"; + +interface SearchInputProps { + setSearchText: (s: string) => void; + searchText: string; + inputProps: { + innerRef: React.RefObject; + "aria-label": "Search"; + type: "search"; + name: "query"; + maxLength: typeof SEARCH_CHAR_LENGTH_LIMIT; + placeholder: "Search"; + }; +} + +// HOC pattern for making different flavour search bars +function withSearch(Component: React.FC) { + const SearchComponent = ({className, inline, onSearch, initialValue}: {className?: string; inline?: boolean; onSearch?: (searchText: string) => void; initialValue?: string}) => { + const [searchText, setSearchText] = useState(initialValue ?? ""); + const searchInputRef = useRef(null); + + const history = useHistory(); + function doSearch(e: FormEvent) { + e.preventDefault(); + if (searchText === "") { + if (searchInputRef.current) searchInputRef.current.focus(); + } else { + onSearch?.(searchText); + pushSearchToHistory(history, searchText, []); + } + } + + // Clear this search field on location (i.e. search query) change - user should use the main search bar + const location = useLocation(); + useEffect(() => { if (location.pathname === "/search") { setSearchText(initialValue ?? ""); }}, [location]); + + return
+
+ + +
+
; + }; + SearchComponent.displayName = "SearchComponent"; + return SearchComponent; +} const PhysicsSearchButton = () => ( + ; +}; diff --git a/src/app/components/pages/QuestionFinder.tsx b/src/app/components/pages/QuestionFinder.tsx index bfa9c58010..49317915c9 100644 --- a/src/app/components/pages/QuestionFinder.tsx +++ b/src/app/components/pages/QuestionFinder.tsx @@ -42,7 +42,7 @@ import {MetaDescription} from "../elements/MetaDescription"; import {CanonicalHrefElement} from "../navigation/CanonicalHrefElement"; import classNames from "classnames"; import queryString from "query-string"; -import {Button, Card, CardBody, CardHeader, Col, Container, Input, InputGroup, Label, Row} from "reactstrap"; +import {Button, Card, CardBody, CardHeader, Col, Container, Label, Row} from "reactstrap"; import {ChoiceTree, getChoiceTreeLeaves, QuestionFinderFilterPanel} from "../elements/panels/QuestionFinderFilterPanel"; import {TierID} from "../elements/svg/HierarchyFilter"; import { MainContent, QuestionFinderSidebar, SidebarLayout } from "../elements/layout/SidebarLayout"; @@ -51,6 +51,7 @@ import { ContentTypeVisibility, LinkToContentSummaryList } from "../elements/lis import { PageFragment } from "../elements/PageFragment"; import { RenderNothing } from "../elements/RenderNothing"; import { processTagHierarchy, pruneTreeNode } from "../../services/questionHierarchy"; +import { SearchInputWithIcon } from "../elements/SearchInputs"; // Type is used to ensure that we check all query params if a new one is added in the future const FILTER_PARAMS = ["query", "topics", "fields", "subjects", "stages", "difficulties", "examBoards", "book", "excludeBooks", "statuses", "randomSeed"] as const; @@ -489,19 +490,15 @@ export const QuestionFinder = withRouter(({location}: RouteComponentProps) => { {isAda && - - { - debouncedSearchHandler(e.target.value); - setRandomSeed(undefined); // This random seed reset is for Ada only! This is managed in the filtersChanged useEffect for Phy - }} - /> -