diff --git a/gameyfin/src/main/frontend/components/general/SearchBar.tsx b/gameyfin/src/main/frontend/components/general/SearchBar.tsx new file mode 100644 index 0000000..bc43d05 --- /dev/null +++ b/gameyfin/src/main/frontend/components/general/SearchBar.tsx @@ -0,0 +1,79 @@ +import {Autocomplete, AutocompleteItem} from "@heroui/react"; +import {CaretRight, MagnifyingGlass} from "@phosphor-icons/react"; +import {useSnapshot} from "valtio/react"; +import {gameState} from "Frontend/state/GameState"; +import GameDto from "Frontend/generated/de/grimsi/gameyfin/games/dto/GameDto"; +import {useNavigate} from "react-router"; +import {Key, KeyboardEvent, useState} from "react"; +import {GameCover} from "Frontend/components/general/covers/GameCover"; + +export default function SearchBar() { + + const navigate = useNavigate(); + const state = useSnapshot(gameState); + const games = state.games as GameDto[]; + + const [selectedId, setSelectedId] = useState(); + + function handleKeyDown(event: KeyboardEvent) { + if (event.key === "Enter") { + event.preventDefault(); + navigate("/game/" + selectedId); + } + } + + function updateSelectedId(key: Key | null) { + if (key === null) return; + setSelectedId(key as number); + } + + return } + onSelectionChange={updateSelectedId} + onKeyDown={handleKeyDown} + isVirtualized={true} + maxListboxHeight={300} + itemHeight={91} // 75px (cover) + 16px (margin top/bottom) = 91px + > + {(item) => ( + navigate("/game/" + item.id)}> +
+ +
+

{item.title} ({item.release && new Date(item.release).getFullYear()})

+

{item.developers && [...item.developers].sort().join(" / ")}

+
+ +
+
+ )} +
+} \ No newline at end of file diff --git a/gameyfin/src/main/frontend/views/MainLayout.tsx b/gameyfin/src/main/frontend/views/MainLayout.tsx index fc56bd5..ed4390f 100644 --- a/gameyfin/src/main/frontend/views/MainLayout.tsx +++ b/gameyfin/src/main/frontend/views/MainLayout.tsx @@ -10,6 +10,7 @@ import {Heart} from "@phosphor-icons/react"; import Confetti, {ConfettiProps} from "react-confetti-boom"; import {useTheme} from "next-themes"; import {UserPreferenceService} from "Frontend/util/user-preference-service"; +import SearchBar from "Frontend/components/general/SearchBar"; export default function MainLayout() { const navigate = useNavigate(); @@ -57,9 +58,14 @@ export default function MainLayout() { {isExploding ? : <>} - navigate('/')}> - + +
navigate('/')}> + +
+ + + {auth.state.user?.emailConfirmed === false ? diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/libraries/LibraryService.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/libraries/LibraryService.kt index 3a88c37..6da7bae 100644 --- a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/libraries/LibraryService.kt +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/libraries/LibraryService.kt @@ -75,9 +75,10 @@ class LibraryService( // Update only non-null fields libraryUpdateDto.name?.let { existingLibrary.name = it } libraryUpdateDto.directories?.let { - existingLibrary.directories = it - .map { d -> DirectoryMapping(internalPath = d.internalPath, externalPath = d.externalPath) } - .toMutableList() + existingLibrary.directories.clear() + existingLibrary.directories.addAll( + it.map { d -> DirectoryMapping(internalPath = d.internalPath, externalPath = d.externalPath) } + ) } val updatedLibrary = libraryRepository.save(existingLibrary)