Compare commits

..

1 Commits

Author SHA1 Message Date
Crowdin Bot
0a83b2100f New Crowdin translations by GitHub Action 2025-09-05 12:13:17 +00:00
14 changed files with 853 additions and 903 deletions

View File

@@ -441,7 +441,6 @@ There are a few optional settings for the Quick Launch feature:
- `showSearchSuggestions`: show search suggestions for the internet search. If this is not specified then the setting will be inherited from the search widget. If it is not specified there either, it will default to false. For custom providers the `suggestionUrl` needs to be set in order for this to work.
- `provider`: search engine provider. If none is specified it will try to use the provider set for the Search Widget, if neither are present then internet search will be disabled.
- `hideVisitURL`: disable detecting and offering an option to open URLs. This is false by default, enabling the feature.
- `mobileButtonPosition`: enables and sets the position of the mobile quicklaunch button. Options are `top-left`, `top-right`, `bottom-left`, `bottom-right`. This is empty by default, disabling the feature.
```yaml
quicklaunch:

View File

@@ -28,7 +28,7 @@ These companies help the Homepage project by providing services, tools, and reso
</div>
<div style="margin-bottom: 16px;">
<a href="https://crowdin.com/project/gethomepage"><img src="https://support.crowdin.com/assets/logos/core-logo/png/crowdin-core-logo-cWhite.png" alt="Crowdin" style="max-width: 100%; height: 64px; display: block;" /></a>
<a href="https://crowdin.com/project/homepage"><img src="https://support.crowdin.com/assets/logos/core-logo/png/crowdin-core-logo-cWhite.png" alt="Crowdin" style="max-width: 100%; height: 64px; display: block;" /></a>
<p>
Crowdin provides the translation platform for the project. Making it easy to translate the project into multiple languages.
</p>

View File

@@ -32,7 +32,7 @@ More detail on configuring service widgets can be found in the [Service Widgets
## Info Widgets
Info widgets are used to display information in the header, often about your system or environment. Info widgets are defined in your `widgets.yaml` file. Here's an example:
Info widgets are used to display information in the header, often about your system or environment. Info widgets are defined your `widgets.yaml` file. Here's an example:
```yaml
- openmeteo:

View File

@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.5.0",
"version": "1.4.6",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",

View File

@@ -276,7 +276,7 @@
"pending": "Afwagtend",
"approved": "Goedgekeur",
"available": "Beskikbaar",
"issues": "Oop Kwessies"
"issues": "Open Issues"
},
"overseerr": {
"pending": "Afwagtend",
@@ -1074,45 +1074,45 @@
"containers": "Houers"
},
"filebrowser": {
"available": "Beskikbaar",
"used": "Gebruik",
"total": "Totaal"
"available": "Available",
"used": "Used",
"total": "Total"
},
"wallos": {
"activeSubscriptions": "Intekeninge",
"thisMonthlyCost": "Hierdie Maand",
"nextMonthlyCost": "Volgende Maand",
"previousMonthlyCost": "Vorige Maand",
"nextRenewingSubscription": "Volgende paaiement"
"activeSubscriptions": "Subscriptions",
"thisMonthlyCost": "This Month",
"nextMonthlyCost": "Next Month",
"previousMonthlyCost": "Prev. Month",
"nextRenewingSubscription": "Next Payment"
},
"unraid": {
"STARTED": "Begin",
"STOPPED": "Gestop",
"NEW_ARRAY": "Nuwe Skikking",
"RECON_DISK": "Rekonstruksie van Skyf",
"DISABLE_DISK": "Skyf Gedeaktiveer",
"SWAP_DSBL": "Ruil Gedeaktiveer",
"INVALID_EXPANSION": "Ongeldige Uitbreiding",
"PARITY_NOT_BIGGEST": "Pariteit nie die grootste nie",
"TOO_MANY_MISSING_DISKS": "Te Veel Ontbrekende Skywe",
"NEW_DISK_TOO_SMALL": "Nuwe Skyf te Klein",
"NO_DATA_DISKS": "Geen Data Skywe",
"notifications": "Kennisgewings",
"STARTED": "Started",
"STOPPED": "Stopped",
"NEW_ARRAY": "New Array",
"RECON_DISK": "Reconstructing Disk",
"DISABLE_DISK": "Disk Disabled",
"SWAP_DSBL": "Swap Disable",
"INVALID_EXPANSION": "Invalid Expansion",
"PARITY_NOT_BIGGEST": "Parity Not Biggest",
"TOO_MANY_MISSING_DISKS": "Too Many Missing Disks",
"NEW_DISK_TOO_SMALL": "New Disk Too Small",
"NO_DATA_DISKS": "No Data Disks",
"notifications": "Notifications",
"status": "Status",
"cpu": "SVE",
"memoryUsed": "Geheue Gebruik",
"memoryAvailable": "Geheue Beskikbaar",
"arrayUsed": "Skikking Gebruik",
"arrayFree": "Skikking Vry",
"poolUsed": "{{pool}} Gebruik",
"poolFree": "{{pool}} Vry"
"cpu": "CPU",
"memoryUsed": "Memory Used",
"memoryAvailable": "Memory Available",
"arrayUsed": "Array Used",
"arrayFree": "Array Free",
"poolUsed": "{{pool}} Used",
"poolFree": "{{pool}} Free"
},
"backrest": {
"num_plans": "Planne",
"num_success_30": "Suksesse",
"num_failure_30": "Mislukkings",
"num_success_latest": "Slaag",
"num_failure_latest": "Mislukking",
"bytes_added_30": "Grepe bygevoeg"
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Failures",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
}
}

