Skip to content

Commit

Permalink
[v4] search tweaks (#3852)
Browse files Browse the repository at this point in the history
* search tweaks

* search tweaks

* search tweaks

* search tweaks

* search tweaks

* search tweaks

* upd

* upd
  • Loading branch information
dimaMachina authored Dec 23, 2024
1 parent 3fc12a0 commit 242e0d0
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 61 deletions.
7 changes: 7 additions & 0 deletions .changeset/beige-owls-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"nextra-theme-blog": patch
"nextra-theme-docs": patch
"nextra": patch
---

search tweaks
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@tailwindcss/postcss": "^4.0.0-beta.8",
"@types/node": "^22.0.0",
"@types/react": "^18.2.23",
"pagefind": "^1.1.1",
"pagefind": "^1.3.0",
"tailwindcss": "^4.0.0-beta.8"
},
"browserslist": [
Expand Down
2 changes: 1 addition & 1 deletion examples/blog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
"react-dom": "18.3.1"
},
"devDependencies": {
"pagefind": "^1.1.1"
"pagefind": "^1.3.0"
}
}
2 changes: 1 addition & 1 deletion examples/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
"react-dom": "18.3.1"
},
"devDependencies": {
"pagefind": "^1.1.1"
"pagefind": "^1.3.0"
}
}
2 changes: 1 addition & 1 deletion examples/swr-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"devDependencies": {
"@next/bundle-analyzer": "^14.2.13",
"@tailwindcss/postcss": "^4.0.0-beta.8",
"pagefind": "^1.1.1",
"pagefind": "^1.3.0",
"tailwindcss": "^4.0.0-beta.8"
},
"browserslist": [
Expand Down
9 changes: 7 additions & 2 deletions packages/esbuild-react-compiler-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ const DEFAULT_REACT_COMPILER_CONFIG = {
filename: string,
result: { kind: 'CompileError' | 'CompileSuccess' }
) {
const relativeFilePath = path.relative(process.cwd(), filename)
if (result.kind === 'CompileSuccess') {
console.info('🚀 File', filename, 'was optimized with react-compiler')
console.info(
'🚀 File',
relativeFilePath,
'was optimized with react-compiler'
)
return
}
console.error(
'❌ File',
filename,
relativeFilePath,
'was not optimized with react-compiler'
)
console.error(result)
Expand Down
12 changes: 8 additions & 4 deletions packages/nextra-theme-docs/src/mdx-components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,25 @@ const DEFAULT_COMPONENTS = getNextraMDXComponents({
{...props}
/>
),
wrapper({ toc, children, ...props }) {
wrapper({ toc, children, metadata, ...props }) {
// @ts-expect-error fixme
toc = toc.map(item => ({
...item,
value: removeLinks(item.value)
}))
return (
<div className="x:mx-auto x:flex x:max-w-(--nextra-content-width)">
<div
className="x:mx-auto x:flex x:max-w-(--nextra-content-width)"
// Attach user-defined props to wrapper container, e.g. `data-pagefind-filter`
{...props}
>
<Sidebar toc={toc} />

<ClientWrapper toc={toc} {...props}>
<ClientWrapper toc={toc} metadata={metadata}>
<SkipNavContent />
<main
data-pagefind-body={
(props.metadata as any).searchable !== false || undefined
(metadata as any).searchable !== false || undefined
}
>
{children}
Expand Down
37 changes: 21 additions & 16 deletions packages/nextra/src/client/components/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NextLink from 'next/link'
import { useRouter } from 'next/navigation'
import type { FC, FocusEventHandler, ReactElement, SyntheticEvent } from 'react'
import { useDeferredValue, useEffect, useRef, useState } from 'react'
import type { PagefindSearchOptions } from '../../types.js'
import { useMounted } from '../hooks/use-mounted.js'
import { InformationCircleIcon, SpinnerIcon } from '../icons/index.js'

Expand Down Expand Up @@ -46,9 +47,10 @@ type SearchProps = {
loading?: ReactElement | string
placeholder?: string
className?: string
searchOptions?: PagefindSearchOptions
}

const INPUTS = new Set(['input', 'select', 'button', 'textarea'])
const INPUTS = new Set(['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'])

const DEV_SEARCH_NOTICE = (
<>
Expand All @@ -69,7 +71,8 @@ export const Search: FC<SearchProps> = ({
emptyResult = 'No results found.',
errorText = 'Failed to load search index.',
loading = 'Loading…',
placeholder = 'Search documentation…'
placeholder = 'Search documentation…',
searchOptions
}) => {
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<ReactElement | string>('')
Expand Down Expand Up @@ -105,7 +108,11 @@ export const Search: FC<SearchProps> = ({
return
}
}
const { results } = await window.pagefind!.search<PagefindResult>(value)
const { results } =
await window.pagefind!.debouncedSearch<PagefindResult>(
value,
searchOptions
)
const data = await Promise.all(results.map(o => o.data()))

setResults(
Expand All @@ -121,34 +128,31 @@ export const Search: FC<SearchProps> = ({
setIsLoading(false)
}
handleSearch(deferredSearch)
}, [deferredSearch])
}, [deferredSearch]) // eslint-disable-line react-hooks/exhaustive-deps -- ignore searchOptions

const router = useRouter()
const [focused, setFocused] = useState(false)
const mounted = useMounted()
const inputRef = useRef<HTMLInputElement>(null)
const inputRef = useRef<HTMLInputElement>(null!)

useEffect(() => {
function handleKeyDown(event: globalThis.KeyboardEvent) {
const input = inputRef.current
const { activeElement } = document
const tagName = activeElement?.tagName.toLowerCase()
const el = document.activeElement
if (
!input ||
!tagName ||
INPUTS.has(tagName) ||
// @ts-expect-error -- fixme
activeElement?.isContentEditable
)
!el ||
INPUTS.has(el.tagName) ||
(el as HTMLElement).isContentEditable
) {
return
}
if (
event.key === '/' ||
(event.key === 'k' &&
(event.metaKey /* for Mac */ || /* for non-Mac */ event.ctrlKey))
) {
event.preventDefault()
// prevent to scroll to top
input.focus({ preventScroll: true })
inputRef.current.focus({ preventScroll: true })
}
}

Expand Down Expand Up @@ -193,7 +197,7 @@ export const Search: FC<SearchProps> = ({
if (!searchResult) return
// Calling before navigation so selector `html:not(:has(*:focus))` in styles.css will work,
// and we'll have padding top since input is not focused
inputRef.current?.blur()
inputRef.current.blur()
router.push(searchResult.url)
setSearch('')
}
Expand All @@ -202,6 +206,7 @@ export const Search: FC<SearchProps> = ({
<Combobox onChange={handleSelect}>
<div
className={cn(
'nextra-search',
'x:relative x:flex x:items-center',
'x:text-gray-900 x:dark:text-gray-300',
'x:contrast-more:text-gray-800 x:contrast-more:dark:text-gray-300',
Expand Down
13 changes: 6 additions & 7 deletions packages/nextra/src/client/components/steps.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import cn from 'clsx'
import type { ComponentProps, CSSProperties, FC } from 'react'
import type { ComponentProps, FC } from 'react'
import { useId } from 'react'

export const Steps: FC<ComponentProps<'div'>> = ({
Expand All @@ -16,12 +16,11 @@ export const Steps: FC<ComponentProps<'div'>> = ({
'x:dark:border-neutral-800',
className
)}
style={
{
...style,
'--counter-id': id
} as CSSProperties
}
style={{
...style,
// @ts-expect-error -- fixme
'--counter-id': id
}}
{...props}
>
{children}
Expand Down
10 changes: 8 additions & 2 deletions packages/nextra/src/client/mdx-components/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ This is Turbopack bug, which will not occurs on production (since Webpack is use
}
}
const ComponentToUse = typeof props.src === 'object' ? NextImage : 'img'
// @ts-expect-error -- fixme
return <ComponentToUse {...props} ref={ref} />
return (
// @ts-expect-error -- fixme
<ComponentToUse
{...props}
ref={ref}
data-pagefind-index-attrs="title,alt"
/>
)
})

Image.displayName = 'Image'
8 changes: 7 additions & 1 deletion packages/nextra/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
declare namespace globalThis {
import type { PagefindSearchOptions } from './types.js'
var pagefind:
| {
search: <T>(query: string) => Promise<{
// https://github.com/CloudCannon/pagefind/blob/2a0aa90cfb78bb8551645ac9127a1cd49cf54add/pagefind_web_js/lib/coupled_search.ts#L600
debouncedSearch: <T>(
term: string,
options?: PagefindSearchOptions,
debounceTimeoutMs?: number
) => Promise<{
results: {
data: () => Promise<T>
id: string
Expand Down
13 changes: 13 additions & 0 deletions packages/nextra/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,16 @@ export type MDXWrapper = FC<{
}>

export type MetaRecord = Record<string, z.infer<typeof metaSchema>>

// Copied from https://github.com/CloudCannon/pagefind/blob/2a0aa90cfb78bb8551645ac9127a1cd49cf54add/pagefind_web_js/types/index.d.ts#L72-L82
/** Options that can be passed to pagefind.search() */
export type PagefindSearchOptions = {
/** If set, this call will load all assets but return before searching. Prefer using pagefind.preload() instead */
preload?: boolean
/** Add more verbose console logging for this search query */
verbose?: boolean
/** The set of filters to execute with this search. Input type is extremely flexible, see the filtering docs for details */
filters?: object
/** The set of sorts to use for this search, instead of relevancy */
sort?: object
}
50 changes: 25 additions & 25 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 242e0d0

Please sign in to comment.