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:
70
www/api-reference/hooks/use-keyboard-shortcut.tsx
Normal file
70
www/api-reference/hooks/use-keyboard-shortcut.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import { useCallback, useEffect } from "react"
|
||||
import { usePageLoading } from "../providers/page-loading"
|
||||
|
||||
type useKeyboardShortcutOptions = {
|
||||
metakey?: boolean
|
||||
shortcutKeys: string[]
|
||||
action: (e: KeyboardEvent) => void
|
||||
checkEditing?: boolean
|
||||
preventDefault?: boolean
|
||||
}
|
||||
|
||||
const useKeyboardShortcut = ({
|
||||
metakey = true,
|
||||
shortcutKeys,
|
||||
action,
|
||||
checkEditing = true,
|
||||
preventDefault = true,
|
||||
}: useKeyboardShortcutOptions) => {
|
||||
const { isLoading } = usePageLoading()
|
||||
|
||||
function isEditingContent(event: KeyboardEvent) {
|
||||
const element = event.target as HTMLElement
|
||||
const tagName = element.tagName
|
||||
return (
|
||||
element.isContentEditable ||
|
||||
tagName === "INPUT" ||
|
||||
tagName === "SELECT" ||
|
||||
tagName === "TEXTAREA"
|
||||
)
|
||||
}
|
||||
|
||||
const checkKeysPressed = useCallback(
|
||||
(pressedKey: string) => {
|
||||
const lowerPressedKey = pressedKey.toLowerCase()
|
||||
return shortcutKeys.some(
|
||||
(value) => lowerPressedKey === value.toLowerCase()
|
||||
)
|
||||
},
|
||||
[shortcutKeys]
|
||||
)
|
||||
|
||||
const sidebarShortcut = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
if (isLoading) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
(!metakey || e.metaKey || e.ctrlKey) &&
|
||||
checkKeysPressed(e.key) &&
|
||||
(!checkEditing || !isEditingContent(e))
|
||||
) {
|
||||
if (preventDefault) {
|
||||
e.preventDefault()
|
||||
}
|
||||
action(e)
|
||||
}
|
||||
},
|
||||
[isLoading, metakey, checkKeysPressed, checkEditing, action, preventDefault]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", sidebarShortcut)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", sidebarShortcut)
|
||||
}
|
||||
}, [sidebarShortcut])
|
||||
}
|
||||
|
||||
export default useKeyboardShortcut
|
||||
93
www/api-reference/hooks/use-select.tsx
Normal file
93
www/api-reference/hooks/use-select.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { useCallback, useMemo } from "react"
|
||||
|
||||
export type OptionType = {
|
||||
value: string
|
||||
label: string
|
||||
index?: string
|
||||
isAllOption?: boolean
|
||||
}
|
||||
|
||||
export type SelectOptions = {
|
||||
value: string | string[]
|
||||
multiple?: boolean
|
||||
options: OptionType[]
|
||||
setSelected?: (value: string | string[]) => void
|
||||
addSelected?: (value: string) => void
|
||||
removeSelected?: (value: string) => void
|
||||
handleAddAll?: (isAllSelected: boolean) => void
|
||||
}
|
||||
|
||||
const useSelect = ({
|
||||
value,
|
||||
options,
|
||||
multiple = false,
|
||||
setSelected,
|
||||
addSelected,
|
||||
removeSelected,
|
||||
handleAddAll,
|
||||
}: SelectOptions) => {
|
||||
const isValueSelected = useCallback(
|
||||
(val: string) => {
|
||||
return (
|
||||
(typeof value === "string" && val === value) ||
|
||||
(Array.isArray(value) && value.includes(val))
|
||||
)
|
||||
},
|
||||
[value]
|
||||
)
|
||||
|
||||
// checks if there are multiple selected values
|
||||
const hasSelectedValues = useMemo(() => {
|
||||
return multiple && Array.isArray(value) && value.length > 0
|
||||
}, [value, multiple])
|
||||
|
||||
// checks if there are any selected values,
|
||||
// whether multiple or one
|
||||
const hasSelectedValue = useMemo(() => {
|
||||
return hasSelectedValues || (typeof value === "string" && value.length)
|
||||
}, [hasSelectedValues, value])
|
||||
|
||||
const selectedValues: OptionType[] = useMemo(() => {
|
||||
if (typeof value === "string") {
|
||||
const selectedValue = options.find((option) => option.value === value)
|
||||
return selectedValue ? [selectedValue] : []
|
||||
} else if (Array.isArray(value)) {
|
||||
return options.filter((option) => value.includes(option.value))
|
||||
}
|
||||
return []
|
||||
}, [options, value])
|
||||
|
||||
const isAllSelected = useMemo(() => {
|
||||
return Array.isArray(value) && value.length === options.length
|
||||
}, [options, value])
|
||||
|
||||
const handleChange = (selectedValue: string, wasSelected: boolean) => {
|
||||
if (multiple) {
|
||||
wasSelected
|
||||
? removeSelected?.(selectedValue)
|
||||
: addSelected?.(selectedValue)
|
||||
} else {
|
||||
setSelected?.(selectedValue)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelectAll = () => {
|
||||
if (handleAddAll) {
|
||||
handleAddAll(isAllSelected)
|
||||
} else {
|
||||
setSelected?.(options.map((option) => option.value))
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isValueSelected,
|
||||
hasSelectedValue,
|
||||
hasSelectedValues,
|
||||
selectedValues,
|
||||
isAllSelected,
|
||||
handleChange,
|
||||
handleSelectAll,
|
||||
}
|
||||
}
|
||||
|
||||
export default useSelect
|
||||
Reference in New Issue
Block a user