Added search suggestions to the quick launch menu.

If this feture and the search feature of the `quicklaunch` are turned on, up to *four* search suggestions will be shown as results.
This commit is contained in:
Flo2410 2024-01-26 21:57:20 +00:00
parent a01f60ec25
commit cc73839874
No known key found for this signature in database
GPG Key ID: 8ECB00AC5216DC7F
3 changed files with 78 additions and 37 deletions

View File

@ -16,9 +16,9 @@ export default function QuickLaunch({
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { settings } = useContext(SettingsContext); const { settings } = useContext(SettingsContext);
const { searchDescriptions, hideVisitURL } = settings?.quicklaunch const { searchDescriptions, hideVisitURL, hideSearchSuggestions } = settings?.quicklaunch
? settings.quicklaunch ? settings.quicklaunch
: { searchDescriptions: false, hideVisitURL: false }; : { searchDescriptions: false, hideVisitURL: false, hideSearchSuggestions: false };
const searchField = useRef(); const searchField = useRef();
@ -90,45 +90,66 @@ export default function QuickLaunch({
} }
useEffect(() => { useEffect(() => {
if (searchString.length === 0) setResults([]); (async () => {
else { if (searchString.length === 0) setResults([]);
let newResults = servicesAndBookmarks.filter((r) => { else {
const nameMatch = r.name.toLowerCase().includes(searchString); let newResults = servicesAndBookmarks.filter((r) => {
let descriptionMatch; const nameMatch = r.name.toLowerCase().includes(searchString);
let descriptionMatch;
if (searchDescriptions) {
descriptionMatch = r.description?.toLowerCase().includes(searchString);
r.priority = nameMatch ? 2 * +nameMatch : +descriptionMatch; // eslint-disable-line no-param-reassign
}
return nameMatch || descriptionMatch;
});
if (searchDescriptions) { if (searchDescriptions) {
descriptionMatch = r.description?.toLowerCase().includes(searchString); newResults = newResults.sort((a, b) => b.priority - a.priority);
r.priority = nameMatch ? 2 * +nameMatch : +descriptionMatch; // eslint-disable-line no-param-reassign
} }
return nameMatch || descriptionMatch;
});
if (searchDescriptions) { if (searchProvider) {
newResults = newResults.sort((a, b) => b.priority - a.priority); newResults.push({
href: searchProvider.url + encodeURIComponent(searchString),
name: `${searchProvider.name ?? t("quicklaunch.custom")} ${t("quicklaunch.search")}`,
type: "search",
});
if (!hideSearchSuggestions) {
const searchSuggestionResult = await fetch(`/api/searchSuggestion?query=${encodeURIComponent(searchString)}&providerName=${searchProvider.name}`);
const searchSuggestion = (await searchSuggestionResult.json())[1];
// Check if there is a search suggestion
if (searchSuggestion) {
// Restrict the searchSuggestion to 4 entries
if (searchSuggestion.length - 4 > 0) {
searchSuggestion.splice(-(searchSuggestion.length-4));
}
newResults = newResults.concat(searchSuggestion.map((suggestion)=>({
href: searchProvider.url + encodeURIComponent(suggestion),
name: suggestion,
type: "search",
})));
}
}
}
if (!hideVisitURL && url) {
newResults.unshift({
href: url.toString(),
name: `${t("quicklaunch.visit")} URL`,
type: "url",
});
}
setResults(newResults);
if (newResults.length) {
setCurrentItemIndex(0);
}
} }
})()
if (searchProvider) { }, [searchString, servicesAndBookmarks, searchDescriptions, hideVisitURL, hideSearchSuggestions, searchProvider, url, t]);
newResults.push({
href: searchProvider.url + encodeURIComponent(searchString),
name: `${searchProvider.name ?? t("quicklaunch.custom")} ${t("quicklaunch.search")} `,
type: "search",
});
}
if (!hideVisitURL && url) {
newResults.unshift({
href: url.toString(),
name: `${t("quicklaunch.visit")} URL`,
type: "url",
});
}
setResults(newResults);
if (newResults.length) {
setCurrentItemIndex(0);
}
}
}, [searchString, servicesAndBookmarks, searchDescriptions, hideVisitURL, searchProvider, url, t]);
const [hidden, setHidden] = useState(true); const [hidden, setHidden] = useState(true);
useEffect(() => { useEffect(() => {

View File

@ -12,31 +12,37 @@ export const searchProviders = {
google: { google: {
name: "Google", name: "Google",
url: "https://www.google.com/search?q=", url: "https://www.google.com/search?q=",
suggestionUrl: "https://www.google.com/complete/search?client=chrome&q=home",
icon: SiGoogle, icon: SiGoogle,
}, },
duckduckgo: { duckduckgo: {
name: "DuckDuckGo", name: "DuckDuckGo",
url: "https://duckduckgo.com/?q=", url: "https://duckduckgo.com/?q=",
suggestionUrl: "https://duckduckgo.com/ac/?type=list&q=",
icon: SiDuckduckgo, icon: SiDuckduckgo,
}, },
bing: { bing: {
name: "Bing", name: "Bing",
url: "https://www.bing.com/search?q=", url: "https://www.bing.com/search?q=",
suggestionUrl: "https://api.bing.com/osjson.aspx?query=",
icon: SiMicrosoftbing, icon: SiMicrosoftbing,
}, },
baidu: { baidu: {
name: "Baidu", name: "Baidu",
url: "https://www.baidu.com/s?wd=", url: "https://www.baidu.com/s?wd=",
suggestionUrl: "http://suggestion.baidu.com/su?&action=opensearch&ie=utf-8&wd=",
icon: SiBaidu, icon: SiBaidu,
}, },
brave: { brave: {
name: "Brave", name: "Brave",
url: "https://search.brave.com/search?q=", url: "https://search.brave.com/search?q=",
suggestionUrl: "https://search.brave.com/api/suggest?&rich=false&q=",
icon: SiBrave, icon: SiBrave,
}, },
custom: { custom: {
name: "Custom", name: "Custom",
url: false, url: false,
suggestionUrl: false,
icon: FiSearch, icon: FiSearch,
}, },
}; };

View File

@ -0,0 +1,14 @@
import { searchProviders } from "components/widgets/search/search";
import cachedFetch from "utils/proxy/cached-fetch";
export default async function handler(req, res) {
const { query, providerName } = req.query;
const provider = Object.values(searchProviders).find(({ name }) => name === providerName);
if (!provider.suggestionUrl) {
return res.json([query, []]); // Responde with the same array format but with no suggestions.
}
return res.send(await cachedFetch(`${provider.suggestionUrl}${query}`, 5));
}