Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat #215: PageFind search implementation #239

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions build_search_index.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
partials="partials"

for dir in content/*
do
mydir="$(basename $dir)"
if [ "$mydir" != "$partials" ]
then
{ # try
npx pagefind --site .next/server/pages/en/"$mydir" --output-path .next/static/chunks/pages/pageFind"$mydir";
} || { # catch
echo "Search index creation for version $mydir FAILED!"
}
fi
done
2 changes: 1 addition & 1 deletion components/Breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function Breadcrumb({ slug }: { slug: string[] }) {
});

return slug ? (
<div className={styles.Container}>
<div className={styles.Container} id="breadcrumb-container">
{breadcrumb.map((crumb, idx) => {
const hrefString = enableVersion
? `/${docVersion}/${crumb.path}`
Expand Down
1 change: 1 addition & 0 deletions components/CategoriesNav/CategoriesNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default function CategoriesNav({ menu }: Props) {
styles.Container,
navBarCollapsed ? styles.CollapsedNav : ""
)}
id="categories-nav-container"
>
<div className={styles.CategoriesContainer}>
{menu.map((item) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export interface ConnectorDetailsHeaderProps {
platform: string;
availableFeatures: Array<string>;
unavailableFeatures: Array<string>;
searchWeight: string;
}
13 changes: 12 additions & 1 deletion components/ConnectorDetailsHeader/ConnectorDetailsHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,29 @@ function ConnectorDetailsHeader({
platform,
availableFeatures,
unavailableFeatures,
searchWeight,
}: Readonly<ConnectorDetailsHeaderProps>) {
const showSubHeading = useMemo(
() => !isEmpty(availableFeatures) || !isEmpty(unavailableFeatures),
[availableFeatures, unavailableFeatures]
);

let otherProps = {};

if (searchWeight) {
otherProps = {
["data-pagefind-weight"]: searchWeight,
};
}

return (
<div className={styles.Container}>
<div className={styles.Heading}>
<div className="flex items-center gap-3">
<div className={styles.ImageContainer}>{getConnectorImage(name)}</div>
<div className={styles.ConnectorName}>{name}</div>
<div className={styles.ConnectorName} {...otherProps}>
{name}
</div>
{getStageBadge(stage)}
</div>
<div className={styles.PlatformDetails}>
Expand Down
8 changes: 5 additions & 3 deletions components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import classNames from "classnames";
import Link from "next/link";
import React from "react";
import styles from "./Footer.module.css";
import {
footerIconItemsData,
footerItemsData,
} from "../../constants/footer.constants";
import styles from "./Footer.module.css";

export default function Footer() {
return (
<footer className={classNames(styles.Container, "footer")}>
<footer
className={classNames(styles.Container, "footer")}
id="footer-container"
>
<hr className={styles.Separator} />
<section className={styles.InnerContainer}>
<nav className={styles.Navigation}>
Expand Down
9 changes: 9 additions & 0 deletions components/Heading/Heading.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ReactNode } from "react";

export interface HeadingProps {
children: ReactNode;
id?: string;
level?: number;
className?: string;
searchWeight?: string;
}
5 changes: 5 additions & 0 deletions components/Heading/Heading.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
margin-top: 32px;
}

.H1Element{
border-bottom: 1px solid var(--default-border-color);
padding-bottom: 16px;
}

.CopiedText {
margin-left: 16px;
font-size: 12px;
Expand Down
18 changes: 17 additions & 1 deletion components/Heading/Heading.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import classNames from "classnames";
import { useState } from "react";
import { HeadingProps } from "./Heading.interface";
import styles from "./Heading.module.css";
import HeadingElement from "./HeadingElement";

export function Heading({ id = "", level = 1, children, className }) {
export function Heading({
id = "",
level = 1,
children,
className = "",
searchWeight,
}: Readonly<HeadingProps>) {
const [copied, setCopied] = useState(false);

const copyLinkUnbound = async () => {
Expand All @@ -14,10 +21,19 @@ export function Heading({ id = "", level = 1, children, className }) {
window.setTimeout(() => setCopied(false), 2000);
};

let otherProps = {};

if (searchWeight) {
otherProps = {
["data-pagefind-weight"]: searchWeight,
};
}

return (
<HeadingElement
className={classNames(className, styles.HeaderLink)}
level={level}
{...otherProps}
>
<a id={id} className="hash-link" />
<span>{children}</span>
Expand Down
53 changes: 42 additions & 11 deletions components/Heading/HeadingElement.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,57 @@
import React from "react";

interface Props {
level: number;
className: string;
className?: string;
children: any;
}

export default function HeadingElement({ level, className, children }: Props) {
export default function HeadingElement({
level,
className = "",
children,
...otherProps
}: Readonly<Props>) {
switch (level) {
case 1:
return <h1 className={className}>{children}</h1>;
return (
<h1 className={className} {...otherProps}>
{children}
</h1>
);
case 2:
return <h2 className={className}>{children}</h2>;
return (
<h2 className={className} {...otherProps}>
{children}
</h2>
);
case 3:
return <h3 className={className}>{children}</h3>;
return (
<h3 className={className} {...otherProps}>
{children}
</h3>
);
case 4:
return <h4 className={className}>{children}</h4>;
return (
<h4 className={className} {...otherProps}>
{children}
</h4>
);
case 5:
return <h5 className={className}>{children}</h5>;
return (
<h5 className={className} {...otherProps}>
{children}
</h5>
);
case 6:
return <h6 className={className}>{children}</h6>;
return (
<h6 className={className} {...otherProps}>
{children}
</h6>
);
default:
return <h6 className={className}>{children}</h6>;
return (
<h6 className={className} {...otherProps}>
{children}
</h6>
);
}
}
22 changes: 6 additions & 16 deletions components/Search/CustomSearch/CustomSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
import { debounce } from "lodash";
import { useCallback, useEffect, useRef } from "react";
import { useSearchBox } from "react-instantsearch";
import { useDocVersionContext } from "../../../context/DocVersionContext";
import { useSearchContext } from "../../../context/SearchContext";
import { isCommandKeyPress } from "../../../utils/SearchUtils";
import styles from "./CustomSearch.module.css";

interface CustomSearchProps {
searchValue: string;
searchText: string;
bringElementIntoView: (
searchResults: NodeListOf<Element>,
focusedSearchItemNumber: number
) => void;
handleSearchValue: (value: string) => void;
handleSearchText: (value: string) => void;
handleIsSuggestionVisible: (value: boolean) => void;
}

function CustomSearch({
bringElementIntoView,
searchValue,
searchText,
handleSearchValue,
handleIsSuggestionVisible,
handleSearchText,
}: CustomSearchProps) {
const { refine } = useSearchBox();
}: Readonly<CustomSearchProps>) {
const { docVersion } = useDocVersionContext();
const searchInputRef = useRef<HTMLInputElement>();
const { onChangeFocusedSearchItem } = useSearchContext();

const handleSearchValueChange = useCallback(
(searchText: string) => {
handleSearchValue(searchText);
onChangeFocusedSearchItem(1);
onChangeFocusedSearchItem(0);

setTimeout(() => {
const searchResults = document.getElementById("search-modal");
Expand Down Expand Up @@ -87,10 +80,11 @@ function CustomSearch({
const handleInputChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.target;
window[`pageFind${docVersion}`].preload(value);
debouncedSearch(value);
handleSearchText(value);
},
[debouncedSearch, handleSearchText]
[debouncedSearch, handleSearchText, docVersion]
);

useEffect(() => {
Expand All @@ -101,10 +95,6 @@ function CustomSearch({
document.body.addEventListener("click", handleOutsideClick);
}, []);

useEffect(() => {
refine(searchValue);
}, [searchValue]);

return (
<input
className={styles.Input}
Expand Down
14 changes: 14 additions & 0 deletions components/Search/ResultItem/ResultItem.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface ResultData {
id: string;
url: string;
raw_url: string;
excerpt: string;
meta: {
title: string;
};
}

export interface ResultsProps {
id: number;
result: ResultData;
}
26 changes: 26 additions & 0 deletions components/Search/ResultItem/ResultItem.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.Container{
display: flex;
flex-direction: column;
gap: 8px;
font-size: 14px;
color: var(--default-text-color);
padding: 8px;
border-radius: 4px;
font-weight: 400;
text-align: left;
width: 100%
}

.Container mark{
background-color: white;
font-weight: 600;
}

.ActiveContainer, .ActiveContainer mark{
background-color: var(--primary-color);
color: white
}

.ResultTitle{
font-weight: 700;
}
43 changes: 43 additions & 0 deletions components/Search/ResultItem/ResultItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import classNames from "classnames";
import Link from "next/link";
import { useRef } from "react";
import { useSearchContext } from "../../../context/SearchContext";
import { ResultsProps } from "./ResultItem.interface";
import styles from "./ResultItem.module.css";

export default function Results({ result, id }: Readonly<ResultsProps>) {
const { focusedSearchItem, onChangeFocusedSearchItem } = useSearchContext();
const resultItemRef = useRef<HTMLButtonElement>(null);

const handleHover = () => {
const searchItems = document.querySelectorAll(`[class^="search-result-"]`);

searchItems.forEach((item) => {
item.classList.remove(styles.ActiveContainer);
});

resultItemRef.current.classList.add(styles.ActiveContainer);

const elementSerialNumber = resultItemRef.current.id.split("-")[2];
onChangeFocusedSearchItem(Number(elementSerialNumber));
};

return (
<Link href={result.raw_url ?? result.url}>
<button
className={classNames(
`search-result-${id}`,
styles.Container,
id === focusedSearchItem ? styles.ActiveContainer : ""
)}
id={`search-result-${id}`}
key={result.id}
ref={resultItemRef}
onMouseEnter={handleHover}
>
<span className={styles.ResultTitle}>{result.meta.title}</span>
<span dangerouslySetInnerHTML={{ __html: result.excerpt }}></span>
</button>
</Link>
);
}
Loading