docs,api-ref: added search filters (#4830)
* initial implementation of search modal * added hit and search suggestions * added support for multiple indices * updated sample env * added close when click outside dropdown * test for mobile * added mobile design * added shortcut * dark mode fixes * added search to docs * added plugins filter * added React import * moved filters to configurations * handled error on page load * change suggestion text * removed hits limit * handle select all * open link in current tab * change highlight colors * added support for shortcuts + auto focus * change header and footer * redesigned search ui
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import type { Area } from "@/types/openapi"
|
||||
import { createContext, useContext, useState } from "react"
|
||||
import { createContext, useContext, useEffect, useState } from "react"
|
||||
import { useSearch } from "./search"
|
||||
|
||||
type AreaContextType = {
|
||||
area: Area
|
||||
@@ -17,6 +18,13 @@ type AreaProviderProps = {
|
||||
|
||||
const AreaProvider = ({ area: passedArea, children }: AreaProviderProps) => {
|
||||
const [area, setArea] = useState<Area>(passedArea)
|
||||
const { defaultFilters, setDefaultFilters } = useSearch()
|
||||
|
||||
useEffect(() => {
|
||||
if (!defaultFilters.includes(area)) {
|
||||
setDefaultFilters([area])
|
||||
}
|
||||
}, [area, defaultFilters, setDefaultFilters])
|
||||
|
||||
return (
|
||||
<AreaContext.Provider
|
||||
|
||||
65
www/api-reference/providers/mobile.tsx
Normal file
65
www/api-reference/providers/mobile.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
"use client"
|
||||
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react"
|
||||
|
||||
type MobileContextType = {
|
||||
isMobile?: boolean
|
||||
}
|
||||
|
||||
const MobileContext = createContext<MobileContextType | null>(null)
|
||||
|
||||
type MobileProviderProps = {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const MobileProvider = ({ children }: MobileProviderProps) => {
|
||||
const [isMobile, setIsMobile] = useState(false)
|
||||
|
||||
const handleResize = useCallback(() => {
|
||||
if (window.innerWidth < 1025 && !isMobile) {
|
||||
setIsMobile(true)
|
||||
} else if (window.innerWidth >= 1025 && isMobile) {
|
||||
setIsMobile(false)
|
||||
}
|
||||
}, [isMobile])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("resize", handleResize)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize)
|
||||
}
|
||||
}, [handleResize])
|
||||
|
||||
useEffect(() => {
|
||||
handleResize()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<MobileContext.Provider
|
||||
value={{
|
||||
isMobile,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</MobileContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default MobileProvider
|
||||
|
||||
export const useMobile = () => {
|
||||
const context = useContext(MobileContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useMobile must be used within a MobileProvider")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import React, { useContext, useEffect, useState } from "react"
|
||||
import React, { useContext, useState } from "react"
|
||||
import { createContext } from "react"
|
||||
import Modal, { ModalProps } from "../components/Modal"
|
||||
|
||||
@@ -23,14 +23,6 @@ const ModalProvider = ({ children }: ModalProviderProps) => {
|
||||
setModalProps(null)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (modalProps) {
|
||||
document.body.setAttribute("data-modal", "opened")
|
||||
} else {
|
||||
document.body.removeAttribute("data-modal")
|
||||
}
|
||||
}, [modalProps])
|
||||
|
||||
return (
|
||||
<ModalContext.Provider
|
||||
value={{
|
||||
|
||||
41
www/api-reference/providers/page-loading.tsx
Normal file
41
www/api-reference/providers/page-loading.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
"use client"
|
||||
|
||||
import { createContext, useContext, useState } from "react"
|
||||
|
||||
type PageLoadingContextType = {
|
||||
isLoading: boolean
|
||||
setIsLoading: (value: boolean) => void
|
||||
}
|
||||
|
||||
const PageLoadingContext = createContext<PageLoadingContextType | null>(null)
|
||||
|
||||
type PageLoadingProviderProps = {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
const PageLoadingProvider = ({ children }: PageLoadingProviderProps) => {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
return (
|
||||
<PageLoadingContext.Provider
|
||||
value={{
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</PageLoadingContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageLoadingProvider
|
||||
|
||||
export const usePageLoading = (): PageLoadingContextType => {
|
||||
const context = useContext(PageLoadingContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("usePageLoading must be used inside a PageLoadingProvider")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
48
www/api-reference/providers/search.tsx
Normal file
48
www/api-reference/providers/search.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
"use client"
|
||||
|
||||
import { createContext, useContext, useState } from "react"
|
||||
import SearchModal from "../components/Search/Modal"
|
||||
|
||||
type SearchContextType = {
|
||||
isOpen: boolean
|
||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||
defaultFilters: string[]
|
||||
setDefaultFilters: (value: string[]) => void
|
||||
}
|
||||
|
||||
const SearchContext = createContext<SearchContextType | null>(null)
|
||||
|
||||
type SearchProviderProps = {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [defaultFilters, setDefaultFilters] = useState<string[]>([])
|
||||
|
||||
return (
|
||||
<SearchContext.Provider
|
||||
value={{
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
defaultFilters,
|
||||
setDefaultFilters,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<SearchModal />
|
||||
</SearchContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default SearchProvider
|
||||
|
||||
export const useSearch = (): SearchContextType => {
|
||||
const context = useContext(SearchContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useSearch must be used inside a SearchProvider")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
useReducer,
|
||||
useState,
|
||||
} from "react"
|
||||
import { usePageLoading } from "./page-loading"
|
||||
|
||||
export enum SidebarItemSections {
|
||||
TOP = "top",
|
||||
@@ -167,6 +168,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
const [activePath, setActivePath] = useState<string | null>("")
|
||||
const [mobileSidebarOpen, setMobileSidebarOpen] = useState<boolean>(false)
|
||||
const [desktopSidebarOpen, setDesktopSidebarOpen] = useState(true)
|
||||
const { isLoading, setIsLoading } = usePageLoading()
|
||||
|
||||
const findItemInSection = useCallback(
|
||||
(
|
||||
@@ -288,6 +290,12 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
}
|
||||
}, [handleHashChange])
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading && items.top.length && items.bottom.length) {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [items, isLoading, setIsLoading])
|
||||
|
||||
return (
|
||||
<SidebarContext.Provider
|
||||
value={{
|
||||
|
||||
Reference in New Issue
Block a user