View File

@@ -630,9 +630,9 @@
},
"opnsense": {
"cpu": "CPU-Last",
"memory": "RAM aktiv",
"wanUpload": "WAN Up",
"wanDownload": "WAN Down"
"memory": "Aktiver RAM",
"wanUpload": "WAN-Upload",
"wanDownload": "WAN-Download"
},
"moonraker": {
"printer_state": "Druckerstatus",
@@ -786,7 +786,7 @@
"downloadCount": "Warteschlange",
"downloadBytesRemaining": "Verbleibend",
"downloadTotalBytes": "Größe",
"downloadSpeed": "Datenrate"
"downloadSpeed": "Geschwindigkeit"
},
"kavita": {
"seriesCount": "Serien",

File diff suppressed because it is too large Load Diff

View File

@@ -241,16 +241,16 @@
"sonarr": {
"wanted": "Poszukiwane",
"queued": "W kolejce",
"series": "Seriale",
"queue": "Kolejka",
"unknown": "Nieznany"
"series": "Series",
"queue": "Queue",
"unknown": "Unknown"
},
"radarr": {
"wanted": "Poszukiwane",
"wanted": "Wanted",
"missing": "Brakujące",
"queued": "W kolejce",
"movies": "Filmy",
"queue": "Kolejka",
"queued": "Queued",
"movies": "Movies",
"queue": "Queue",
"unknown": "Unknown"
},
"lidarr": {
@@ -273,16 +273,16 @@
"available": "Dostępne"
},
"jellyseerr": {
"pending": "Oczekujące",
"approved": "Zaakceptowane",
"available": "Dostępne",
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Oczekujące",
"pending": "Pending",
"processing": "Przetwarzane",
"approved": "Zaakceptowane",
"available": "Dostępne"
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
@@ -297,8 +297,8 @@
"gravity": "Grawitacja"
},
"adguard": {
"queries": "Zapytania",
"blocked": "Zablokowane",
"queries": "Queries",
"blocked": "Blocked",
"filtered": "Przefiltrowane",
"latency": "Opóźnienia"
},
@@ -313,7 +313,7 @@
"total": "Total"
},
"suwayomi": {
"download": "Pobrano",
"download": "Downloaded",
"nondownload": "Niepobrane",
"read": "Read",
"unread": "Unread",
@@ -367,7 +367,7 @@
"unknown": "Unknown"
},
"navidrome": {
"nothing_streaming": "Brak aktywnych strumieni",
"nothing_streaming": "No Active Streams",
"please_wait": "Proszę czekać"
},
"npm": {
@@ -426,26 +426,26 @@
"unread": "Unread"
},
"authentik": {
"users": "Użytkownicy",
"users": "Users",
"loginsLast24H": "Logowania (24h)",
"failedLoginsLast24H": "Nieudane logowania (24h)"
},
"proxmox": {
"mem": "RAM",
"mem": "MEM",
"cpu": "Procesor",
"lxc": "Kontenery LXC",
"vms": "Maszyn wirtualnych"
},
"glances": {
"cpu": "Procesor",
"load": "Obciążenie",
"load": "Load",
"wait": "Proszę czekać",
"temp": "TEMP.",
"temp": "TEMP",
"_temp": "Temperatura",
"warn": "Ostrzeżenie",
"uptime": "UP",
"total": "Total",
"free": "Wolne",
"free": "Free",
"used": "Used",
"days": "d",
"hours": "h",
@@ -471,57 +471,57 @@
"1-day": "Głównie słoneczny",
"1-night": "Głównie bezchmurny",
"2-day": "Częściowo pochmurnie",
"2-night": "Częściowo pochmurnie",
"2-night": "Partly Cloudy",
"3-day": "Pochmurnie",
"3-night": "Pochmurnie",
"3-night": "Cloudy",
"45-day": "Mgliście",
"45-night": "Mgliście",
"48-day": "Mgliście",
"48-night": "Mgliście",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"51-day": "Lekka mżawka",
"51-night": "Lekka mżawka",
"51-night": "Light Drizzle",
"53-day": "Mżawka",
"53-night": "Mżawka",
"53-night": "Drizzle",
"55-day": "Gęsta mżawka",
"55-night": "Gęsta mżawka",
"55-night": "Heavy Drizzle",
"56-day": "Lekko chłodna mżawka",
"56-night": "Lekko chłodna mżawka",
"56-night": "Light Freezing Drizzle",
"57-day": "Chłodna mżawka",
"57-night": "Chłodna mżawka",
"57-night": "Freezing Drizzle",
"61-day": "Lekki deszcz",
"61-night": "Lekki deszcz",
"61-night": "Light Rain",
"63-day": "Deszcz",
"63-night": "Deszcz",
"63-night": "Rain",
"65-day": "Ciężki deszcz",
"65-night": "Ciężki deszcz",
"65-night": "Heavy Rain",
"66-day": "Mroźny deszcz",
"66-night": "Mroźny deszcz",
"67-day": "Mroźny deszcz",
"67-night": "Mroźny deszcz",
"66-night": "Freezing Rain",
"67-day": "Freezing Rain",
"67-night": "Freezing Rain",
"71-day": "Lekki śnieg",
"71-night": "Lekki śnieg",
"71-night": "Light Snow",
"73-day": "Śnieg",
"73-night": "Śnieg",
"73-night": "Snow",
"75-day": "Ciężki śnieg",
"75-night": "Ciężki śnieg",
"75-night": "Heavy Snow",
"77-day": "Ziarnisty śnieg",
"77-night": "Ziarnisty śnieg",
"77-night": "Snow Grains",
"80-day": "Lekkie opady",
"80-night": "Lekkie opady",
"80-night": "Light Showers",
"81-day": "Opady",
"81-night": "Opady",
"81-night": "Showers",
"82-day": "Ciężkie opady",
"82-night": "Ciężkie opady",
"82-night": "Heavy Showers",
"85-day": "Opady śniegu",
"85-night": "Opady śniegu",
"86-day": "Opady śniegu",
"86-night": "Opady śniegu",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "Burze z piorunami",
"95-night": "Burze z piorunami",
"95-night": "Thunderstorm",
"96-day": "Burza z gradobiciem",
"96-night": "Burza z gradobiciem",
"99-day": "Burza z gradobiciem",
"99-night": "Burza z gradobiciem"
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
},
"homebridge": {
"available_update": "System",

View File

@@ -63,7 +63,7 @@
"wlan_users": "Usuários de WLAN",
"up": "UP",
"down": "Desligado",
"wait": "Por favor, aguarde",
"wait": "Please wait",
"empty_data": "Status do Subsistema desconhecido"
},
"docker": {
@@ -83,7 +83,7 @@
"partial": "Parcial"
},
"ping": {
"error": "Erro",
"error": "Error",
"ping": "Tempo de resposta",
"down": "Inativo",
"up": "Ativo",
@@ -91,11 +91,11 @@
},
"siteMonitor": {
"http_status": "Estado HTTP",
"error": "Erro",
"error": "Error",
"response": "Resposta",
"down": "Inativo",
"up": "Ativo",
"not_available": "Não Disponível"
"down": "Down",
"up": "Up",
"not_available": "Not Available"
},
"emby": {
"playing": "A reproduzir",
@@ -112,7 +112,7 @@
"offline_alt": "Offline",
"online": "Disponível",
"total": "Total",
"unknown": "Desconhecido"
"unknown": "Unknown"
},
"evcc": {
"pv_power": "Produção",
@@ -141,11 +141,11 @@
"connectionStatusDisconnecting": "Desconectando",
"connectionStatusDisconnected": "Desconectado",
"connectionStatusConnected": "Conectado",
"uptime": "Tempo ativo",
"uptime": "Uptime",
"maxDown": "Tempo de inatividade máximo",
"maxUp": "Máx. Acima",
"down": "Inativo",
"up": "Ativo",
"down": "Down",
"up": "Up",
"received": "Recebido",
"sent": "Enviado",
"externalIPAddress": "IP Externo",
@@ -168,10 +168,10 @@
"passes": "Passes"
},
"tautulli": {
"playing": "Tocando",
"transcoding": "Transcodificando",
"bitrate": "Taxa de bits",
"no_active": "Sem Streams Ativos",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"plex_connection_error": "Verifique a conexão do Plex"
},
"omada": {
@@ -189,28 +189,28 @@
"plex": {
"streams": "Streams Ativas",
"albums": "Álbuns",
"movies": "Filmes",
"movies": "Movies",
"tv": "Series de TV"
},
"sabnzbd": {
"rate": "Taxa",
"rate": "Rate",
"queue": "Fila",
"timeleft": "Tempo restante"
},
"rutorrent": {
"active": "Ativo",
"upload": "Carregar",
"download": "Descarregar"
"upload": "Upload",
"download": "Download"
},
"transmission": {
"download": "Descarregar",
"upload": "Carregar",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Descarregar",
"upload": "Carregar",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -223,8 +223,8 @@
"invalid": "Inválido"
},
"deluge": {
"download": "Descarregar",
"upload": "Carregar",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -233,25 +233,25 @@
"cachemissbytes": "Bytes de Falha de Cache"
},
"downloadstation": {
"download": "Descarregar",
"upload": "Carregar",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Desejada",
"queued": "Em fila",
"series": "Séries",
"queue": "Fila",
"unknown": "Desconhecido"
"series": "Series",
"queue": "Queue",
"unknown": "Unknown"
},
"radarr": {
"wanted": "Wanted",
"missing": "Faltando",
"queued": "Em fila",
"movies": "Filmes",
"queue": "Fila",
"unknown": "Desconhecido"
"queued": "Queued",
"movies": "Movies",
"queue": "Queue",
"unknown": "Unknown"
},
"lidarr": {
"wanted": "Wanted",

View File

@@ -276,7 +276,7 @@
"pending": "На чекању",
"approved": "Одобрено",
"available": "Доступно",
"issues": "Отворених питања"
"issues": "Open Issues"
},
"overseerr": {
"pending": "На чекању",
@@ -1108,11 +1108,11 @@
"poolFree": "{{pool}} слободно"
},
"backrest": {
"num_plans": "Планови",
"num_success_30": "Успешно",
"num_failure_30": "Неуспешно",
"num_success_latest": "Успевајући",
"num_failure_latest": "Неуспешно",
"bytes_added_30": "Додати бајтови"
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Failures",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
}
}

