feat: add support for searching across all docs instances

This commit is contained in:
Hossein Mehrabi
2023-06-06 01:17:57 +03:30
parent 4859e36dab
commit b85c3f7711
11 changed files with 89 additions and 70 deletions
+22 -20
View File
@@ -13,30 +13,32 @@ const makeSearchPluginConfig = (
plugins: PluginConfig[],
options: PluginOptions,
): PluginConfig[] => {
const singleIndex = options.localSearch?.singleIndex ?? true
const docs = findDocInstances(plugins).map((plugin) =>
validateDocPluginOptions(plugin![1]),
)
return [
[
'@acid-info/logos-docusaurus-search-local',
{
hashed: true,
indexDocs: true,
indexBlog: false,
indexPages: true,
docsDir: docs.map((doc) => doc.path),
searchContextByPaths: docs.map(({ routeBasePath, path }) =>
routeBasePath === '/'
? path
: routeBasePath.startsWith('/')
? routeBasePath.slice(1)
: routeBasePath,
),
docsRouteBasePath: docs.map((doc) => doc.routeBasePath),
} as Partial<SearchPluginOptions>,
],
]
const config = {
hashed: true,
indexDocs: true,
indexBlog: false,
indexPages: true,
docsDir: docs.map((doc) => doc.path),
docsRouteBasePath: docs.map((doc) => doc.routeBasePath),
} as Partial<SearchPluginOptions>
if (!singleIndex) {
config.searchContextByPaths = docs.map(({ routeBasePath, path }) =>
routeBasePath === '/'
? path
: routeBasePath.startsWith('/')
? routeBasePath.slice(1)
: routeBasePath,
)
}
return [['@acid-info/logos-docusaurus-search-local', config]]
}
export default function logosPreset(
@@ -28,6 +28,10 @@ export type Contact = {
export type ContactInfo = Contact[]
export type LocalSearchConfig = {
singleIndex?: boolean
}
export type PresetConfig = {
businessUnit: BusinessUnits
contactInfo?: string
@@ -42,4 +46,5 @@ export type PresetConfig = {
}
customSiteConfig?: boolean
docs?: Partial<DocPluginOptions>
localSearch?: LocalSearchConfig
}
@@ -33,13 +33,10 @@ const findSearchContext = ({
versionUrl: string
searchContextByPaths: string | string[]
}): string => {
const { pathname } = window.location
let pathname = window.location.pathname
pathname = pathname.endsWith('/') ? pathname : pathname + '/'
if (
searchContextByPaths === '' ||
!Array.isArray(searchContextByPaths) ||
!pathname.startsWith(versionUrl)
)
if (!Array.isArray(searchContextByPaths) || !pathname.startsWith(versionUrl))
return ''
const uri = pathname.substring(versionUrl.length)
@@ -0,0 +1,5 @@
export const ensureTrailingString = (str: string, trail: string) =>
str.endsWith(trail) ? str : str + trail
export const ensureTrailingSlash = (str: string) =>
ensureTrailingString(str, '/')
@@ -5,10 +5,12 @@ export const usePersistedHistory = <T = any>(
options?: {
equals?: (a: T, b: T) => boolean
unique?: boolean
maxItems?: number
},
) => {
const unique = options?.unique ?? false
const equals = options?.equals ?? ((a, b) => a === b)
const maxItems = options?.maxItems ?? null
const [history, setHistory] = useLocalStorage<T[]>(
'logos-docusaurus-theme-' + key,
@@ -17,10 +19,11 @@ export const usePersistedHistory = <T = any>(
const add = (value: T) => {
const arr = history ?? []
setHistory([
const newHistory = [
value,
...(unique ? arr.filter((item) => !equals(item, value)) : arr),
])
]
setHistory(maxItems ? newHistory.slice(0, maxItems) : newHistory)
}
const remove = (rm: (item: T, index: number) => boolean) => {
@@ -14,6 +14,7 @@ export const SearchBar: React.FC<{}> = ({}) => {
const history = usePersistedHistory<SearchResultGroupItem>('search', {
unique: true,
equals: (a, b) => a.title === b.title && a.href === b.href,
maxItems: 10,
})
const search = useSearch()
const ref = useRef<HTMLDivElement>(null)
@@ -1,5 +0,0 @@
export const useProxiedGeneratedData = () => {
const win = window as any
return win.getProxiedGeneratedData()
}
@@ -1,21 +1,19 @@
import { useEffect, useRef, useState } from 'react'
import { useProxiedGeneratedData } from './useProxiedGeneratedData'
import { useVersionUrl } from './useVersionUrl'
import { useSearchContextPath } from './useSearchContextPath'
export const useSearch = () => {
const win = window as any
const { createSearchInstance } = window as any
const data = useProxiedGeneratedData()
const versionUrl = useVersionUrl()
const searchContextPath = useSearchContextPath()
const [loaded, setLoaded] = useState(false)
const search = useRef<any>(null)
const init = async () => {
search.current = await win.createSearchInstance({
search.current = await createSearchInstance({
resultsLimit: 50,
preferredVersionPath: versionUrl,
searchContextByPaths: data.searchContextByPaths,
preferredVersionPath: searchContextPath[0],
searchContextByPaths: searchContextPath[1],
})
await search.current.init()
@@ -27,7 +25,7 @@ export const useSearch = () => {
setLoaded(false)
init()
}, [versionUrl])
}, [searchContextPath[0], searchContextPath[1]])
return {
loaded,
@@ -0,0 +1,33 @@
import { useActivePluginAndVersion } from '@docusaurus/plugin-content-docs/client'
import { ensureTrailingSlash } from '../../../lib/string.utils'
const useProxiedData = () => {
const win = window as any
return win.getProxiedGeneratedData()
}
const useSearchContextByPaths = () => {
return useProxiedData().searchContextByPaths
}
export const useSearchContextPath = () => {
const separateContexts = useSearchContextByPaths()
const activePluginData = useActivePluginAndVersion()
if (!activePluginData) return ['/', '']
const {
activePlugin: {
pluginData: { path: pluginPath },
},
activeVersion,
} = activePluginData
if (!activeVersion) return ['/', '']
return [
pluginPath !== activeVersion.path
? ensureTrailingSlash(activeVersion.path)
: '/',
separateContexts,
]
}
@@ -1,27 +0,0 @@
import { useActivePlugin } from '@docusaurus/plugin-content-docs/client'
import { useDocsPreferredVersion } from '@docusaurus/theme-common/internal'
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import { useProxiedGeneratedData } from './useProxiedGeneratedData'
export const useVersionUrl = () => {
const {
siteConfig: { baseUrl },
} = useDocusaurusContext()
const { docsPluginIdForPreferredVersion } = useProxiedGeneratedData()
let result = baseUrl
const activePlugin = useActivePlugin()
const { preferredVersion } = useDocsPreferredVersion(
activePlugin?.pluginId ?? docsPluginIdForPreferredVersion,
)
result =
preferredVersion && !preferredVersion.isLast
? preferredVersion.path + '/'
: result
return result
}
@@ -1,3 +1,4 @@
import ErrorBoundary from '@docusaurus/ErrorBoundary'
import { useActivePlugin } from '@docusaurus/plugin-content-docs/lib/client/index.js'
import React from 'react'
import { SearchBar } from './SearchBar'
@@ -6,7 +7,13 @@ const SearchBarWrapper: React.FC = () => {
const activePlugin = useActivePlugin()
if (!activePlugin) return <></>
return typeof window === 'undefined' ? <></> : <SearchBar />
return typeof window === 'undefined' ? (
<></>
) : (
<ErrorBoundary fallback={() => <></>}>
<SearchBar />
</ErrorBoundary>
)
}
export default SearchBarWrapper