diff --git a/src/App.js b/src/App.js index 8ef44d7e6..7f7d112b8 100644 --- a/src/App.js +++ b/src/App.js @@ -3,8 +3,8 @@ import React, { useEffect, useCallback, useRef, Suspense } from 'react'; import { Routes, Route, useNavigate, Navigate } from 'react-router-dom'; import { Helmet } from 'react-helmet'; import { useDispatch, useSelector } from 'react-redux'; -import CookieConsent from "react-cookie-consent"; -import { ErrorBoundary } from "react-error-boundary"; +import CookieConsent from 'react-cookie-consent'; +import { ErrorBoundary } from 'react-error-boundary'; import { ThemeProvider } from '@mui/material/styles'; import './App.css'; @@ -14,12 +14,12 @@ import i18n from './i18n.js'; import loadPolyfills from './modules/polyfills.js'; import RemoteControlId from './components/remote-control-id/index.jsx'; -import { fetchTarkovTrackerProgress, setPlayerPosition } from './features/settings/settingsSlice.mjs'; - import { - setConnectionStatus, - enableConnection, -} from './features/sockets/socketsSlice.js'; + fetchTarkovTrackerProgress, + setPlayerPosition, +} from './features/settings/settingsSlice.mjs'; + +import { setConnectionStatus, enableConnection } from './features/sockets/socketsSlice.js'; import useStateWithLocalStorage from './hooks/useStateWithLocalStorage.jsx'; import makeID from './modules/make-id.js'; import WindowFocusHandler from './modules/window-focus-handler.mjs'; @@ -99,17 +99,36 @@ loadPolyfills(); function Fallback({ error, resetErrorBoundary }) { return ( -
-

- Something went wrong. -

-
+
+

Something went wrong.

+
-
{error.message}
+
{error.message}
{error.stack}
- You can or report the issue by - joining our Discord server and - copy/paste the above error and some details in #🐞bugs-issues channel. + You can{' '} + {' '} + or report the issue by joining our{' '} + + Discord + {' '} + server and copy/paste the above error and some details in{' '} + + #🐞bugs-issues + {' '} + channel.
@@ -117,9 +136,7 @@ function Fallback({ error, resetErrorBoundary }) { } function App() { - const connectToId = new URLSearchParams(window.location.search).get( - 'connection', - ); + const connectToId = new URLSearchParams(window.location.search).get('connection'); if (connectToId) { localStorage.setItem('sessionId', JSON.stringify(connectToId)); } @@ -157,14 +174,17 @@ function App() { const scheduleTarkovTrackerUpdate = useCallback(() => { clearInterval(tarkovTrackerProgressInterval.current); - tarkovTrackerProgressInterval.current = setInterval(() => { - if (!tabHasFocus.current) { - // window doesn't have focus, so postpone the update until it does - tarkovTrackerUpdatePending.current = true; - return; - } - updateTarkovTrackerData(); - }, 1000 * 60 * 5); + tarkovTrackerProgressInterval.current = setInterval( + () => { + if (!tabHasFocus.current) { + // window doesn't have focus, so postpone the update until it does + tarkovTrackerUpdatePending.current = true; + return; + } + updateTarkovTrackerData(); + }, + 1000 * 60 * 5, + ); }, [updateTarkovTrackerData]); // monitor window focus for Tarkov Tracker updates @@ -177,27 +197,31 @@ function App() { scheduleTarkovTrackerUpdate(); updateTarkovTrackerData(); }; - + const handleBlur = () => { tabHasFocus.current = false; }; - + window.addEventListener('focus', handleFocus); window.addEventListener('blur', handleBlur); - + // Clean up return () => { - window.removeEventListener('focus', handleFocus); - window.removeEventListener('blur', handleBlur); + window.removeEventListener('focus', handleFocus); + window.removeEventListener('blur', handleBlur); }; - }, [scheduleTarkovTrackerUpdate, updateTarkovTrackerData]); + }, [scheduleTarkovTrackerUpdate, updateTarkovTrackerData]); useEffect(() => { if (!tarkovTrackerProgressInterval.current && useTarkovTracker) { scheduleTarkovTrackerUpdate(); } - if (useTarkovTracker && progressStatus !== 'loading' && retrievedTarkovTrackerToken.current !== tarkovTrackerAPIKey) { + if ( + useTarkovTracker && + progressStatus !== 'loading' && + retrievedTarkovTrackerToken.current !== tarkovTrackerAPIKey + ) { updateTarkovTrackerData(); } @@ -210,7 +234,13 @@ function App() { clearInterval(tarkovTrackerProgressInterval.current); tarkovTrackerProgressInterval.current = false; }; - }, [progressStatus, scheduleTarkovTrackerUpdate, updateTarkovTrackerData, tarkovTrackerAPIKey, useTarkovTracker]); + }, [ + progressStatus, + scheduleTarkovTrackerUpdate, + updateTarkovTrackerData, + tarkovTrackerAPIKey, + useTarkovTracker, + ]); useEffect(() => { const handleDisplayMessage = (rawMessage) => { @@ -320,9 +350,7 @@ function App() { [controlId], ); - const hideRemoteControlId = useSelector( - (state) => state.settings.hideRemoteControl, - ); + const hideRemoteControlId = useSelector((state) => state.settings.hideRemoteControl); const remoteControlSessionElement = hideRemoteControlId ? null : ( } key="suspense-connection-wrapper"> ); - const alternateLangs = supportedLanguages.filter(lang => lang !== i18n.language); + const alternateLangs = supportedLanguages.filter((lang) => lang !== i18n.language); return ( -
- - - {alternateLangs.map((lang) => ( - - ))} - - - - {i18n.t('cookie-consent')} - - - - - } key="suspense-start-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-ammo-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-ammo-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-maps-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-map-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-loot-tier-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-barters-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-items-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-helmets-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-glasses-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-armors-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-backpacks-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-rigs-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-suppressors-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-guns-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-mods-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-pistol-grips-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-barter-items-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-containers-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-grenades-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-headsets-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-keys-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-provisions-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-items-category-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-items-category-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-item-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-bosses-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-boss-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-traders-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - , - remoteControlSessionElement, - ]} - /> - } key="suspense-trader-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-hideout-profit-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-item-tracker-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-debug-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-about-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-api-docs-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-nightbot-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-streamelements-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-moobot-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-api-users-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-hideout-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-wipe-length-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-bitcoin-farm-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-settings-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-control-wrapper"> - - , - ]} - /> - } key="suspense-tasks-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-task-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-achievements-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-players-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-player-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-player-forward-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-converter-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-converter-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - } key="suspense-errorpage-wrapper"> - - , - remoteControlSessionElement, - ]} - /> - - -
-
+
+ + + {alternateLangs.map((lang) => ( + + ))} + + + + {i18n.t('cookie-consent')} + + + + + } key="suspense-start-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-ammo-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-ammo-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-maps-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-map-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-loot-tier-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-barters-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + } key="suspense-items-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + , remoteControlSessionElement]} + /> + } key="suspense-helmets-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-glasses-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-armors-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-backpacks-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , + remoteControlSessionElement, + ]} + /> + } key="suspense-rigs-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + } key="suspense-suppressors-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-barrel-attachments-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + , + remoteControlSessionElement, + ]} + /> + } key="suspense-guns-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-mods-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + } + key="suspense-pistol-grips-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-barter-items-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-containers-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , + remoteControlSessionElement, + ]} + /> + } key="suspense-grenades-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , + remoteControlSessionElement, + ]} + /> + } key="suspense-headsets-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , + remoteControlSessionElement, + ]} + /> + } key="suspense-keys-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + } key="suspense-provisions-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-items-category-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-items-category-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-item-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-bosses-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + } key="suspense-boss-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-traders-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + , remoteControlSessionElement]} + /> + } key="suspense-trader-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-hideout-profit-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-item-tracker-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-debug-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-about-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-api-docs-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-nightbot-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-streamelements-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-moobot-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-api-users-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-hideout-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-wipe-length-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-bitcoin-farm-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-settings-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-control-wrapper"> + + , + ]} + /> + } key="suspense-tasks-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-task-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-achievements-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-players-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-player-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } + key="suspense-player-forward-wrapper" + > + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-converter-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-converter-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + } key="suspense-errorpage-wrapper"> + + , + remoteControlSessionElement, + ]} + /> + + +
+
); } diff --git a/src/components/filter/index.css b/src/components/filter/index.css index 05b3bb79a..6d5cfe002 100644 --- a/src/components/filter/index.css +++ b/src/components/filter/index.css @@ -11,7 +11,8 @@ transform-origin: top; transform: scaleY(0); transition: transform 0.26s ease; - z-index: 1; + /* Raise stacking context so the filter and its controls can appear above page content */ + z-index: 1000; } .filter-wrapper.full-width { @@ -35,7 +36,7 @@ } .filter-wrapper.open { - box-shadow: 0px 5px 15px 5px rgb( from var(--color-black) r g b / 0.70); + box-shadow: 0px 5px 15px 5px rgb(from var(--color-black) r g b / 0.7); overflow: visible; transform: scaleY(1); } @@ -50,7 +51,26 @@ position: fixed; right: 20px; width: 6vh; - z-index: 1; + /* Make sure the toggle button sits above the filter when needed */ + z-index: 1001; +} + +/* Ensure react-select controls and menus in the filter stack above other elements. + Some react-select menus are rendered into a portal (body); adding global rules + here ensures consistent stacking regardless of portal usage. */ +.basic-multi-select .select__control { + z-index: 1002; +} + +.basic-multi-select .select__menu, +.basic-multi-select .select__menu-list { + z-index: 9999; /* match inline portal z-index used in SelectFilter */ +} + +/* Also cover portal-mounted menus which are rendered as siblings under */ +.select__menu, +.select__menu-list { + z-index: 9999 !important; } .filter-toggle-icon-wrapper svg { @@ -66,6 +86,20 @@ width: 400px; } +/* Page-specific tweak: add spacing to filter labels on the barrel attachments page */ +.barrel-attachments-filter .single-filter-label { + padding-right: 12px; +} + +/* Narrow the inner filter content on the Barrel Attachments page so the + page headline can fit on a single line next to the filter controls. */ +.barrel-attachments-filter .filter-content-wrapper { + max-width: 820px; /* reduce from full width to keep headline on one line */ + padding-left: 12px; + padding-right: 12px; + justify-content: flex-end; +} + .single-filter-wrapper-wide .basic-multi-select { flex-grow: 1; } @@ -98,7 +132,15 @@ .basic-multi-select { min-width: 110px; - color: var(--color-gunmetal-dark); + /* Ensure the select's visible text is light on the dark control background */ + color: var(--color-white); +} + +/* Make sure the react-select input, single value and placeholder text are readable */ +.basic-multi-select .select__input, +.basic-multi-select .select__single-value, +.basic-multi-select .select__placeholder { + color: var(--color-white) !important; } .filter-slider-wrapper .MuiSlider-root { @@ -140,7 +182,7 @@ .button-group-button:hover img, .button-group-button.selected img { - opacity: 1.0; + opacity: 1; } .button-group-button:first-child { diff --git a/src/components/filter/index.js b/src/components/filter/index.js index d5f193a4d..f1a00b665 100644 --- a/src/components/filter/index.js +++ b/src/components/filter/index.js @@ -13,13 +13,7 @@ const ConditionalWrapper = ({ condition, wrapper, children }) => { return condition ? wrapper(children) : children; }; -function ButtonGroupFilterButton({ - tooltipContent, - onClick, - content, - selected, - type = 'image', -}) { +function ButtonGroupFilterButton({ tooltipContent, onClick, content, selected, type = 'image' }) { return (