Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add sorting to user profile games grid #1154

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .env.example

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
});
79 changes: 76 additions & 3 deletions src/renderer/src/pages/profile/profile-content/profile-content.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
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";
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";
Expand All @@ -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);
Expand All @@ -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(""));

Expand Down Expand Up @@ -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;

Expand All @@ -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={{
Expand Down Expand Up @@ -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={{
Expand Down Expand Up @@ -261,6 +333,7 @@ export function ProfileContent() {
t,
formatPlayTime,
navigate,
sortOption,
]);

return (
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading