Skip to content

Commit

Permalink
fix: address search bar issue in the navbar
Browse files Browse the repository at this point in the history
  • Loading branch information
allenhack638 committed Dec 3, 2024
1 parent ef509bd commit 77fae5d
Showing 1 changed file with 98 additions and 31 deletions.
129 changes: 98 additions & 31 deletions components/AlgoliaSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
/* eslint-disable no-underscore-dangle */
import { DocSearchModal } from '@docsearch/react';
import type { DocSearchHit, InternalDocSearchHit, StoredDocSearchHit } from '@docsearch/react/dist/esm/types';
import type {
DocSearchHit,
InternalDocSearchHit,
StoredDocSearchHit,
} from '@docsearch/react/dist/esm/types';
import clsx from 'clsx';
import Head from 'next/head';
import Link from 'next/link';
import { useRouter } from 'next/router';
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
import React, {
createContext,
useCallback,
useContext,
useEffect,
useRef,
useState,
} from 'react';
import { createPortal } from 'react-dom';

export const INDEX_NAME = 'asyncapi';
Expand Down Expand Up @@ -46,8 +57,17 @@ interface IUseDocSearchKeyboardEvents {
onInput?: (e: React.KeyboardEvent) => void;
}

type ISearchButtonProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> & {
children?: React.ReactNode | (({ actionKey }: { actionKey: { shortKey: string; key: string } }) => React.ReactNode);
type ISearchButtonProps = Omit<
React.ButtonHTMLAttributes<HTMLButtonElement>,
'children'
> & {
children?:
| React.ReactNode
| (({
actionKey,
}: {
actionKey: { shortKey: string; key: string };
}) => React.ReactNode);
indexName?: string;
};

Expand All @@ -64,7 +84,8 @@ function transformItems(items: DocSearchHit[]) {

a.href = item.url;

const hash = a.hash === '#content-wrapper' || a.hash === '#header' ? '' : a.hash;
const hash =
a.hash === '#content-wrapper' || a.hash === '#header' ? '' : a.hash;

if (item.hierarchy?.lvl0) {
// eslint-disable-next-line no-param-reassign
Expand All @@ -75,10 +96,15 @@ function transformItems(items: DocSearchHit[]) {
...item,
url: `${a.pathname}${hash}`,
__is_result: () => true,
__is_parent: () => item.type === 'lvl1' && items.length > 1 && index === 0,
__is_child: () => item.type !== 'lvl1' && items.length > 1 && items[0].type === 'lvl1' && index !== 0,
__is_parent: () =>
item.type === 'lvl1' && items.length > 1 && index === 0,
__is_child: () =>
item.type !== 'lvl1' &&
items.length > 1 &&
items[0].type === 'lvl1' &&
index !== 0,
__is_first: () => index === 1,
__is_last: () => index === items.length - 1 && index !== 0
__is_last: () => index === items.length - 1 && index !== 0,
};
});
}
Expand All @@ -97,7 +123,7 @@ function Hit({ hit, children }: IHitProps) {
'DocSearch-Hit--Parent': hit.__is_parent?.(),
'DocSearch-Hit--FirstChild': hit.__is_first?.(),
'DocSearch-Hit--LastChild': hit.__is_last?.(),
'DocSearch-Hit--Child': hit.__is_child?.()
'DocSearch-Hit--Child': hit.__is_child?.(),
})}
>
{children}
Expand All @@ -118,9 +144,13 @@ function AlgoliaModal({ onClose, initialQuery, indexName }: AlgoliaModalProps) {
initialQuery={initialQuery}
initialScrollY={window.scrollY}
searchParameters={{
distinct: 1
distinct: 1,
}}
placeholder={indexName === DOCS_INDEX_NAME ? 'Search documentation' : 'Search resources'}
placeholder={
indexName === DOCS_INDEX_NAME
? 'Search documentation'
: 'Search resources'
}
onClose={onClose}
indexName={indexName}
apiKey={API_KEY}
Expand All @@ -129,15 +159,15 @@ function AlgoliaModal({ onClose, initialQuery, indexName }: AlgoliaModalProps) {
navigate({ itemUrl }) {
onClose();
router.push(itemUrl);
}
},
}}
hitComponent={Hit}
transformItems={transformItems}
getMissingResultsUrl={({ query }) => {
return `https://github.com/asyncapi/website/issues/new?title=Cannot%20search%20given%20query:%20${query}`;
}}
/>,
document.body
document.body,
);
}

Expand All @@ -151,7 +181,10 @@ function isEditingContent(event: KeyboardEvent) {
const { tagName } = element as HTMLElement;

return (
(element as HTMLElement).isContentEditable || tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA'
(element as HTMLElement).isContentEditable ||
tagName === 'INPUT' ||
tagName === 'SELECT' ||
tagName === 'TEXTAREA'
);
}

