From 7d686eb1b2599e298dcac6ae5107d0dc86ae8229 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 3 Jun 2023 14:36:01 -0300 Subject: [PATCH 1/3] Some fixes in search autocomplete --- .../components/UI/SearchBar/index.css | 68 ----------------- .../components/UI/SearchBar/index.scss | 73 +++++++++++++++++++ .../components/UI/SearchBar/index.tsx | 60 ++++++--------- 3 files changed, 96 insertions(+), 105 deletions(-) delete mode 100644 src/frontend/components/UI/SearchBar/index.css create mode 100644 src/frontend/components/UI/SearchBar/index.scss diff --git a/src/frontend/components/UI/SearchBar/index.css b/src/frontend/components/UI/SearchBar/index.css deleted file mode 100644 index b807bbc118..0000000000 --- a/src/frontend/components/UI/SearchBar/index.css +++ /dev/null @@ -1,68 +0,0 @@ -.SearchBar { - grid-area: search; - width: 100%; - position: relative; - display: inline-flex; - background: var(--search-bar-background, var(--input-background)); - border-radius: var(--space-md); - padding: var(--space-xs); -} - -.SearchBar:focus-within { - box-shadow: 0px 0px 0px 3px var(--search-bar-border, var(--input-backgroundd)); -} - -.autoComplete { - position: absolute; - top: 75%; - max-height: 200px; - width: 100%; - background-color: var(--input-background); - overflow: auto; - list-style: none; - margin: -2px -8px; - display: none; - padding: var(--space-xs) var(--space-md); - text-align: left; - overflow-x: hidden; - z-index: 1; - border-bottom-left-radius: var(--space-md); - border-bottom-right-radius: var(--space-md); -} - -.SearchBar:focus-within ul.autoComplete { - display: block; -} - -li { - padding: 2px 0px; -} - -.autoComplete li:hover { - background-color: var(--accent); - color: var(--background); -} - -.searchButton { - padding: var(--space-2xs) var(--space-2xs) 0 var(--space-2xs); -} - -.clearSearchButton { - padding-right: var(--space-md); - transition: color 250ms; - background: transparent; - border: none; - color: var(--text-secondary); -} - -.searchBarInput { - width: 100%; - appearance: none; - background: transparent; - font: var(--font-secondary-bold); - color: var(--text-secondary); - padding: 0 var(--space-lg); - border: none; - outline: none; - transition: color 250ms; -} diff --git a/src/frontend/components/UI/SearchBar/index.scss b/src/frontend/components/UI/SearchBar/index.scss new file mode 100644 index 0000000000..47e1752a92 --- /dev/null +++ b/src/frontend/components/UI/SearchBar/index.scss @@ -0,0 +1,73 @@ +.SearchBar { + grid-area: search; + width: 100%; + position: relative; + display: inline-flex; + background: var(--search-bar-background, var(--input-background)); + border-radius: var(--space-md); + padding: var(--space-xs); + + &:focus-within { + box-shadow: 0px 0px 0px 3px + var(--search-bar-border, var(--input-backgroundd)); + } + + .autoComplete { + position: absolute; + top: 75%; + max-height: 200px; + width: 100%; + background-color: var(--input-background); + overflow: auto; + list-style: none; + margin: -2px -8px; + display: none; + padding: var(--space-xs) var(--space-md); + text-align: left; + overflow-x: hidden; + z-index: 1; + border-bottom-left-radius: var(--space-md); + border-bottom-right-radius: var(--space-md); + + li { + padding: 2px 0px; + + span { + opacity: 0.3; + } + + &:hover { + background-color: var(--accent); + color: var(--background); + } + } + } + + &:focus-within ul.autoComplete { + display: block; + } + + .searchButton { + padding: var(--space-2xs) var(--space-2xs) 0 var(--space-2xs); + } + + .clearSearchButton { + padding-right: var(--space-md); + transition: color 250ms; + background: transparent; + border: none; + color: var(--text-secondary); + } + + .searchBarInput { + width: 100%; + appearance: none; + background: transparent; + font: var(--font-secondary-bold); + color: var(--text-secondary); + padding: 0 var(--space-lg); + border: none; + outline: none; + transition: color 250ms; + } +} diff --git a/src/frontend/components/UI/SearchBar/index.tsx b/src/frontend/components/UI/SearchBar/index.tsx index 36af038e6b..f1f9b1242c 100644 --- a/src/frontend/components/UI/SearchBar/index.tsx +++ b/src/frontend/components/UI/SearchBar/index.tsx @@ -9,7 +9,7 @@ import React, { import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom' import ContextProvider from 'frontend/state/ContextProvider' -import './index.css' +import './index.scss' import { faXmark } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { GameInfo } from '../../../../common/types' @@ -19,6 +19,11 @@ function fixFilter(text: string) { return text.replaceAll(regex, '') } +const RUNNER_TO_STORE = { + legendary: 'Epic', + gog: 'GOG' +} + export default React.memo(function SearchBar() { const { handleSearch, filterText, epic, gog, sideloadedLibrary } = useContext(ContextProvider) @@ -30,18 +35,20 @@ export default React.memo(function SearchBar() { const list = useMemo(() => { // Set can't handle spread of undefined. Leading to // TypeError. If undefined we just pass empty array. - const library = new Set( + return new Set( [ ...(epic.library ?? []), ...(gog.library ?? []), ...(sideloadedLibrary ?? []) ] .filter(Boolean) - .map((g) => g.title) - .sort() - ) - return [...library].filter((i) => - new RegExp(fixFilter(filterText), 'i').test(i) + .filter((el) => { + return ( + !el.install.is_dlc && + new RegExp(fixFilter(filterText), 'i').test(el.title) + ) + }) + .sort((g1, g2) => (g1.title < g2.title ? -1 : 1)) ) }, [epic.library, gog.library, filterText]) @@ -70,36 +77,17 @@ export default React.memo(function SearchBar() { } }, [input]) - const handleClick = (title: string) => { + const handleClick = (game: GameInfo) => { handleSearch('') if (input.current) { input.current.value = '' - const game: GameInfo | undefined = getGameInfoByAppTitle(title) - - if (game !== undefined) { - navigate(`/gamepage/${game.runner}/${game.app_name}`, { - state: { gameInfo: game } - }) - } + navigate(`/gamepage/${game.runner}/${game.app_name}`, { + state: { gameInfo: game } + }) } } - const getGameInfoByAppTitle = (title: string) => { - return ( - getGameInfoByAppTitleAndLibrary(epic.library, title) || - getGameInfoByAppTitleAndLibrary(gog.library, title) || - getGameInfoByAppTitleAndLibrary(sideloadedLibrary, title) - ) - } - - const getGameInfoByAppTitleAndLibrary = ( - library: GameInfo[], - title: string - ) => { - return library.filter((g: GameInfo) => g.title === title).at(0) - } - return (
@@ -118,13 +106,11 @@ export default React.memo(function SearchBar() { {filterText.length > 0 && ( <>
    - {list.length > 0 && - list.map((title, i) => ( -
  • handleClick(e.currentTarget.innerText)} - key={i} - > - {title} + {list.size > 0 && + [...list].map((game) => ( +
  • handleClick(game)} key={game.app_name}> + {game.title}{' '} + ({RUNNER_TO_STORE[game.runner] || game.runner})
  • ))}
From 56c96318b2c5c99fe47a5989e7d269b02c0bf132 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 3 Jun 2023 14:42:52 -0300 Subject: [PATCH 2/3] Don't use a Set since elements are already unique --- .../components/UI/SearchBar/index.tsx | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/frontend/components/UI/SearchBar/index.tsx b/src/frontend/components/UI/SearchBar/index.tsx index f1f9b1242c..2f73ebe3b5 100644 --- a/src/frontend/components/UI/SearchBar/index.tsx +++ b/src/frontend/components/UI/SearchBar/index.tsx @@ -35,21 +35,19 @@ export default React.memo(function SearchBar() { const list = useMemo(() => { // Set can't handle spread of undefined. Leading to // TypeError. If undefined we just pass empty array. - return new Set( - [ - ...(epic.library ?? []), - ...(gog.library ?? []), - ...(sideloadedLibrary ?? []) - ] - .filter(Boolean) - .filter((el) => { - return ( - !el.install.is_dlc && - new RegExp(fixFilter(filterText), 'i').test(el.title) - ) - }) - .sort((g1, g2) => (g1.title < g2.title ? -1 : 1)) - ) + return [ + ...(epic.library ?? []), + ...(gog.library ?? []), + ...(sideloadedLibrary ?? []) + ] + .filter(Boolean) + .filter((el) => { + return ( + !el.install.is_dlc && + new RegExp(fixFilter(filterText), 'i').test(el.title) + ) + }) + .sort((g1, g2) => (g1.title < g2.title ? -1 : 1)) }, [epic.library, gog.library, filterText]) // we have to use an event listener instead of the react @@ -106,8 +104,8 @@ export default React.memo(function SearchBar() { {filterText.length > 0 && ( <>
    - {list.size > 0 && - [...list].map((game) => ( + {list.length > 0 && + list.map((game) => (
  • handleClick(game)} key={game.app_name}> {game.title}{' '} ({RUNNER_TO_STORE[game.runner] || game.runner}) From a61ab234396185833b290d15a2298a5d04ebc810 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Fri, 9 Jun 2023 22:17:03 -0300 Subject: [PATCH 3/3] Remove comment [skip ci] --- src/frontend/components/UI/SearchBar/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/frontend/components/UI/SearchBar/index.tsx b/src/frontend/components/UI/SearchBar/index.tsx index 2f73ebe3b5..4492114aa9 100644 --- a/src/frontend/components/UI/SearchBar/index.tsx +++ b/src/frontend/components/UI/SearchBar/index.tsx @@ -33,8 +33,6 @@ export default React.memo(function SearchBar() { const input = useRef(null) const list = useMemo(() => { - // Set can't handle spread of undefined. Leading to - // TypeError. If undefined we just pass empty array. return [ ...(epic.library ?? []), ...(gog.library ?? []),