import { Combobox } from '@headlessui/react' import { CustomIcon } from 'components/CustomIcon' import decamelize from 'decamelize' import Fuse from 'fuse.js' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { interactionMap } from 'lib/settings/initialKeybindings' import { Setting } from 'lib/settings/initialSettings' import { SettingsLevel } from 'lib/settings/settingsTypes' import { useEffect, useMemo, useRef, useState } from 'react' import { useHotkeys } from 'react-hotkeys-hook' import { useNavigate } from 'react-router-dom' type ExtendedSettingsLevel = SettingsLevel | 'keybindings' export type SettingsSearchItem = { name: string displayName: string description: string category: string level: ExtendedSettingsLevel } export function SettingsSearchBar() { const inputRef = useRef(null) useHotkeys( 'Ctrl+.', (e) => { e.preventDefault() inputRef.current?.focus() }, { enableOnFormTags: true } ) const navigate = useNavigate() const [query, setQuery] = useState('') const { settings } = useSettingsAuthContext() const settingsAsSearchable: SettingsSearchItem[] = useMemo( () => [ ...Object.entries(settings.state.context).flatMap( ([category, categorySettings]) => Object.entries(categorySettings).flatMap(([settingName, setting]) => { const s = setting as Setting return (['project', 'user'] satisfies SettingsLevel[]) .filter((l) => s.hideOnLevel !== l) .map((l) => ({ category: decamelize(category, { separator: ' ' }), name: settingName, description: s.description ?? '', displayName: decamelize(settingName, { separator: ' ' }), level: l as ExtendedSettingsLevel, })) }) ), ...Object.entries(interactionMap).flatMap( ([category, categoryKeybindings]) => categoryKeybindings.map((keybinding) => ({ name: keybinding.name, displayName: keybinding.title, description: keybinding.description, category: category, level: 'keybindings' as ExtendedSettingsLevel, })) ), ], [settings.state.context] ) const [searchResults, setSearchResults] = useState(settingsAsSearchable) const fuse = new Fuse(settingsAsSearchable, { keys: ['category', 'displayName', 'description'], includeScore: true, }) useEffect(() => { const results = fuse.search(query).map((result) => result.item) setSearchResults(query.length > 0 ? results : settingsAsSearchable) }, [query]) function handleSelection({ level, name }: SettingsSearchItem) { navigate(`?tab=${level}#${name}`) } return (
setQuery(event.target.value)} className="w-full bg-transparent focus:outline-none selection:bg-primary/20 dark:selection:bg-primary/40 dark:focus:outline-none" placeholder="Search settings (^.)" autoCapitalize="off" autoComplete="off" autoCorrect="off" spellCheck="false" autoFocus />
{searchResults?.map((option) => (

{option.level} ·{' '} {decamelize(option.category, { separator: ' ' })} ·{' '} {option.displayName}

{option.description && (

{option.description}

)}
))}
) }