diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index 8faf6d864..5eae86002 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/ca/common.json b/public/locales/ca/common.json index e40c5b0d1..1971c3ff5 100644 --- a/public/locales/ca/common.json +++ b/public/locales/ca/common.json @@ -207,5 +207,9 @@ "cpu": "Processador", "mem": "Memòria", "wait": "Si us plau, espereu" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/de/common.json b/public/locales/de/common.json index 05e5834b7..9d9ed6bc2 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "RAM", "wait": "Bitte warten" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/en/common.json b/public/locales/en/common.json index b1fded098..a1fc6ae58 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -219,6 +219,10 @@ "mem": "MEM", "wait": "Please wait" }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" + }, "wmo": { "0-day": "Sunny", "0-night": "Clear", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 862162f8c..10724e675 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -207,5 +207,9 @@ "cpu": "Procesador", "mem": "Memoria", "wait": "Espere por favor" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/fi/common.json b/public/locales/fi/common.json index 0a3e50c2e..b419ee32f 100644 --- a/public/locales/fi/common.json +++ b/public/locales/fi/common.json @@ -207,5 +207,9 @@ "wait": "Please wait", "cpu": "CPU", "mem": "MEM" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index f6429c492..0b81a28c5 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -47,7 +47,7 @@ "wanted": "Demande", "queued": "En attente", "movies": "Films", - "missing": "Missing" + "missing": "Manquant" }, "readarr": { "wanted": "Demande", @@ -207,5 +207,9 @@ "cpu": "Cpu", "mem": "Mém", "wait": "Merci de patienter" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/he/common.json b/public/locales/he/common.json index 5d0d41536..46cd144af 100644 --- a/public/locales/he/common.json +++ b/public/locales/he/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/hr/common.json b/public/locales/hr/common.json index 9e8bc13fe..a00bcaadb 100644 --- a/public/locales/hr/common.json +++ b/public/locales/hr/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/hu/common.json b/public/locales/hu/common.json index ec15d5e64..bc76c1f31 100644 --- a/public/locales/hu/common.json +++ b/public/locales/hu/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/it/common.json b/public/locales/it/common.json index 4d673e3d7..edc397cd8 100644 --- a/public/locales/it/common.json +++ b/public/locales/it/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/nb-NO/common.json b/public/locales/nb-NO/common.json index b9b7cdf63..1e7484e14 100644 --- a/public/locales/nb-NO/common.json +++ b/public/locales/nb-NO/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json index d8206f53c..38af7341e 100644 --- a/public/locales/nl/common.json +++ b/public/locales/nl/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/pl/common.json b/public/locales/pl/common.json index 6c0a7377b..2b492d877 100644 --- a/public/locales/pl/common.json +++ b/public/locales/pl/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/pt-BR/common.json b/public/locales/pt-BR/common.json index 9d38815b7..4dbd1d3ed 100644 --- a/public/locales/pt-BR/common.json +++ b/public/locales/pt-BR/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json index 96d818642..53ba73efb 100644 --- a/public/locales/pt/common.json +++ b/public/locales/pt/common.json @@ -218,5 +218,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/ro/common.json b/public/locales/ro/common.json index 645b71823..1ed28d2da 100644 --- a/public/locales/ro/common.json +++ b/public/locales/ro/common.json @@ -207,5 +207,9 @@ "cpu": "Procesor", "mem": "Memorie", "wait": "Te rugam sa astepti" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index e20e3084e..dabdcf290 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/sr/common.json b/public/locales/sr/common.json index 777d1e1cc..34c796b65 100644 --- a/public/locales/sr/common.json +++ b/public/locales/sr/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/sv/common.json b/public/locales/sv/common.json index e91e6474e..9bb45161c 100644 --- a/public/locales/sv/common.json +++ b/public/locales/sv/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Vänligen vänta" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/te/common.json b/public/locales/te/common.json index e367d409a..f97af7c94 100644 --- a/public/locales/te/common.json +++ b/public/locales/te/common.json @@ -92,7 +92,7 @@ "wanted": "కావలెను", "queued": "క్యూయూఎడ్", "movies": "సినిమాలు", - "missing": "Missing" + "missing": "మిస్సింగ్" }, "lidarr": { "wanted": "కావలెను", @@ -192,11 +192,11 @@ "up": "అప్", "down": "డౌన్", "wait": "దయచేసి వేచి ఉండండి", - "lan": "LAN", + "lan": "లాన్", "wlan": "WLAN", - "devices": "Devices", - "lan_devices": "LAN Devices", - "wlan_devices": "WLAN Devices" + "devices": "పరికరాలు", + "lan_devices": "LAN పరికరాలు", + "wlan_devices": "WLAN పరికరాలు" }, "plex": { "streams": "యాక్టివ్ స్ట్రీమ్‌లు", @@ -207,5 +207,9 @@ "cpu": "సీపియూ", "mem": "MEM", "wait": "దయచేసి వేచి ఉండండి" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/tr/common.json b/public/locales/tr/common.json index 6f4b7d242..13f0086ad 100644 --- a/public/locales/tr/common.json +++ b/public/locales/tr/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json index b00128e80..3f347af24 100644 --- a/public/locales/vi/common.json +++ b/public/locales/vi/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/yue/common.json b/public/locales/yue/common.json index 4f7622b54..cb98c0776 100644 --- a/public/locales/yue/common.json +++ b/public/locales/yue/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json index ec3cc2bfc..da1e4a35e 100644 --- a/public/locales/zh-CN/common.json +++ b/public/locales/zh-CN/common.json @@ -207,5 +207,9 @@ "cpu": "处理器", "mem": "内存", "wait": "请稍等" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/public/locales/zh-Hant/common.json b/public/locales/zh-Hant/common.json index a7a343676..b2a8d99c0 100644 --- a/public/locales/zh-Hant/common.json +++ b/public/locales/zh-Hant/common.json @@ -207,5 +207,9 @@ "cpu": "CPU", "mem": "MEM", "wait": "Please wait" + }, + "homepagesearch": { + "bookmark": "Bookmark", + "service": "Service" } } diff --git a/src/components/quicklaunch.jsx b/src/components/quicklaunch.jsx new file mode 100644 index 000000000..58d15cef2 --- /dev/null +++ b/src/components/quicklaunch.jsx @@ -0,0 +1,156 @@ +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, searchDescriptions}) { + 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" : result.target ?? 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 { + let newResults = servicesAndBookmarks.filter(r => { + 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) { + newResults = newResults.sort((a, b) => b.priority - a.priority); + } + + setResults(newResults); + + if (newResults.length) { + setCurrentItemIndex(0); + } + } + }, [searchString, servicesAndBookmarks, searchDescriptions]); + + + 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]); + + function highlightText(text) { + const parts = text.split(new RegExp(`(${searchString})`, 'gi')); + return {parts.map(part => part.toLowerCase() === searchString.toLowerCase() ? {part} : part)}; + } + + return ( +