diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index c0d2d545..f9a683bf 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -46,8 +46,15 @@ "checking_files": "Checking {{title}} files… ({{percentage}} complete)" }, "catalogue": { - "next_page": "Next page", - "previous_page": "Previous page" + "search": "Filter…", + "developers": "Developers", + "genres": "Genres", + "tags": "Tags", + "publishers": "Publishers", + "download_sources": "Download sources", + "result_count": "{{resultCount}} results", + "filter_count": "{{filterCount}} available", + "clear_filters": "Clear {{filterCount}} selected" }, "game_details": { "open_download_options": "Open download options", diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json index a9261c9d..b3dd42f8 100644 --- a/src/locales/es/translation.json +++ b/src/locales/es/translation.json @@ -46,8 +46,15 @@ "checking_files": "Verificando archivos de {{title}}… ({{percentage}} completado)" }, "catalogue": { - "next_page": "Siguiente página", - "previous_page": "Pagina anterior" + "search": "Filtrar…", + "developers": "Desarrolladores", + "genres": "Géneros", + "tags": "Marcadores", + "publishers": "Distribuidoras", + "download_sources": "Fuentes de descarga", + "result_count": "{{resultCount}} resultados", + "filter_count": "{{filterCount}} disponibles", + "clear_filters": "Limpiar {{filterCount}} seleccionados" }, "game_details": { "open_download_options": "Ver opciones de descargas", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index de33fd14..46f7e70f 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -284,11 +284,15 @@ "instructions": "Verifique a forma correta de instalar algum deles no seu distro Linux, garantindo assim a execução normal do jogo" }, "catalogue": { - "search": "Pesquisar…", + "search": "Filtrar…", "developers": "Desenvolvedores", "genres": "Gêneros", - "tags": "Tags", - "download_sources": "Fontes de download" + "tags": "Marcadores", + "publishers": "Distribuidoras", + "download_sources": "Fontes de download", + "result_count": "{{resultCount}} resultados", + "filter_count": "{{filterCount}} disponíveis", + "clear_filters": "Limpar {{filterCount}} selecionados" }, "modal": { "close": "Botão de fechar" diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json index 81b5c890..741f5e16 100644 --- a/src/locales/ru/translation.json +++ b/src/locales/ru/translation.json @@ -46,8 +46,15 @@ "checking_files": "Проверка файлов {{title}}… ({{percentage}} завершено)" }, "catalogue": { - "next_page": "Следующая страница", - "previous_page": "Предыдущая страница" + "search": "Фильтр…", + "developers": "Разработчики", + "genres": "Жанры", + "tags": "Маркеры", + "publishers": "Издательства", + "download_sources": "Источники загрузки", + "result_count": "{{resultCount}} результатов", + "filter_count": "{{filterCount}} доступных", + "clear_filters": "Очистить {{filterCount}} выбранных" }, "game_details": { "open_download_options": "Открыть источники", diff --git a/src/renderer/src/features/catalogue-search.ts b/src/renderer/src/features/catalogue-search.ts index 95fccb29..ad6ae3f3 100644 --- a/src/renderer/src/features/catalogue-search.ts +++ b/src/renderer/src/features/catalogue-search.ts @@ -6,6 +6,8 @@ import type { CatalogueSearchPayload } from "@types"; export interface CatalogueSearchState { filters: CatalogueSearchPayload; page: number; + steamUserTags: Record>; + steamGenres: Record; } const initialState: CatalogueSearchState = { @@ -17,6 +19,8 @@ const initialState: CatalogueSearchState = { genres: [], developers: [], }, + steamUserTags: {}, + steamGenres: {}, page: 1, }; @@ -41,8 +45,23 @@ export const catalogueSearchSlice = createSlice({ clearPage: (state) => { state.page = initialState.page; }, + setTags: ( + state, + action: PayloadAction>> + ) => { + state.steamUserTags = action.payload; + }, + setGenres: (state, action: PayloadAction>) => { + state.steamGenres = action.payload; + }, }, }); -export const { setFilters, clearFilters, setPage, clearPage } = - catalogueSearchSlice.actions; +export const { + setFilters, + clearFilters, + setPage, + clearPage, + setTags, + setGenres, +} = catalogueSearchSlice.actions; diff --git a/src/renderer/src/hooks/use-catalogue.ts b/src/renderer/src/hooks/use-catalogue.ts index 9c774e83..1d0aeb57 100644 --- a/src/renderer/src/hooks/use-catalogue.ts +++ b/src/renderer/src/hooks/use-catalogue.ts @@ -1,30 +1,29 @@ import axios from "axios"; import { useCallback, useEffect, useState } from "react"; +import { useAppDispatch } from "./redux"; +import { setGenres, setTags } from "@renderer/features"; export const externalResourcesInstance = axios.create({ baseURL: import.meta.env.RENDERER_VITE_EXTERNAL_RESOURCES_URL, }); export function useCatalogue() { - const [steamGenres, setSteamGenres] = useState>({}); - const [steamUserTags, setSteamUserTags] = useState< - Record> - >({}); + const dispatch = useAppDispatch(); const [steamPublishers, setSteamPublishers] = useState([]); const [steamDevelopers, setSteamDevelopers] = useState([]); const getSteamUserTags = useCallback(() => { externalResourcesInstance.get("/steam-user-tags.json").then((response) => { - setSteamUserTags(response.data); + dispatch(setTags(response.data)); }); - }, []); + }, [dispatch]); const getSteamGenres = useCallback(() => { externalResourcesInstance.get("/steam-genres.json").then((response) => { - setSteamGenres(response.data); + dispatch(setGenres(response.data)); }); - }, []); + }, [dispatch]); const getSteamPublishers = useCallback(() => { externalResourcesInstance.get("/steam-publishers.json").then((response) => { @@ -50,5 +49,5 @@ export function useCatalogue() { getSteamDevelopers, ]); - return { steamGenres, steamUserTags, steamPublishers, steamDevelopers }; + return { steamPublishers, steamDevelopers }; } diff --git a/src/renderer/src/pages/catalogue/catalogue.scss b/src/renderer/src/pages/catalogue/catalogue.scss index 18cc18be..701652df 100644 --- a/src/renderer/src/pages/catalogue/catalogue.scss +++ b/src/renderer/src/pages/catalogue/catalogue.scss @@ -1,11 +1,13 @@ @use "../../scss/globals.scss"; .catalogue { + overflow-y: auto; display: flex; flex-direction: column; gap: calc(globals.$spacing-unit * 2); width: 100%; padding: 16px; + scroll-behavior: smooth; &__filters-container { width: 270px; diff --git a/src/renderer/src/pages/catalogue/catalogue.tsx b/src/renderer/src/pages/catalogue/catalogue.tsx index eb51f856..524b3c25 100644 --- a/src/renderer/src/pages/catalogue/catalogue.tsx +++ b/src/renderer/src/pages/catalogue/catalogue.tsx @@ -33,9 +33,13 @@ const PAGE_SIZE = 20; export default function Catalogue() { const abortControllerRef = useRef(null); + const cataloguePageRef = useRef(null); - const { steamGenres, steamUserTags, steamDevelopers, steamPublishers } = - useCatalogue(); + const { steamDevelopers, steamPublishers } = useCatalogue(); + + const { steamGenres, steamUserTags } = useAppSelector( + (state) => state.catalogueSearch + ); const [downloadSources, setDownloadSources] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -128,7 +132,7 @@ export default function Catalogue() { ...filters.tags.map((tag) => ({ label: Object.keys(steamUserTags[language]).find( (key) => steamUserTags[language][key] === tag - ) as string, + ), orbColor: filterCategoryColors.tags, key: "tags", value: tag, @@ -214,7 +218,7 @@ export default function Catalogue() { ]); return ( -
+
(
  • { dispatch( @@ -298,12 +302,21 @@ export default function Catalogue() { marginTop: 16, }} > - {formatNumber(itemsCount)} resultados + + {t("result_count", { + resultCount: formatNumber(itemsCount), + })} + dispatch(setPage(page))} + onPageChange={(page) => { + dispatch(setPage(page)); + if (cataloguePageRef.current) { + cataloguePageRef.current.scrollTop = 0; + } + }} />
  • diff --git a/src/renderer/src/pages/catalogue/filter-section.tsx b/src/renderer/src/pages/catalogue/filter-section.tsx index 2e238f81..0569ba9d 100644 --- a/src/renderer/src/pages/catalogue/filter-section.tsx +++ b/src/renderer/src/pages/catalogue/filter-section.tsx @@ -3,6 +3,8 @@ import { useFormat } from "@renderer/hooks"; import { useCallback, useMemo, useState } from "react"; import List from "rc-virtual-list"; +import { vars } from "@renderer/theme.css"; +import { useTranslation } from "react-i18next"; export interface FilterSectionProps { title: string; @@ -24,6 +26,7 @@ export function FilterSection({ onClear, }: FilterSectionProps) { const [search, setSearch] = useState(""); + const { t } = useTranslation("catalogue"); const filteredItems = useMemo(() => { if (search.length > 0) { @@ -64,7 +67,6 @@ export function FilterSection({ style={{ fontSize: 16, fontWeight: 500, - color: "#fff", }} > {title} @@ -78,22 +80,26 @@ export function FilterSection({ fontSize: 12, marginBottom: 12, display: "block", - color: "#fff", + color: vars.color.body, cursor: "pointer", textDecoration: "underline", }} onClick={onClear} > - Limpar {formatNumber(selectedItemsCount)} selecionados + {t("clear_filters", { + filterCount: formatNumber(selectedItemsCount), + })} ) : ( - {formatNumber(items.length)} disponíveis + {t("filter_count", { + filterCount: formatNumber(items.length), + })} )} onSearch(e.target.value)} value={search} containerProps={{ style: { marginBottom: 16 } }}