diff --git a/src/renderer/components/Footer.tsx b/src/renderer/components/Footer.tsx index d8a2a384f..bf562e800 100644 --- a/src/renderer/components/Footer.tsx +++ b/src/renderer/components/Footer.tsx @@ -10,6 +10,7 @@ import { WithPreferencesProps } from '../containers/withPreferences'; import { gameScaleSpan, getViewName } from '../Util'; import { LangContext } from '../util/lang'; import { WithViewProps } from '@renderer/containers/withView'; +import { GENERAL_VIEW_ID } from '@renderer/store/search/slice'; export type FooterProps = RouteComponentProps & WithViewProps & WithPreferencesProps & WithMainStateProps; @@ -61,7 +62,7 @@ export class Footer extends React.Component { {/* Game Count */}

{`${strings.total}: ${this.props.main.gamesTotal}`}

- {currentLabel && strings.searchResults ? ( + {currentLabel && view.id !== GENERAL_VIEW_ID && strings.searchResults ? ( <>

|

{`${strings.searchResults}: ${gamesTotal > -1 ? gamesTotal : this.context.misc.searching}`}

diff --git a/src/renderer/components/SearchBar.tsx b/src/renderer/components/SearchBar.tsx index ee22e5ee2..a0d49033f 100644 --- a/src/renderer/components/SearchBar.tsx +++ b/src/renderer/components/SearchBar.tsx @@ -7,13 +7,12 @@ import { useView } from '@renderer/hooks/search'; import { forceSearch, setAdvancedFilter, setOrderBy, setOrderReverse, setSearchText } from '@renderer/store/search/slice'; import { ArrowKeyStepper, AutoSizer, List, ListRowProps } from 'react-virtualized-reactv17'; import { AdvancedFilter } from 'flashpoint-launcher'; -import { useContext } from 'react'; +import { useContext, useMemo } from 'react'; import { LangContext } from '@renderer/util/lang'; import { useAppSelector } from '@renderer/hooks/useAppSelector'; +import { getPlatformIconURL } from '@renderer/Util'; -export type SearchBarProps = {}; - -export function SearchBar(props: SearchBarProps) { +export function SearchBar() { const view = useView(); const dispatch = useDispatch(); const [expanded, setExpanded] = React.useState(true); @@ -122,6 +121,32 @@ export function SearchBar(props: SearchBarProps) { const onTogglePlatform = onToggleFactory('platform'); const onClearPlatform = onClearFactory('platform'); + const simpleSelectItems = (values: string[]): SearchableSelectItem[] => { + return values.map(v => ({ + value: v, + orderVal: v, + })); + }; + + const libraryItems = useMemo(() => simpleSelectItems(mainState.libraries), [mainState.libraries]); + const playModeItems = useMemo(() => simpleSelectItems(mainState.suggestions.playMode), [mainState.suggestions.playMode]); + const platformItems = useMemo(() => simpleSelectItems(mainState.suggestions.platforms), [mainState.suggestions.platforms]); + + const platformLabelRenderer = (item: SearchableSelectItem) => { + const platformIcon = getPlatformIconURL(item.value, mainState.logoVersion); + + return ( +
+
+
+ {item.value} +
+
+ ); + }; + return (
@@ -176,7 +201,7 @@ export function SearchBar(props: SearchBarProps) { { window.Shared.preferences.data.useCustomViews && ( @@ -244,17 +270,23 @@ function ThreeStateCheckbox(props: ThreeStateCheckboxProps) { ); } -type SearchableSelectProps = { +type SearchableSelectProps = { title: string; - items: string[]; + items: T[]; selected: string[]; - onToggle: (item: string) => void; + onToggle: (value: string) => void; onClear: () => void; - mapName?: (id: string) => string; + mapName?: (name: string) => string; + labelRenderer?: (item: T, selected: boolean) => JSX.Element; +} + +type SearchableSelectItem = { + value: string; + orderVal: string; } -function SearchableSelect(props: SearchableSelectProps) { - const { title, items, selected, onToggle, onClear, mapName } = props; +function SearchableSelect(props: SearchableSelectProps) { + const { title, items, selected, onToggle, onClear, mapName, labelRenderer } = props; const [expanded, setExpanded] = React.useState(false); const dropdownRef = React.useRef(null); @@ -302,10 +334,11 @@ function SearchableSelect(props: SearchableSelectProps) {
{expanded && ( a.orderVal.localeCompare(b.orderVal))} onToggle={onToggle} selected={selected} mapName={mapName} + labelRenderer={labelRenderer} /> )}
@@ -313,15 +346,17 @@ function SearchableSelect(props: SearchableSelectProps) { ); } -type SearchableSelectDropdownProps = { - items: string[]; +type SearchableSelectDropdownProps = { + items: T[]; selected: string[]; + + labelRenderer?: (item: T, selected: boolean) => JSX.Element; mapName?: (id: string) => string; onToggle: (item: string) => void; } -function SearchableSelectDropdown(props: SearchableSelectDropdownProps) { - const { items, selected, onToggle, mapName } = props; +function SearchableSelectDropdown(props: SearchableSelectDropdownProps) { + const { items, selected, onToggle, mapName, labelRenderer } = props; const inputRef = React.useRef(null); const [search, setSearch] = React.useState(''); @@ -329,9 +364,8 @@ function SearchableSelectDropdown(props: SearchableSelectDropdownProps) { const filteredItems = React.useMemo(() => { const lowerSearch = search.toLowerCase().replace(' ', ''); - return storedItems.filter((item) => item.toLowerCase().replace(' ', '').includes(lowerSearch)); + return storedItems.filter((item) => item.orderVal.toLowerCase().replace(' ', '').includes(lowerSearch)); }, [search, storedItems]); - console.log(filteredItems); // Update the stored items when all selections removed // Too difficult to do this any other way @@ -344,27 +378,46 @@ function SearchableSelectDropdown(props: SearchableSelectDropdownProps) { const rowRenderer = (props: ListRowProps) => { const { style } = props; const item = filteredItems[props.index]; - console.log(filteredItems[0]); - const marked = selected.includes(item); - - return ( -
onToggle(item)} - key={item}> -
- {item ? (mapName ? mapName(item) : item ) : None} + const marked = selected.includes(item.value); + + if (labelRenderer !== undefined) { + return ( +
onToggle(item.value)} + key={item.value}> + {labelRenderer(item, marked)} + { marked && ( +
+ +
+ )}
- { marked && ( -
- + ); + } else { + return ( +
onToggle(item.value)} + key={item.value}> +
+ {item.orderVal ? (mapName ? mapName(item.orderVal) : item.orderVal ) : None}
- )} -
- ); + { marked && ( +
+ +
+ )} +
+ ); + } + + }; React.useEffect(() => { diff --git a/static/window/styles/core.css b/static/window/styles/core.css index 9cf56ea1f..885c198e6 100644 --- a/static/window/styles/core.css +++ b/static/window/styles/core.css @@ -3622,3 +3622,22 @@ body { height: 80%; margin-right: 0.3rem; } + +.dropdown-icon { + height: 1rem; + width: 1rem; + flex: none; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} + +.platform-label-row { + display: flex; + flex-direction: row; + flex-grow: 1; +} + +.platform-label-row > :not(:first-child) { + margin-left: 0.3rem; +}