docs: add search to workflows reference (#11054)

* docs: add search to workflows reference

* fix error
This commit is contained in:
Shahed Nasser
2025-01-20 17:02:29 +02:00
committed by GitHub
parent 5b9cb5a2be
commit af350c3a8b
15 changed files with 349 additions and 112 deletions
@@ -1,21 +1,25 @@
"use client"
import React, { useCallback, useMemo } from "react"
import React, { useCallback, useEffect, useMemo, useState } from "react"
import {
Card,
CardList,
getLocalSearch,
H2,
H3,
H4,
Hr,
isSidebarItemLink,
LocalSearch,
MarkdownContent,
SearchInput,
useIsBrowser,
useSidebar,
} from "../.."
import { InteractiveSidebarItem, SidebarItem, SidebarItemLink } from "types"
import slugify from "slugify"
import { MDXComponents } from "../.."
import { ChevronDoubleRight } from "@medusajs/icons"
import { ChevronDoubleRight, ExclamationCircle } from "@medusajs/icons"
type HeadingComponent = (
props: React.HTMLAttributes<HTMLHeadingElement>
@@ -32,6 +36,11 @@ export type UseChildDocsProps = {
childLevel?: number
itemsPerRow?: number
defaultItemsPerRow?: number
search?: {
enable: boolean
storageKey?: string
placeholder?: string
}
}
export const useChildDocs = ({
@@ -45,8 +54,18 @@ export const useChildDocs = ({
childLevel = 1,
itemsPerRow,
defaultItemsPerRow,
search: {
enable: enableSearch = false,
storageKey = "child-docs",
...searchProps
} = { enable: false },
}: UseChildDocsProps) => {
const { currentItems, activeItem } = useSidebar()
const { isBrowser } = useIsBrowser()
const [searchQuery, setSearchQuery] = useState("")
const [localSearch, setLocalSearch] = useState<
LocalSearch<SidebarItemLink> | undefined
>()
const TitleHeaderComponent = useCallback(
(level: number): HeadingComponent => {
switch (level) {
@@ -92,16 +111,11 @@ export const useChildDocs = ({
}
}
const filterItems = (items: SidebarItem[]): SidebarItem[] => {
return items
.filter(filterCondition)
const filterItems = (items: SidebarItem[]): InteractiveSidebarItem[] => {
return (items.filter(filterCondition) as InteractiveSidebarItem[])
.map((item) => Object.assign({}, item))
.map((item) => {
if (
item.type !== "separator" &&
item.children &&
filterType === "hide"
) {
if (item.children && filterType === "hide") {
item.children = filterItems(item.children)
}
@@ -109,25 +123,6 @@ export const useChildDocs = ({
})
}
const filteredItems = useMemo(() => {
const targetItems =
type === "sidebar"
? currentItems
? Object.assign({}, currentItems)
: undefined
: {
default: [...(activeItem?.children || [])],
}
if (filterType === "all" || !targetItems) {
return targetItems
}
return {
...targetItems,
default: filterItems(targetItems.default),
}
}, [currentItems, type, activeItem, filterItems])
const filterNonInteractiveItems = (
items: SidebarItem[] | undefined
): InteractiveSidebarItem[] => {
@@ -164,11 +159,115 @@ export const useChildDocs = ({
return childrenResult
}
const getTopLevelElms = (items?: SidebarItem[]) => {
const filteredItems = useMemo(() => {
let targetItems =
type === "sidebar"
? currentItems
? Object.assign({}, currentItems)
: undefined
: {
default: [...(activeItem?.children || [])],
}
if (filterType !== "all" && targetItems) {
targetItems = {
...targetItems,
default: filterItems(targetItems.default),
}
}
return targetItems
? {
...targetItems,
default: filterNonInteractiveItems(targetItems?.default),
}
: undefined
}, [currentItems, type, activeItem, filterType])
const searchableItems = useMemo(() => {
const searchableItems: SidebarItemLink[] = []
if (!enableSearch) {
return searchableItems
}
if (onlyTopLevel) {
filteredItems?.default?.forEach((item) => {
if (isSidebarItemLink(item)) {
searchableItems.push(item)
} else {
const firstChild = item.children?.find((child) =>
isSidebarItemLink(child)
)
if (firstChild) {
searchableItems.push(firstChild as SidebarItemLink)
}
}
})
} else {
filteredItems?.default?.forEach((item) => {
const childItems: SidebarItemLink[] =
(getChildrenForLevel(item)?.filter((childItem) => {
return isSidebarItemLink(childItem)
}) as SidebarItemLink[]) || []
searchableItems.push(...childItems)
})
}
return searchableItems
}, [filteredItems, onlyTopLevel, enableSearch])
useEffect(() => {
if (!enableSearch && localSearch) {
setLocalSearch(undefined)
return
}
if (!enableSearch || !searchableItems?.length || localSearch) {
return
}
setLocalSearch(
getLocalSearch<SidebarItemLink>({
docs: searchableItems,
searchableFields: ["title", "description"],
options: {
storeFields: ["title", "description", "path", "type"],
searchOptions: {
boost: { title: 2 },
prefix: true,
fuzzy: 0.2,
},
idField: "path",
},
})
)
}, [searchableItems, enableSearch, localSearch])
const searchResult = useMemo(() => {
return localSearch?.search(searchQuery) || []
}, [localSearch, searchQuery])
useEffect(() => {
if (!isBrowser || !enableSearch) {
return
}
const storedQuery = localStorage.getItem(`${storageKey}-query`)
if (storedQuery) {
setSearchQuery(storedQuery)
}
}, [isBrowser, storageKey, enableSearch])
useEffect(() => {
if (!isBrowser || !enableSearch) {
return
}
localStorage.setItem(`${storageKey}-query`, searchQuery)
}, [isBrowser, searchQuery, storageKey, enableSearch])
const getTopLevelElms = (items?: InteractiveSidebarItem[]) => {
return (
<CardList
items={
filterNonInteractiveItems(items).map((childItem) => {
items?.map((childItem) => {
const href = isSidebarItemLink(childItem)
? childItem.path
: childItem.children?.length
@@ -193,11 +292,10 @@ export const useChildDocs = ({
}
const getAllLevelsElms = (
items?: SidebarItem[],
items?: InteractiveSidebarItem[],
headerLevel = titleLevel
) => {
const filteredItems = filterNonInteractiveItems(items)
return filteredItems.map((item, key) => {
return items?.map((item, key) => {
const itemChildren = getChildrenForLevel(item)
const HeadingComponent = itemChildren?.length
? TitleHeaderComponent(headerLevel)
@@ -243,7 +341,7 @@ export const useChildDocs = ({
defaultItemsPerRow={defaultItemsPerRow}
/>
)}
{key !== filteredItems.length - 1 && headerLevel === 2 && <Hr />}
{key !== items.length - 1 && headerLevel === 2 && <Hr />}
</>
)}
{!HeadingComponent && isSidebarItemLink(item) && (
@@ -259,12 +357,64 @@ export const useChildDocs = ({
})
}
const getElms = (items?: SidebarItem[]) => {
return onlyTopLevel ? getTopLevelElms(items) : getAllLevelsElms(items)
const getSearchResultElms = () => {
const Heading = TitleHeaderComponent(titleLevel)
return (
<>
<Heading>Search Results</Heading>
{searchResult.length > 0 && (
<CardList
items={searchResult.map((item) => ({
title: item.title,
href: item.path,
text: item.description,
rightIcon: item.type === "ref" ? ChevronDoubleRight : undefined,
highlightText: item.terms,
}))}
itemsPerRow={itemsPerRow}
defaultItemsPerRow={defaultItemsPerRow}
className="my-docs_2"
/>
)}
{!searchResult.length && (
<div className="flex flex-col justify-center items-center gap-docs_0.75">
<ExclamationCircle className="text-medusa-fg-subtle" />
<span className="text-compact-small-plus text-medusa-fg-subtle text-center">
No results found matching your query.
</span>
<span className="text-compact-small text-medusa-fg-muted text-center">
Try searching with another term or clearing the search.
</span>
</div>
)}
</>
)
}
const getElms = () => {
return (
<>
{enableSearch && (
<SearchInput
value={searchQuery || ""}
onChange={setSearchQuery}
{...searchProps}
/>
)}
{searchQuery && getSearchResultElms()}
{!searchQuery && (
<>
{onlyTopLevel
? getTopLevelElms(filteredItems?.default)
: getAllLevelsElms(filteredItems?.default)}
</>
)}
</>
)
}
return {
items: filteredItems,
component: getElms(filteredItems?.default),
component: getElms(),
}
}