diff --git a/src/pages/research/index.tsx b/src/pages/research/index.tsx index 77782978..07b71aa6 100644 --- a/src/pages/research/index.tsx +++ b/src/pages/research/index.tsx @@ -12,26 +12,88 @@ export interface ResearchCardProps { referenceHref: string; } +interface ResearchSearchContextValue { + category: string; + query: string; +} + +const ResearchSearchContext = React.createContext({ + category: "", + query: "", +}); + +const normalizeSearchText = (value: string) => value.trim().toLocaleLowerCase(); + +const paperMatchesSearch = ( + title: string, + reference: string, + category: string, + query: string, +) => + normalizeSearchText(`${title} ${reference} ${category}`).includes( + normalizeSearchText(query), + ); + export const ResearchCard: React.FC = ({ title, referenceHref, reference, -}) => ( - -); +}) => { + const { category, query } = React.useContext(ResearchSearchContext); + + if (!paperMatchesSearch(title, reference, category, query)) { + return null; + } + + return ( + + ); +}; + +const categoryMatchesSearch = ( + contents: React.ReactElement<{ children?: React.ReactNode }>, + category: string, + query: string, +) => { + if ( + !query || + normalizeSearchText(category).includes(normalizeSearchText(query)) + ) { + return true; + } + + return React.Children.toArray(contents.props.children).some( + (child) => + React.isValidElement(child) && + paperMatchesSearch( + child.props.title, + child.props.reference, + category, + query, + ), + ); +}; const Papers = [ { title: "Computer-based assessments with randomization and instant feedback", contents: ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), }, @@ -315,6 +545,12 @@ const Papers = [ title: "Computer-based collaborative learning", contents: ( + + + + + + + + + + + + + + + + + + + + + + + + + ), + }, + { + title: "Applications in engineering, mathematics, and data science", + contents: ( + + + + + + + + + + + + + + ), + }, + { + title: "Applications in Discrete Math and Algorithms courses", contents: ( - - + + + + + + + + ({ + ...paper, + originalIndex: index, + })).filter((paper) => + categoryMatchesSearch(paper.contents, paper.title, normalizedQuery), + ); + return ( - Case Studies | PrairieLearn + Research | PrairieLearn
- - {Papers.map((faq, i) => ( - - - {faq.title} - - {faq.contents} - - ))} - + + setQuery(event.target.value)} + placeholder="Search by topic, author, or venue" + type="search" + value={query} + /> + + {visiblePapers.length > 0 ? ( + paper.originalIndex.toString()) + : undefined + } + key={normalizedQuery || "all-publications"} + > + {visiblePapers.map((paper) => { + const eventKey = paper.originalIndex.toString(); + + return ( + + + {paper.title} + + + + {paper.contents} + + + + ); + })} + + ) : ( +

No publications match your search.

+ )}