Expand All @@ -161,22 +194,24 @@ function isEditingContent(event: KeyboardEvent) {
*/
function getActionKey() {
if (typeof navigator !== 'undefined') {
if (/(Mac|iPhone|iPod|iPad)/i.test(navigator.userAgent || navigator.platform)) {
if (
/(Mac|iPhone|iPod|iPad)/i.test(navigator.userAgent || navigator.platform)
) {
return {
shortKey: '⌘',
key: 'Command'
key: 'Command',
};
}

return {
shortKey: 'Ctrl',
key: 'Control'
key: 'Control',
};
}

return {
shortKey: 'Ctrl',
key: 'Control'
key: 'Control',
};
}

Expand All @@ -185,7 +220,11 @@ function getActionKey() {
* @description The hook used for the Algolia search keyboard events
* @param {IUseDocSearchKeyboardEvents} props - The props of the useDocSearchKeyboardEvents hook
*/
function useDocSearchKeyboardEvents({ isOpen, onOpen, onClose }: IUseDocSearchKeyboardEvents) {
function useDocSearchKeyboardEvents({
isOpen,
onOpen,
onClose,
}: IUseDocSearchKeyboardEvents) {
useEffect(() => {
/**
* @description The function used to handle the keyboard event.
Expand All @@ -211,7 +250,9 @@ function useDocSearchKeyboardEvents({ isOpen, onOpen, onClose }: IUseDocSearchKe
if (typeof document !== 'undefined') {
const loc = document.location;

indexName = loc.pathname.startsWith('/docs') ? DOCS_INDEX_NAME : INDEX_NAME;
indexName = loc.pathname.startsWith('/docs')
? DOCS_INDEX_NAME
: INDEX_NAME;
}
onOpen(indexName);
}
Expand All @@ -231,7 +272,11 @@ function useDocSearchKeyboardEvents({ isOpen, onOpen, onClose }: IUseDocSearchKe
* @description The Algolia search component used for searching the website
* @param {React.ReactNode} children - The content of the page
*/
export default function AlgoliaSearch({ children }: { children: React.ReactNode }) {
export default function AlgoliaSearch({
children,
}: {
children: React.ReactNode;
}) {
const [isOpen, setIsOpen] = useState(false);
const [indexName, setIndexName] = useState<string>(INDEX_NAME);
const [initialQuery, setInitialQuery] = useState<string>();
Expand All @@ -243,7 +288,7 @@ export default function AlgoliaSearch({ children }: { children: React.ReactNode
}
setIsOpen(true);
},
[setIsOpen, setIndexName]
[setIsOpen, setIndexName],
);

const onClose = useCallback(() => {
Expand All @@ -255,23 +300,35 @@ export default function AlgoliaSearch({ children }: { children: React.ReactNode
setIsOpen(true);
setInitialQuery(e.key);
},
[setIsOpen, setInitialQuery]
[setIsOpen, setInitialQuery],
);

useDocSearchKeyboardEvents({
isOpen,
onOpen,
onClose,
onInput
onInput,
});

return (
<>
<Head>
<link rel='preconnect' href={`https://${APP_ID}-dsn.algolia.net`} crossOrigin='anonymous' />
<link
rel="preconnect"
href={`https://${APP_ID}-dsn.algolia.net`}
crossOrigin="anonymous"
/>
</Head>
<SearchContext.Provider value={{ isOpen, onOpen, onClose, onInput }}>{children}</SearchContext.Provider>
{isOpen && <AlgoliaModal initialQuery={initialQuery ?? ''} onClose={onClose} indexName={indexName} />}
<SearchContext.Provider value={{ isOpen, onOpen, onClose, onInput }}>
{children}
</SearchContext.Provider>
{isOpen && (
<AlgoliaModal
initialQuery={initialQuery ?? ''}
onClose={onClose}
indexName={indexName}
/>
)}
</>
);
}
Expand All @@ -281,7 +338,11 @@ export default function AlgoliaSearch({ children }: { children: React.ReactNode
* @description The search button component used for opening the Algolia search
* @param {ISearchButtonProps} props - The props of the search button
*/
export function SearchButton({ children, indexName = INDEX_NAME, ...props }: ISearchButtonProps) {
export function SearchButton({
children,
indexName = INDEX_NAME,
...props
}: ISearchButtonProps) {
const { onOpen, onInput } = useContext(SearchContext);
const [Children, setChildren] = useState<string | React.ReactNode>('');
const searchButtonRef = useRef<HTMLButtonElement>(null);
Expand All @@ -295,7 +356,11 @@ export function SearchButton({ children, indexName = INDEX_NAME, ...props }: ISe
* @returns {void}
*/
function onKeyDown(event: KeyboardEvent) {
if (searchButtonRef && searchButtonRef.current === document.activeElement && onInput) {
if (
searchButtonRef &&
searchButtonRef.current === document.activeElement &&
onInput
) {
if (/[a-zA-Z0-9]/.test(event.key)) {
onInput(event as unknown as React.KeyboardEvent);
}
Expand All @@ -312,18 +377,20 @@ export function SearchButton({ children, indexName = INDEX_NAME, ...props }: ISe
useEffect(() => {
if (typeof children === 'function') {
setChildren(children({ actionKey }));
} else {
setChildren(children);
}
}, []);

return (
<button
type='button'
type="button"
ref={searchButtonRef}
onClick={() => {
onOpen(indexName);
}}
{...props}
data-testid='Search-Button'
data-testid="Search-Button"
>
{Children}
</button>
Expand Down

0 comments on commit 77fae5d

Please sign in to comment.