View File

@@ -367,7 +367,7 @@
"unknown": "Unknown"
},
"navidrome": {
"nothing_streaming": "",
"nothing_streaming": "No Active Streams",
"please_wait": "请等待"
},
"npm": {

View File

@@ -1,37 +1,21 @@
Babel==2.12.1
backrefs==5.9
cairocffi==1.7.1
CairoSVG==2.7.1
certifi==2023.7.22
cffi==1.17.1
cfgv==3.4.0
charset-normalizer==3.2.0
click==8.1.7
colorama==0.4.6
cssselect2==0.7.0
defusedxml==0.7.1
distlib==0.3.9
filelock==3.17.0
ghp-import==2.1.0
identify==2.6.7
idna==3.4
Jinja2==3.1.2
Markdown==3.4.4
MarkupSafe==2.1.3
mergedeep==1.3.4
mkdocs==1.6.0
mkdocs-get-deps==0.2.0
mkdocs-material==9.6.18
mkdocs==1.6
mkdocs-material==9.5.26
mkdocs-material-extensions==1.3.1
mkdocs-redirects==1.2.1
nodeenv==1.9.1
packaging==23.1
paginate==0.5.6
pathspec==0.11.2
pillow==10.4.0
platformdirs==3.10.0
pre-commit==3.5.0
pycparser==2.22
Pygments==2.16.1
pymdown-extensions==10.3
python-dateutil==2.8.2
@@ -40,8 +24,8 @@ pyyaml_env_tag==0.1
regex==2023.8.8
requests==2.31.0
six==1.16.0
tinycss2==1.4.0
urllib3==2.0.5
virtualenv==20.29.2
watchdog==3.0.0
webencodings==0.5.1
pre-commit==3.5.0
mkdocs-material[imaging]==9.5.26
mkdocs-redirects==1.2.1

View File

@@ -1,21 +1,13 @@
import classNames from "classnames";
import { useTranslation } from "next-i18next";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import { FiSearch } from "react-icons/fi";
import useSWR from "swr";
import { SettingsContext } from "utils/contexts/settings";
import ResolvedIcon from "./resolvedicon";
import { getStoredProvider, searchProviders } from "./widgets/search/search";
const MOBILE_BUTTON_POSITIONS = {
"top-left": "top-4 left-4",
"top-right": "top-4 right-4",
"bottom-left": "bottom-4 left-4",
"bottom-right": "bottom-4 right-4",
};
export default function QuickLaunch({ servicesAndBookmarks, searchString, setSearchString, isOpen, setSearching }) {
export default function QuickLaunch({ servicesAndBookmarks, searchString, setSearchString, isOpen, close }) {
const { t } = useTranslation();
const { settings } = useContext(SettingsContext);
@@ -57,10 +49,6 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
);
}
let mobileButtonPosition = settings.quicklaunch?.mobileButtonPosition
? MOBILE_BUTTON_POSITIONS[settings.quicklaunch.mobileButtonPosition]
: null;
function openCurrentItem(newWindow) {
const result = results[currentItemIndex];
window.open(
@@ -71,13 +59,13 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
}
const closeAndReset = useCallback(() => {
setSearching(false);
close(false);
setTimeout(() => {
setSearchString("");
setCurrentItemIndex(null);
setSearchSuggestions([]);
}, 200); // delay a little for animations
}, [setSearching, setSearchString, setCurrentItemIndex, setSearchSuggestions]);
}, [close, setSearchString, setCurrentItemIndex, setSearchSuggestions]);
function handleSearchChange(event) {
const rawSearchString = event.target.value;
@@ -257,98 +245,86 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
}
return (
<>
<div
className={classNames(
"relative z-40 ease-in-out duration-300 transition-opacity",
hidden && !isOpen && "hidden",
!hidden && isOpen && "opacity-100",
!isOpen && "opacity-0",
)}
role="dialog"
aria-modal="true"
>
<div className="fixed inset-0 bg-gray-500 opacity-50" />
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full min-w-full items-start justify-center text-center">
<dialog className="mt-[10%] mx-auto min-w-[90%] max-w-[90%] md:min-w-[40%] md:max-w-[40%] rounded-md p-0 block font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-50 dark:bg-theme-800">
<input
placeholder="Search"
className={classNames(
results.length > 0 && "rounded-t-md",
results.length === 0 && "rounded-md",
"w-full p-4 m-0 border-0 border-b border-slate-700 focus:border-slate-700 focus:outline-0 focus:ring-0 text-sm md:text-xl text-theme-700 dark:text-theme-200 bg-theme-60 dark:bg-theme-800",
)}
type="text"
autoCorrect="false"
ref={searchField}
value={searchString}
onChange={handleSearchChange}
onKeyDown={handleSearchKeyDown}
/>
{results.length > 0 && (
<ul className="max-h-[60vh] overflow-y-auto m-2">
{results.map((r, i) => (
<li key={[r.name, r.container, r.app, r.href].filter((s) => s).join("-")}>
<button
type="button"
data-index={i}
onMouseEnter={handleItemHover}
onClick={handleItemClick}
onKeyDown={handleItemKeyDown}
className={classNames(
"flex flex-row w-full items-center justify-between rounded-md text-sm md:text-xl py-2 px-4 cursor-pointer text-theme-700 dark:text-theme-200",
i === currentItemIndex && "bg-theme-300/50 dark:bg-theme-700/50",
<div
className={classNames(
"relative z-40 ease-in-out duration-300 transition-opacity",
hidden && !isOpen && "hidden",
!hidden && isOpen && "opacity-100",
!isOpen && "opacity-0",
)}
role="dialog"
aria-modal="true"
>
<div className="fixed inset-0 bg-gray-500 opacity-50" />
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full min-w-full items-start justify-center text-center">
<dialog className="mt-[10%] mx-auto min-w-[90%] max-w-[90%] md:min-w-[40%] md:max-w-[40%] rounded-md p-0 block font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-50 dark:bg-theme-800">
<input
placeholder="Search"
className={classNames(
results.length > 0 && "rounded-t-md",
results.length === 0 && "rounded-md",
"w-full p-4 m-0 border-0 border-b border-slate-700 focus:border-slate-700 focus:outline-0 focus:ring-0 text-sm md:text-xl text-theme-700 dark:text-theme-200 bg-theme-60 dark:bg-theme-800",
)}
type="text"
autoCorrect="false"
ref={searchField}
value={searchString}
onChange={handleSearchChange}
onKeyDown={handleSearchKeyDown}
/>
{results.length > 0 && (
<ul className="max-h-[60vh] overflow-y-auto m-2">
{results.map((r, i) => (
<li key={[r.name, r.container, r.app, r.href].filter((s) => s).join("-")}>
<button
type="button"
data-index={i}
onMouseEnter={handleItemHover}
onClick={handleItemClick}
onKeyDown={handleItemKeyDown}
className={classNames(
"flex flex-row w-full items-center justify-between rounded-md text-sm md:text-xl py-2 px-4 cursor-pointer text-theme-700 dark:text-theme-200",
i === currentItemIndex && "bg-theme-300/50 dark:bg-theme-700/50",
)}
>
<div className="flex flex-row items-center mr-4 pointer-events-none">
{(r.icon || r.abbr) && (
<div className="w-5 text-xs mr-4">
{r.icon && <ResolvedIcon icon={r.icon} />}
{r.abbr && r.abbr}
</div>
)}
>
<div className="flex flex-row items-center mr-4 pointer-events-none">
{(r.icon || r.abbr) && (
<div className="w-5 text-xs mr-4">
{r.icon && <ResolvedIcon icon={r.icon} />}
{r.abbr && r.abbr}
<div className="flex flex-col md:flex-row text-left items-baseline mr-4 pointer-events-none">
{r.type !== "searchSuggestion" && <span className="mr-4">{r.name}</span>}
{r.type === "searchSuggestion" && (
<div className="flex-nowrap">
<span className="whitespace-pre">
{r.name.indexOf(searchString) === 0 ? searchString : ""}
</span>
<span className="whitespace-pre opacity-50">
{r.name.indexOf(searchString) === 0 ? r.name.substring(searchString.length) : r.name}
</span>
</div>
)}
<div className="flex flex-col md:flex-row text-left items-baseline mr-4 pointer-events-none">
{r.type !== "searchSuggestion" && <span className="mr-4">{r.name}</span>}
{r.type === "searchSuggestion" && (
<div className="flex-nowrap">
<span className="whitespace-pre">
{r.name.indexOf(searchString) === 0 ? searchString : ""}
</span>
<span className="whitespace-pre opacity-50">
{r.name.indexOf(searchString) === 0 ? r.name.substring(searchString.length) : r.name}
</span>
</div>
)}
{r.description && (
<span className="text-xs text-theme-600 text-light">
{searchDescriptions && r.priority < 2 ? highlightText(r.description) : r.description}
</span>
)}
</div>
{r.description && (
<span className="text-xs text-theme-600 text-light">
{searchDescriptions && r.priority < 2 ? highlightText(r.description) : r.description}
</span>
)}
</div>
<div className="text-xs text-theme-600 font-bold pointer-events-none">
{t(`quicklaunch.${r.type ? r.type.toLowerCase() : "bookmark"}`)}
</div>
</button>
</li>
))}
</ul>
)}
</dialog>
</div>
</div>
<div className="text-xs text-theme-600 font-bold pointer-events-none">
{t(`quicklaunch.${r.type ? r.type.toLowerCase() : "bookmark"}`)}
</div>
</button>
</li>
))}
</ul>
)}
</dialog>
</div>
</div>
{mobileButtonPosition && (
<button
type="button"
onClick={setSearching.bind(this, !isOpen)}
className={`fixed ${mobileButtonPosition} z-40 p-2 rounded-full sm:hidden text-theme-700 dark:text-theme-200 bg-theme-50 dark:bg-theme-800 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 transition-opacity duration-100`}
style={{ opacity: isOpen ? 0 : 1 }}
>
<FiSearch className="w-4 h-4" />
</button>
)}
</>
</div>
);
}

View File

@@ -432,7 +432,7 @@ function Home({ initialSettings }) {
searchString={searchString}
setSearchString={setSearchString}
isOpen={searching}
setSearching={setSearching}
close={setSearching}
/>
<div
id="information-widgets"
@@ -499,7 +499,6 @@ function Home({ initialSettings }) {
export default function Wrapper({ initialSettings, fallback }) {
const { theme } = useContext(ThemeContext);
const { color } = useContext(ColorContext);
let backgroundImage = "";
let opacity = initialSettings?.backgroundOpacity ?? 0;
let backgroundBlur = false;
@@ -528,22 +527,14 @@ export default function Wrapper({ initialSettings, fallback }) {
html.classList.toggle("dark", theme === "dark");
html.classList.add(theme === "dark" ? "scheme-dark" : "scheme-light");
const desiredThemeClass = `theme-${color || initialSettings.color || "slate"}`;
const themeClassesToRemove = Array.from(html.classList).filter(
(cls) => cls.startsWith("theme-") && cls !== desiredThemeClass,
);
if (themeClassesToRemove.length) {
html.classList.remove(...themeClassesToRemove);
}
if (!html.classList.contains(desiredThemeClass)) {
html.classList.add(desiredThemeClass);
}
html.classList.remove(...Array.from(html.classList).filter((cls) => cls.startsWith("theme-")));
html.classList.add(`theme-${initialSettings.color || "slate"}`);
// Remove any previously applied inline styles
body.style.backgroundImage = "";
body.style.backgroundColor = "";
body.style.backgroundAttachment = "";
}, [backgroundImage, opacity, theme, color, initialSettings.color]);
}, [backgroundImage, opacity, theme, initialSettings.color]);
return (
<>