mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-02 16:23:48 +03:00
feat: add sorting to user profile games grid
This commit is contained in:
parent
5705de7d7a
commit
9766059250
@ -1,5 +0,0 @@
|
||||
MAIN_VITE_API_URL=API_URL
|
||||
MAIN_VITE_AUTH_URL=AUTH_URL
|
||||
MAIN_VITE_STEAMGRIDDB_API_KEY=YOUR_API_KEY
|
||||
MAIN_VITE_SENTRY_DSN=YOUR_SENTRY_DSN
|
||||
SENTRY_AUTH_TOKEN=
|
@ -44,7 +44,7 @@
|
||||
"@vanilla-extract/recipes": "^0.5.2",
|
||||
"auto-launch": "^5.0.6",
|
||||
"axios": "^1.7.7",
|
||||
"better-sqlite3": "^11.3.0",
|
||||
"better-sqlite3": "^11.5.0",
|
||||
"check-disk-space": "^3.4.0",
|
||||
"classnames": "^2.5.1",
|
||||
"color": "^4.2.3",
|
||||
|
@ -203,3 +203,44 @@ export const achievementsProgressBar = style({
|
||||
borderRadius: "4px",
|
||||
},
|
||||
});
|
||||
|
||||
export const gridSorting = style({
|
||||
display: "flex", // Usa flexbox para organizar o layout
|
||||
justifyContent: "space-between", // Espaça o label e os botões
|
||||
alignItems: "center", // Centraliza verticalmente
|
||||
marginBottom: `${SPACING_UNIT * 2}px`,
|
||||
});
|
||||
|
||||
export const sortOption = style({
|
||||
transition: "all ease 0.2s",
|
||||
display: "inline-flex", // Altera para inline-flex para alinhar itens no botão
|
||||
alignItems: "center", // Centraliza o ícone e o texto verticalmente
|
||||
gap: "10px", // Define o espaçamento entre o ícone e o texto
|
||||
color: vars.color.body,
|
||||
":hover": {
|
||||
color: "white",
|
||||
cursor: "pointer",
|
||||
},
|
||||
});
|
||||
|
||||
export const selectedSortOption = style({
|
||||
transition: "all ease 0.2s",
|
||||
display: "inline-flex", // Altera para inline-flex para alinhar itens no botão
|
||||
alignItems: "center", // Centraliza o ícone e o texto verticalmente
|
||||
color: "white",
|
||||
gap: "10px", // Define o espaçamento entre o ícone e o texto
|
||||
":hover": {
|
||||
cursor: "pointer",
|
||||
},
|
||||
});
|
||||
|
||||
export const sortOptionsWrapper = style({
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: "5px",
|
||||
});
|
||||
|
||||
export const sortDivider = style({
|
||||
border: `0.5px solid ${vars.color.body}`,
|
||||
margin: "0px 5px"
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { userProfileContext } from "@renderer/context";
|
||||
import { useCallback, useContext, useEffect, useMemo } from "react";
|
||||
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
|
||||
import { ProfileHero } from "../profile-hero/profile-hero";
|
||||
import { useAppDispatch, useFormat } from "@renderer/hooks";
|
||||
import { setHeaderTitle } from "@renderer/features";
|
||||
@ -7,7 +7,12 @@ import { steamUrlBuilder } from "@shared";
|
||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||
|
||||
import * as styles from "./profile-content.css";
|
||||
import { ClockIcon, TelescopeIcon, TrophyIcon } from "@primer/octicons-react";
|
||||
import {
|
||||
ClockIcon,
|
||||
TelescopeIcon,
|
||||
TrophyIcon,
|
||||
HistoryIcon,
|
||||
} from "@primer/octicons-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { LockedProfile } from "./locked-profile";
|
||||
@ -21,6 +26,7 @@ import {
|
||||
formatDownloadProgress,
|
||||
} from "@renderer/helpers";
|
||||
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
|
||||
import { sortBy } from "lodash-es";
|
||||
|
||||
export function ProfileContent() {
|
||||
const { userProfile, isMe, userStats } = useContext(userProfileContext);
|
||||
@ -29,6 +35,8 @@ export function ProfileContent() {
|
||||
|
||||
const { t } = useTranslation("user_profile");
|
||||
|
||||
const [sortOption, setSortOption] = useState("lastPlayed"); // Estado para o critério de ordenação
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setHeaderTitle(""));
|
||||
|
||||
@ -78,6 +86,25 @@ export function ProfileContent() {
|
||||
[numberFormatter, t]
|
||||
);
|
||||
|
||||
const sortGames = (games) => {
|
||||
if (sortOption === "playtime") {
|
||||
return sortBy(games, (game) => -game.playTimeInSeconds);
|
||||
} else if (sortOption === "achievements") {
|
||||
return sortBy(games, (game) => {
|
||||
return game.achievementCount > 0
|
||||
? -(game.unlockedAchievementCount / game.achievementCount)
|
||||
: 0;
|
||||
});
|
||||
} else if (sortOption === "lastPlayed") {
|
||||
return sortBy(games, (game) => {
|
||||
return game.lastTimePlayed
|
||||
? -new Date(game.lastTimePlayed).getTime()
|
||||
: 0;
|
||||
});
|
||||
}
|
||||
return games;
|
||||
};
|
||||
|
||||
const content = useMemo(() => {
|
||||
if (!userProfile) return null;
|
||||
|
||||
@ -93,6 +120,8 @@ export function ProfileContent() {
|
||||
|
||||
const shouldShowRightContent = hasGames || userProfile.friends.length > 0;
|
||||
|
||||
const sortedGames = sortGames(userProfile.libraryGames || []); // Ordena os jogos conforme o critério
|
||||
|
||||
return (
|
||||
<section
|
||||
style={{
|
||||
@ -122,8 +151,51 @@ export function ProfileContent() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.gridSorting}>
|
||||
<div>
|
||||
<label htmlFor="sort-options">Ordenar por: </label>
|
||||
</div>
|
||||
<div className={styles.sortOptionsWrapper}>
|
||||
<button
|
||||
className={`${sortOption === "lastPlayed" ? styles.selectedSortOption : styles.sortOption}`}
|
||||
onClick={() => setSortOption("lastPlayed")}
|
||||
onKeyDown={(e) =>
|
||||
e.key === "Enter" && setSortOption("lastPlayed")
|
||||
} // Add keyboard support
|
||||
tabIndex={0} // Optional if you keep using <span>
|
||||
>
|
||||
<HistoryIcon size={14} />
|
||||
Jogados recentemente
|
||||
</button>
|
||||
<div className={styles.sortDivider} />
|
||||
<button
|
||||
className={`${sortOption === "playtime" ? styles.selectedSortOption : styles.sortOption}`}
|
||||
onClick={() => setSortOption("playtime")}
|
||||
onKeyDown={(e) =>
|
||||
e.key === "Enter" && setSortOption("playtime")
|
||||
} // Add keyboard support
|
||||
tabIndex={0} // Optional if you keep using <span>
|
||||
>
|
||||
<ClockIcon size={14} />
|
||||
Tempo jogado
|
||||
</button>
|
||||
<div className={styles.sortDivider} />
|
||||
<button
|
||||
className={`${sortOption === "achievements" ? styles.selectedSortOption : styles.sortOption}`}
|
||||
onClick={() => setSortOption("achievements")}
|
||||
onKeyDown={(e) =>
|
||||
e.key === "Enter" && setSortOption("achievements")
|
||||
} // Add keyboard support
|
||||
tabIndex={0} // Optional if you keep using <span>
|
||||
>
|
||||
<TrophyIcon size={14} />
|
||||
Conquistas obtidas
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul className={styles.gamesGrid}>
|
||||
{userProfile?.libraryGames?.map((game) => (
|
||||
{sortedGames.map((game) => (
|
||||
<li
|
||||
key={game.objectId}
|
||||
style={{
|
||||
@ -261,6 +333,7 @@ export function ProfileContent() {
|
||||
t,
|
||||
formatPlayTime,
|
||||
navigate,
|
||||
sortOption,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
@ -3255,10 +3255,10 @@ bep53-range@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/bep53-range/-/bep53-range-2.0.0.tgz#a1770475661b4b814c4359e4b66f7cbd88de2b10"
|
||||
integrity sha512-sMm2sV5PRs0YOVk0LTKtjuIprVzxgTQUsrGX/7Yph2Rm4FO2Fqqtq7hNjsOB5xezM4v4+5rljCgK++UeQJZguA==
|
||||
|
||||
better-sqlite3@^11.3.0:
|
||||
version "11.3.0"
|
||||
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.3.0.tgz#f10b32ddff665c33176d148e707bd1e57dfd0284"
|
||||
integrity sha512-iHt9j8NPYF3oKCNOO5ZI4JwThjt3Z6J6XrcwG85VNMVzv1ByqrHWv5VILEbCMFWDsoHhXvQ7oC8vgRXFAKgl9w==
|
||||
better-sqlite3@^11.5.0:
|
||||
version "11.5.0"
|
||||
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.5.0.tgz#58faa51e02845a578dd154f0083487132ead0695"
|
||||
integrity sha512-e/6eggfOutzoK0JWiU36jsisdWoHOfN9iWiW/SieKvb7SAa6aGNmBM/UKyp+/wWSXpLlWNN8tCPwoDNPhzUvuQ==
|
||||
dependencies:
|
||||
bindings "^1.5.0"
|
||||
prebuild-install "^7.1.1"
|
||||
|
Loading…
Reference in New Issue
Block a user