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

fix: address search bar issue in the navbar #3444

Closed
wants to merge 4 commits into from
Closed
Changes from 1 commit
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
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';
Comment on lines 1 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing IconLoupe import

The PR objective mentions fixing the visibility of IconLoupe component, but the import statement for this component is missing. This could be the root cause of the search icon not being visible.

Add the following import:

import { DocSearchModal } from '@docsearch/react';
+ import { IconLoupe } from '@/components/icons';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* 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';
/* eslint-disable no-underscore-dangle */
import { DocSearchModal } from '@docsearch/react';
import { IconLoupe } from '@/components/icons';
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';
🧰 Tools
🪛 eslint

[error] 3-7: Replace ⏎··DocSearchHit,⏎··InternalDocSearchHit,⏎··StoredDocSearchHit,⏎ with ·DocSearchHit,·InternalDocSearchHit,·StoredDocSearchHit·

(prettier/prettier)


[error] 6-6: Unexpected trailing comma.

(comma-dangle)


[error] 12-19: Replace ⏎··createContext,⏎··useCallback,⏎··useContext,⏎··useEffect,⏎··useRef,⏎··useState,⏎ with ·createContext,·useCallback,·useContext,·useEffect,·useRef,·useState·

(prettier/prettier)


[error] 18-18: Unexpected trailing comma.

(comma-dangle)

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>
Comment on lines +387 to 396
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add IconLoupe to button content

To address the visibility issue, ensure the IconLoupe is rendered within the button when no children are provided.

 <button
   type="button"
   ref={searchButtonRef}
   onClick={() => {
     onOpen(indexName);
   }}
   {...props}
   data-testid="Search-Button"
 >
-  {Children}
+  {Children || <IconLoupe className="h-5 w-5" />}
 </button>

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 eslint

[error] 387-387: Replace "button" with 'button'

(prettier/prettier)


[error] 387-387: Unexpected usage of doublequote.

(jsx-quotes)


[error] 393-393: Replace "Search-Button" with 'Search-Button'

(prettier/prettier)


[error] 393-393: Unexpected usage of doublequote.

(jsx-quotes)

Expand Down
Loading