mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-05 12:22:45 +02:00
feat(v2): add search page (#2756)
This commit is contained in:
parent
1fe2dc192e
commit
3ad4550854
12 changed files with 688 additions and 38 deletions
|
@ -6,8 +6,20 @@
|
|||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const eta = require('eta');
|
||||
const {normalizeUrl} = require('@docusaurus/utils');
|
||||
const openSearchTemplate = require('./templates/opensearch');
|
||||
|
||||
const OPEN_SEARCH_FILENAME = 'opensearch.xml';
|
||||
|
||||
module.exports = function (context) {
|
||||
const {
|
||||
baseUrl,
|
||||
siteConfig: {title, url, favicon},
|
||||
} = context;
|
||||
const pagePath = path.resolve(__dirname, './pages/search/index.js');
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
name: 'docusaurus-theme-search-algolia',
|
||||
|
||||
|
@ -15,6 +27,10 @@ module.exports = function () {
|
|||
return path.resolve(__dirname, './theme');
|
||||
},
|
||||
|
||||
getPathsToWatch() {
|
||||
return [pagePath];
|
||||
},
|
||||
|
||||
configureWebpack() {
|
||||
// Ensure that algolia docsearch styles is its own chunk.
|
||||
return {
|
||||
|
@ -34,5 +50,44 @@ module.exports = function () {
|
|||
},
|
||||
};
|
||||
},
|
||||
|
||||
async contentLoaded({actions: {addRoute}}) {
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, 'search']),
|
||||
component: pagePath,
|
||||
exact: true,
|
||||
});
|
||||
},
|
||||
|
||||
async postBuild({outDir}) {
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
path.join(outDir, OPEN_SEARCH_FILENAME),
|
||||
eta.render(openSearchTemplate.trim(), {
|
||||
title,
|
||||
url,
|
||||
favicon: normalizeUrl([url, favicon]),
|
||||
}),
|
||||
);
|
||||
} catch (err) {
|
||||
throw new Error(`Generating OpenSearch file failed: ${err}`);
|
||||
}
|
||||
},
|
||||
|
||||
injectHtmlTags() {
|
||||
return {
|
||||
headTags: [
|
||||
{
|
||||
tagName: 'link',
|
||||
attributes: {
|
||||
rel: 'search',
|
||||
type: 'application/opensearchdescription+xml',
|
||||
title,
|
||||
href: normalizeUrl([baseUrl, OPEN_SEARCH_FILENAME]),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.searchQueryInput,
|
||||
.searchVersionInput {
|
||||
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;
|
||||
}
|
||||
|
||||
.searchResultsColumn {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.searchLogoColumn {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.algoliaLogo {
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.algoliaLogoPathFill {
|
||||
fill: var(--ifm-font-color-base);
|
||||
}
|
||||
|
||||
.searchResultItem {
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #dfe3e8;
|
||||
}
|
||||
|
||||
.searchResultItemHeading {
|
||||
font-size: var(--ifm-h2-font-size);
|
||||
}
|
||||
|
||||
.searchResultItemPath {
|
||||
font-size: 0.8rem;
|
||||
color: var(--ifm-color-content-secondary);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.searchResultItemSummary {
|
||||
margin: 0.5rem 0 0 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 996px) {
|
||||
.searchQueryColumn {
|
||||
max-width: 60% !important;
|
||||
}
|
||||
|
||||
.searchVersionColumn {
|
||||
max-width: 40% !important;
|
||||
}
|
||||
|
||||
.algoliaLogo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.searchResultsColumn {
|
||||
max-width: 60% !important;
|
||||
}
|
||||
|
||||
.searchLogoColumn {
|
||||
overflow: hidden;
|
||||
max-width: 40% !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.loadingSpinner {
|
||||
pointer-events: none;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border: 0.4em solid transparent;
|
||||
border-color: #eee;
|
||||
border-top-color: var(--ifm-color-primary);
|
||||
border-radius: 50%;
|
||||
animation: loadingspin 1s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@keyframes loadingspin {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
:global(.search-result-match) {
|
||||
background: rgba(255, 215, 142, 0.22);
|
||||
padding: 0.09em 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
module.exports = `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName><%= it.title %></ShortName>
|
||||
<Description>Search <%= it.title %></Description>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Image width="16" height="16" type="image/x-icon"><%= it.favicon %></Image>
|
||||
<Url type="text/html" method="get" template="<%= it.url %>/search?q={searchTerms}"/>
|
||||
<Url type="application/opensearchdescription+xml" rel="self" template="<%= it.url %>/opensearch.xml" />
|
||||
<moz:SearchForm><%= it.url %></moz:SearchForm>
|
||||
</OpenSearchDescription>
|
||||
`;
|
|
@ -10,6 +10,7 @@ import classnames from 'classnames';
|
|||
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import {useHistory} from '@docusaurus/router';
|
||||
import useSearchQuery from '@theme/hooks/useSearchQuery';
|
||||
|
||||
import './styles.css';
|
||||
|
||||
|
@ -21,6 +22,7 @@ const Search = (props) => {
|
|||
themeConfig: {algolia},
|
||||
} = siteConfig;
|
||||
const history = useHistory();
|
||||
const {navigateToSearchPage} = useSearchQuery();
|
||||
|
||||
function initAlgolia(focus) {
|
||||
window.docsearch({
|
||||
|
@ -29,6 +31,9 @@ const Search = (props) => {
|
|||
indexName: algolia.indexName,
|
||||
inputSelector: '#search_input_react',
|
||||
algoliaOptions: algolia.algoliaOptions,
|
||||
autocompleteOptions: {
|
||||
autoselect: false,
|
||||
},
|
||||
// Override algolia's default selection event, allowing us to do client-side
|
||||
// navigation and avoiding a full page refresh.
|
||||
handleSelected: (_input, _event, suggestion) => {
|
||||
|
@ -87,6 +92,12 @@ const Search = (props) => {
|
|||
loadAlgolia(needFocus);
|
||||
});
|
||||
|
||||
const handleSearchInputPressEnter = useCallback((e) => {
|
||||
if (e.key === 'Enter') {
|
||||
navigateToSearchPage(e.target.value);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="navbar__search" key="search-box">
|
||||
<span
|
||||
|
@ -112,6 +123,7 @@ const Search = (props) => {
|
|||
onMouseOver={handleSearchInput}
|
||||
onFocus={handleSearchInput}
|
||||
onBlur={handleSearchInputBlur}
|
||||
onKeyDown={handleSearchInputPressEnter}
|
||||
ref={searchBarRef}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {useHistory, useLocation} from '@docusaurus/router';
|
||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||
|
||||
const SEARCH_PARAM_QUERY = 'q';
|
||||
|
||||
function useSearchQuery() {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
return {
|
||||
searchValue:
|
||||
(ExecutionEnvironment.canUseDOM &&
|
||||
new URLSearchParams(location.search).get(SEARCH_PARAM_QUERY)) ||
|
||||
'',
|
||||
updateSearchPath: (searchValue) => {
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
|
||||
if (searchValue) {
|
||||
searchParams.set(SEARCH_PARAM_QUERY, searchValue);
|
||||
} else {
|
||||
searchParams.delete(SEARCH_PARAM_QUERY);
|
||||
}
|
||||
|
||||
history.replace({
|
||||
search: searchParams.toString(),
|
||||
});
|
||||
},
|
||||
navigateToSearchPage: (searchValue) => {
|
||||
history.push(`/search?q=${searchValue}`);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default useSearchQuery;
|
Loading…
Add table
Add a link
Reference in a new issue