-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: search page to view all results
- Loading branch information
1 parent
506b5c3
commit 0495e71
Showing
21 changed files
with
626 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
.searchQueryInput { | ||
border-radius: var(--ifm-global-radius); | ||
border: var(--ifm-global-border-width) solid | ||
var(--ifm-color-content-secondary); | ||
font-size: var(--ifm-font-size-base); | ||
padding: 0.5rem; | ||
width: 100%; | ||
background: #fff; | ||
margin-bottom: 1rem; | ||
} | ||
|
||
.searchResultItem { | ||
padding: 1rem 0px; | ||
border-bottom: 1px solid rgb(223, 227, 232); | ||
} | ||
|
||
.searchResultItem > h2 { | ||
margin-bottom: 0; | ||
} | ||
|
||
.searchResultItemPath { | ||
color: var(--ifm-color-content-secondary); | ||
font-size: 0.8rem; | ||
margin: 0.5rem 0px 0px; | ||
} | ||
|
||
.searchResultItemSummary { | ||
font-style: italic; | ||
margin: 0.5rem 0px 0px; | ||
} | ||
|
||
/* Start: pure CSS loaders */ | ||
/* https://loading.io/css/ */ | ||
.ldsRing { | ||
display: inline-block; | ||
position: absolute; | ||
width: 20px; | ||
height: 20px; | ||
opacity: var(--search-local-loading-icon-opacity, 0.5); | ||
} | ||
|
||
.ldsRing div { | ||
box-sizing: border-box; | ||
display: block; | ||
position: absolute; | ||
width: 16px; | ||
height: 16px; | ||
margin: 2px; | ||
border: 2px solid | ||
var(--search-load-loading-icon-color, var(--ifm-navbar-search-input-color)); | ||
border-radius: 50%; | ||
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; | ||
border-color: var( | ||
--search-load-loading-icon-color, | ||
var(--ifm-navbar-search-input-color) | ||
) | ||
transparent transparent transparent; | ||
} | ||
|
||
.ldsRing div:nth-child(1) { | ||
animation-delay: -0.45s; | ||
} | ||
|
||
.ldsRing div:nth-child(2) { | ||
animation-delay: -0.3s; | ||
} | ||
|
||
.ldsRing div:nth-child(3) { | ||
animation-delay: -0.15s; | ||
} | ||
|
||
@keyframes lds-ring { | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
/* End: pure CSS loaders */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import React, { useCallback, useEffect, useMemo, useState } from "react"; | ||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; | ||
import Layout from "@theme/Layout"; | ||
import Head from "@docusaurus/Head"; | ||
import Link from "@docusaurus/Link"; | ||
import useSearchQuery from "../hooks/useSearchQuery"; | ||
|
||
import styles from "./SearchPage.module.css"; | ||
import { fetchIndexes } from "../SearchBar/fetchIndexes"; | ||
import { SearchSourceFactory } from "../../utils/SearchSourceFactory"; | ||
import { SearchDocument, SearchResult } from "../../../shared/interfaces"; | ||
import { highlight } from "../../utils/highlight"; | ||
import { highlightStemmed } from "../../utils/highlightStemmed"; | ||
import { getStemmedPositions } from "../../utils/getStemmedPositions"; | ||
|
||
export default function SearchPage(): React.ReactElement { | ||
const { | ||
siteConfig: { baseUrl }, | ||
} = useDocusaurusContext(); | ||
const { searchValue, updateSearchPath } = useSearchQuery(); | ||
const [searchQuery, setSearchQuery] = useState(searchValue); | ||
const [searchSource, setSearchSource] = useState< | ||
(input: string, callback: (results: SearchResult[]) => void) => void | ||
>(); | ||
const [searchResults, setSearchResults] = useState<SearchResult[]>(); | ||
|
||
const pageTitle = useMemo( | ||
() => | ||
searchQuery | ||
? `Search results for "${searchQuery}"` | ||
: "Search the documentation", | ||
[searchQuery] | ||
); | ||
|
||
useEffect(() => { | ||
updateSearchPath(searchQuery); | ||
|
||
if (searchSource) { | ||
if (searchQuery) { | ||
searchSource(searchQuery, (results) => { | ||
setSearchResults(results); | ||
}); | ||
} else { | ||
setSearchResults(undefined); | ||
} | ||
} | ||
|
||
// `updateSearchPath` should not be in the deps, | ||
// otherwise will cause call stack overflow. | ||
}, [searchQuery, searchSource]); | ||
|
||
const handleSearchInputChange = useCallback((e) => { | ||
setSearchQuery(e.target.value); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (searchValue && searchValue !== searchQuery) { | ||
setSearchQuery(searchValue); | ||
} | ||
}, [searchValue]); | ||
|
||
useEffect(() => { | ||
async function doFetchIndexes() { | ||
const { wrappedIndexes, zhDictionary } = await fetchIndexes(baseUrl); | ||
setSearchSource(() => | ||
SearchSourceFactory(wrappedIndexes, zhDictionary, 100) | ||
); | ||
} | ||
doFetchIndexes(); | ||
}, [baseUrl]); | ||
|
||
return ( | ||
<Layout title={pageTitle}> | ||
<Head> | ||
{/* | ||
We should not index search pages | ||
See https://github.com/facebook/docusaurus/pull/3233 | ||
*/} | ||
<meta property="robots" content="noindex, follow" /> | ||
</Head> | ||
|
||
<div className="container margin-vert--lg"> | ||
<h1>{pageTitle}</h1> | ||
|
||
<form> | ||
<input | ||
type="search" | ||
name="q" | ||
className={styles.searchQueryInput} | ||
aria-label="Search" | ||
onChange={handleSearchInputChange} | ||
value={searchQuery} | ||
autoComplete="off" | ||
autoFocus | ||
/> | ||
</form> | ||
|
||
{!searchSource && searchQuery && ( | ||
<div> | ||
<div className={styles.ldsRing}> | ||
<div></div> | ||
<div></div> | ||
<div></div> | ||
<div></div> | ||
</div> | ||
</div> | ||
)} | ||
|
||
{searchResults && | ||
(searchResults.length > 0 ? ( | ||
<p> | ||
{searchResults.length} document | ||
{searchResults.length === 1 ? "" : "s"} found | ||
</p> | ||
) : ( | ||
<p>No documents were found</p> | ||
))} | ||
|
||
<section> | ||
{searchResults && | ||
searchResults.map((item) => ( | ||
<SearchResultItem key={item.document.i} searchResult={item} /> | ||
))} | ||
</section> | ||
</div> | ||
</Layout> | ||
); | ||
} | ||
|
||
function SearchResultItem({ | ||
searchResult: { document, type, page, tokens, metadata }, | ||
}: { | ||
searchResult: SearchResult; | ||
}): React.ReactElement { | ||
const isTitle = type === 0; | ||
const isContent = type === 2; | ||
const pathItems = ((isTitle | ||
? document.b | ||
: (page as SearchDocument).b) as string[]).slice(); | ||
const articleTitle = (isContent ? document.s : document.t) as string; | ||
if (!isTitle) { | ||
pathItems.push((page as SearchDocument).t); | ||
} | ||
return ( | ||
<article className={styles.searchResultItem}> | ||
<h2> | ||
<Link | ||
to={document.u} | ||
dangerouslySetInnerHTML={{ | ||
__html: isContent | ||
? highlight(articleTitle, tokens) | ||
: highlightStemmed( | ||
articleTitle, | ||
getStemmedPositions(metadata, "t"), | ||
tokens, | ||
100 | ||
), | ||
}} | ||
></Link> | ||
</h2> | ||
{pathItems.length > 0 && ( | ||
<p className={styles.searchResultItemPath}>{pathItems.join(" › ")}</p> | ||
)} | ||
{isContent && ( | ||
<p | ||
className={styles.searchResultItemSummary} | ||
dangerouslySetInnerHTML={{ | ||
__html: highlightStemmed( | ||
document.t, | ||
getStemmedPositions(metadata, "t"), | ||
tokens, | ||
100 | ||
), | ||
}} | ||
/> | ||
)} | ||
</article> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import SearchPage from "./SearchPage"; | ||
|
||
export default SearchPage; |
Oops, something went wrong.