import { useTranslation } from "react-i18next"; import { useEffect, useState, useRef, useCallback, useContext } from "react"; import classNames from "classnames"; import { resolveIcon } from "./services/item"; import { SettingsContext } from "utils/contexts/settings"; export default function QuickLaunch({servicesAndBookmarks, searchString, setSearchString, isOpen, close}) { const { t } = useTranslation(); const { settings } = useContext(SettingsContext); const searchField = useRef(); const [results, setResults] = useState([]); const [currentItemIndex, setCurrentItemIndex] = useState(null); function openCurrentItem(newWindow) { const result = results[currentItemIndex]; window.open(result.href, newWindow ? "_blank" : settings.target ?? "_blank"); } const closeAndReset = useCallback(() => { close(false); setTimeout(() => { setSearchString(""); setCurrentItemIndex(null); }, 200); // delay a little for animations }, [close, setSearchString, setCurrentItemIndex]); function handleSearchChange(event) { setSearchString(event.target.value.toLowerCase()) } function handleSearchKeyDown(event) { if (event.key === "Escape") { closeAndReset(); } else if (event.key === "Enter" && results.length) { closeAndReset(); openCurrentItem(event.metaKey); } else if (event.key === "ArrowDown" && results[currentItemIndex + 1]) { setCurrentItemIndex(currentItemIndex + 1); event.preventDefault(); } else if (event.key === "ArrowUp" && currentItemIndex > 0) { setCurrentItemIndex(currentItemIndex - 1); event.preventDefault(); } } function handleItemHover(event) { setCurrentItemIndex(parseInt(event.target?.dataset?.index, 10)); } function handleItemClick(event) { closeAndReset(); openCurrentItem(event.metaKey); } useEffect(() => { if (searchString.length === 0) setResults([]); else { const newResults = servicesAndBookmarks.filter(r => r.name.toLowerCase().includes(searchString)); setResults(newResults); if (newResults.length) { setCurrentItemIndex(0); } } }, [searchString, servicesAndBookmarks]); const [hidden, setHidden] = useState(true); useEffect(() => { function handleBackdropClick(event) { if (event.target?.tagName === "DIV") closeAndReset(); } if (isOpen) { searchField.current.focus(); document.body.addEventListener('click', handleBackdropClick); setHidden(false); } else { document.body.removeEventListener('click', handleBackdropClick); setTimeout(() => { setHidden(true); }, 300); // disable on close } }, [isOpen, closeAndReset]); return (