diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 14fba932..96f72e1b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -89,6 +89,7 @@ "amount_minutes": "{{amount}} minutes", "accuracy": "{{accuracy}}% accuracy", "add_to_library": "Add to library", + "already_in_library": "Already in library", "remove_from_library": "Remove from library", "no_downloads": "No downloads available", "play_time": "Played for {{amount}}", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index 1f6adcd0..22f5b533 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -76,6 +76,7 @@ "amount_minutes": "{{amount}} minutos", "accuracy": "{{accuracy}}% de precisão", "add_to_library": "Adicionar à biblioteca", + "already_in_library": "Já está na biblioteca", "remove_from_library": "Remover da biblioteca", "no_downloads": "Nenhum download disponível", "play_time": "Jogou por {{amount}}", diff --git a/src/renderer/src/pages/catalogue/game-item.scss b/src/renderer/src/pages/catalogue/game-item.scss index f49bcbf8..ec20b4a5 100644 --- a/src/renderer/src/pages/catalogue/game-item.scss +++ b/src/renderer/src/pages/catalogue/game-item.scss @@ -16,6 +16,25 @@ &:hover { background-color: rgba(255, 255, 255, 0.05); + + .game-item__plus-wrapper { + opacity: 1; + pointer-events: auto; + } + } + + &__plus-wrapper { + position: absolute; + top: 8px; + right: 8px; + opacity: 0; + pointer-events: none; + transition: opacity 0.2s ease-in-out; + cursor: pointer; + } + + &__plus-wrapper--added { + opacity: 0.5; } &__cover { diff --git a/src/renderer/src/pages/catalogue/game-item.tsx b/src/renderer/src/pages/catalogue/game-item.tsx index 39f5e6eb..63748710 100644 --- a/src/renderer/src/pages/catalogue/game-item.tsx +++ b/src/renderer/src/pages/catalogue/game-item.tsx @@ -1,13 +1,14 @@ import { Badge } from "@renderer/components"; import { buildGameDetailsPath } from "@renderer/helpers"; -import { useAppSelector, useRepacks } from "@renderer/hooks"; -import { useMemo } from "react"; +import { useAppSelector, useRepacks, useLibrary } from "@renderer/hooks"; +import { useMemo, useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import "./game-item.scss"; import { useTranslation } from "react-i18next"; import { CatalogueSearchResult } from "@types"; -import { QuestionIcon } from "@primer/octicons-react"; +import { QuestionIcon, PlusIcon, CheckIcon } from "@primer/octicons-react"; +import cn from "classnames"; export interface GameItemProps { game: CatalogueSearchResult; @@ -16,7 +17,9 @@ export interface GameItemProps { export function GameItem({ game }: GameItemProps) { const navigate = useNavigate(); - const { i18n } = useTranslation(); + const { i18n, t } = useTranslation("game_details"); + + const language = i18n.language.split("-")[0]; const { steamGenres } = useAppSelector((state) => state.catalogueSearch); @@ -24,7 +27,39 @@ export function GameItem({ game }: GameItemProps) { const repacks = getRepacksForObjectId(game.objectId); - const language = i18n.language.split("-")[0]; + const [isAddingToLibrary, setIsAddingToLibrary] = useState(false); + + const [added, setAdded] = useState(false); + + const { library, updateLibrary } = useLibrary(); + + useEffect(() => { + const exists = library.some( + (libItem) => + libItem.shop === game.shop && libItem.objectId === game.objectId + ); + setAdded(exists); + }, [library, game.shop, game.objectId]); + + const addGameToLibrary = async (event: React.MouseEvent | React.KeyboardEvent) => { + event.stopPropagation(); + if (added || isAddingToLibrary) return; + + setIsAddingToLibrary(true); + + try { + await window.electron.addGameToLibrary( + game.shop, + game.objectId, + game.title + ); + updateLibrary(); + } catch (error) { + console.error(error); + } finally { + setIsAddingToLibrary(false); + } + }; const uniqueRepackers = useMemo(() => { return Array.from(new Set(repacks.map((repack) => repack.repacker))); @@ -85,6 +120,23 @@ export function GameItem({ game }: GameItemProps) { ))} +
{ + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + addGameToLibrary(e); + } + }} + title={added ? t("already_in_library") : t("add_to_library")} + > + {added ? : } +
); }