Skip to content

Commit

Permalink
feat: support search based on description and keywords
Browse files Browse the repository at this point in the history
closes #344
  • Loading branch information
weareoutman committed May 23, 2024
1 parent 8553b40 commit 0c12b59
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SearchDocumentType } from "../../../shared/interfaces";
import { SuggestionTemplate } from "./SuggestionTemplate";

jest.mock("./icons");
Expand All @@ -12,7 +13,7 @@ describe("SuggestionTemplate", () => {
t: "Hello world",
u: "/docs/a",
},
type: 0,
type: SearchDocumentType.Title,
page: false,
metadata: {
hello: {
Expand Down Expand Up @@ -65,7 +66,7 @@ describe("SuggestionTemplate", () => {
t: "Hello fruits.",
u: "/docs/b",
},
type: 1,
type: SearchDocumentType.Heading,
page: {
i: 1,
t: "Hello world",
Expand Down Expand Up @@ -134,7 +135,7 @@ describe("SuggestionTemplate", () => {
t: "Goodbye fruits.",
u: "/docs/c",
},
type: 2,
type: SearchDocumentType.Content,
page: {
i: 1,
t: "Hello world",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { SearchDocument, SearchResult } from "../../../shared/interfaces";
import {
SearchDocument,
SearchDocumentType,
SearchResult,
} from "../../../shared/interfaces";
import { concatDocumentPath } from "../../utils/concatDocumentPath";
import { getStemmedPositions } from "../../utils/getStemmedPositions";
import { highlight } from "../../utils/highlight";
Expand All @@ -23,8 +27,10 @@ export function SuggestionTemplate({
isInterOfTree,
isLastOfTree,
}: Omit<SearchResult, "score" | "index">): string {
const isTitle = type === 0;
const isHeading = type === 1;
const isTitle = type === SearchDocumentType.Title;
const isKeywords = type === SearchDocumentType.Keywords;
const isTitleRelated = isTitle || isKeywords;
const isHeading = type === SearchDocumentType.Heading;
const tree: string[] = [];
if (isInterOfTree) {
tree.push(iconTreeInter);
Expand All @@ -35,30 +41,34 @@ export function SuggestionTemplate({
(item) => `<span class="${styles.hitTree}">${item}</span>`
);
const icon = `<span class="${styles.hitIcon}">${
isTitle ? iconTitle : isHeading ? iconHeading : iconContent
isTitleRelated ? iconTitle : isHeading ? iconHeading : iconContent
}</span>`;
const wrapped = [
`<span class="${styles.hitTitle}">${highlightStemmed(
document.t,
getStemmedPositions(metadata, "t"),
tokens
)}</span>`,
`<span class="${styles.hitTitle}">${
isKeywords
? highlight(document.s!, tokens)
: highlightStemmed(
document.t,
getStemmedPositions(metadata, "t"),
tokens
)
}</span>`,
];

const needsExplicitHitPath =
!isInterOfTree && !isLastOfTree && explicitSearchResultPath;
if (needsExplicitHitPath) {
const pathItems = page
? (page.b ?? [])
.concat(page.t)
? page.b
?.concat(page.t)
.concat(!document.s || document.s === page.t ? [] : document.s)
: document.b;
wrapped.push(
`<span class="${styles.hitPath}">${concatDocumentPath(
pathItems ?? []
)}</span>`
);
} else if (!isTitle) {
} else if (!isTitleRelated) {
wrapped.push(
`<span class="${styles.hitPath}">${highlight(
(page as SearchDocument).t ||
Expand Down
43 changes: 28 additions & 15 deletions docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import clsx from "clsx";
import useSearchQuery from "../hooks/useSearchQuery";
import { fetchIndexes } from "../SearchBar/fetchIndexes";
import { SearchSourceFactory } from "../../utils/SearchSourceFactory";
import { SearchDocument, SearchResult } from "../../../shared/interfaces";
import {
SearchDocument,
SearchDocumentType,
SearchResult,
} from "../../../shared/interfaces";
import { highlight } from "../../utils/highlight";
import { highlightStemmed } from "../../utils/highlightStemmed";
import { getStemmedPositions } from "../../utils/getStemmedPositions";
Expand Down Expand Up @@ -109,7 +113,9 @@ function SearchPageContent(): React.ReactElement {
useEffect(() => {
async function doFetchIndexes() {
const { wrappedIndexes, zhDictionary } =
!Array.isArray(searchContextByPaths) || searchContext || useAllContextsWithNoSearchContext
!Array.isArray(searchContextByPaths) ||
searchContext ||
useAllContextsWithNoSearchContext
? await fetchIndexes(versionUrl, searchContext)
: { wrappedIndexes: [], zhDictionary: [] };
setSearchSource(() =>
Expand Down Expand Up @@ -245,13 +251,19 @@ function SearchResultItem({
}: {
searchResult: SearchResult;
}): React.ReactElement {
const isTitle = type === 0;
const isContent = type === 2;
const isTitle = type === SearchDocumentType.Title;
const isKeywords = type === SearchDocumentType.Keywords;
const isDescription = type === SearchDocumentType.Description;
const isDescriptionOrKeywords = isDescription || isKeywords;
const isTitleRelated = isTitle || isDescriptionOrKeywords;
const isContent = type === SearchDocumentType.Content;
const pathItems = (
(isTitle ? document.b : (page as SearchDocument).b) as string[]
).slice();
const articleTitle = (isContent ? document.s : document.t) as string;
if (!isTitle) {
const articleTitle = (
isContent || isDescriptionOrKeywords ? document.s : document.t
) as string;
if (!isTitleRelated) {
pathItems.push((page as SearchDocument).t);
}
let search = "";
Expand All @@ -268,14 +280,15 @@ function SearchResultItem({
<Link
to={document.u + search + (document.h || "")}
dangerouslySetInnerHTML={{
__html: isContent
? highlight(articleTitle, tokens)
: highlightStemmed(
articleTitle,
getStemmedPositions(metadata, "t"),
tokens,
100
),
__html:
isContent || isDescriptionOrKeywords
? highlight(articleTitle, tokens)
: highlightStemmed(
articleTitle,
getStemmedPositions(metadata, "t"),
tokens,
100
),
}}
></Link>
</h2>
Expand All @@ -284,7 +297,7 @@ function SearchResultItem({
{concatDocumentPath(pathItems)}
</p>
)}
{isContent && (
{(isContent || isDescription) && (
<p
className={styles.searchResultItemSummary}
dangerouslySetInnerHTML={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import lunr from "lunr";
import { SearchDocument } from "../../shared/interfaces";
import { SearchDocument, SearchDocumentType } from "../../shared/interfaces";
import { SearchSourceFactory } from "./SearchSourceFactory";

// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down Expand Up @@ -32,6 +32,22 @@ describe("SearchSourceFactory", () => {
p: 1,
},
];
const documentsOfDescriptions: SearchDocument[] = [
{
i: 1,
t: "First description",
u: "/1",
p: 1,
},
];
const documentsOfKeywords: SearchDocument[] = [
{
i: 1,
t: "First keywords",
u: "/1",
p: 1,
},
];
const documentsOfContents: SearchDocument[] = [
{
i: 3,
Expand Down Expand Up @@ -60,17 +76,27 @@ describe("SearchSourceFactory", () => {
{
documents: documentsOfTitles,
index: getIndex(documentsOfTitles),
type: 0,
type: SearchDocumentType.Title,
},
{
documents: documentsOfHeadings,
index: getIndex(documentsOfHeadings),
type: 1,
type: SearchDocumentType.Heading,
},
{
documents: documentsOfDescriptions,
index: getIndex(documentsOfDescriptions),
type: SearchDocumentType.Description,
},
{
documents: documentsOfKeywords,
index: getIndex(documentsOfKeywords),
type: SearchDocumentType.Keywords,
},
{
documents: documentsOfContents,
index: getIndex(documentsOfContents),
type: 2,
type: SearchDocumentType.Content,
},
],
[],
Expand All @@ -82,6 +108,9 @@ describe("SearchSourceFactory", () => {
[",", []],
["nothing", []],
["peace", [4, 2]],
["description", [1]],
["keywords", [1]],
["first", [1, 2]],
])(
"SearchSourceFactory('%s', zhDictionary) should return %j",
(input, results) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
SearchResult,
SearchDocument,
InitialSearchResult,
SearchDocumentType,
} from "../../shared/interfaces";
import { sortSearchResults } from "./sortSearchResults";
import { processTreeStatusOfSearchResults } from "./processTreeStatusOfSearchResults";
Expand Down Expand Up @@ -58,7 +59,7 @@ export function SearchSourceFactory(
document,
type,
page:
type !== 0 &&
type !== SearchDocumentType.Title &&
wrappedIndexes[0].documents.find(
(doc) => doc.i === document.p
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { InitialSearchResult } from "../../shared/interfaces";
import {
InitialSearchResult,
SearchDocumentType,
} from "../../shared/interfaces";
import { processTreeStatusOfSearchResults } from "./processTreeStatusOfSearchResults";

describe("processTreeStatusOfSearchResults", () => {
Expand All @@ -8,14 +11,21 @@ describe("processTreeStatusOfSearchResults", () => {
document: {
i: 100,
},
type: 0,
type: SearchDocumentType.Title,
page: undefined,
},
{
document: {
i: 200,
},
type: 0,
type: SearchDocumentType.Title,
page: undefined,
},
{
document: {
i: 300,
},
type: SearchDocumentType.Title,
page: undefined,
},
] as InitialSearchResult[];
Expand All @@ -24,49 +34,63 @@ describe("processTreeStatusOfSearchResults", () => {
document: {
i: 1,
},
type: 2,
type: SearchDocumentType.Content,
page: {},
},
{
document: {
i: 2,
},
type: 1,
type: SearchDocumentType.Heading,
page: {},
},
pageTitles[0],
{
document: {
i: 101,
},
type: 2,
type: SearchDocumentType.Content,
page: pageTitles[0].document,
},
{
document: {
i: 3,
},
type: 1,
type: SearchDocumentType.Heading,
page: {},
},
pageTitles[1],
{
document: {
i: 201,
},
type: 1,
type: SearchDocumentType.Heading,
page: pageTitles[1].document,
},
{
document: {
i: 202,
},
type: 2,
type: SearchDocumentType.Content,
page: pageTitles[1].document,
},
{
document: {
i: 301,
},
type: SearchDocumentType.Keywords,
page: pageTitles[2].document,
},
{
document: {
i: 302,
},
type: SearchDocumentType.Description,
page: pageTitles[2].document,
},
] as InitialSearchResult[];
processTreeStatusOfSearchResults(results);
const statuses: [boolean, boolean][] = [
const statuses: [boolean | undefined, boolean | undefined][] = [
[undefined, undefined],
[undefined, undefined],
[undefined, undefined],
Expand All @@ -75,6 +99,8 @@ describe("processTreeStatusOfSearchResults", () => {
[undefined, undefined],
[true, undefined],
[undefined, true],
[undefined, undefined],
[undefined, true],
];
results.forEach((item, i) => {
expect([item.isInterOfTree, item.isLastOfTree]).toEqual(statuses[i]);
Expand Down
Loading

0 comments on commit 0c12b59

Please sign in to comment.