From 5496df327e5a15fdf22e275088eee17a8a384901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lu=C3=ADs?= Date: Sun, 14 Apr 2024 20:35:05 -0300 Subject: [PATCH 1/6] feat: add a loading skeleton to game details page --- .../game-details/game-details-skeleton.tsx | 71 ++++++ .../pages/game-details/game-details.tsx | 221 +++++++++--------- 2 files changed, 188 insertions(+), 104 deletions(-) create mode 100644 src/renderer/pages/game-details/game-details-skeleton.tsx diff --git a/src/renderer/pages/game-details/game-details-skeleton.tsx b/src/renderer/pages/game-details/game-details-skeleton.tsx new file mode 100644 index 000000000..209ee7b81 --- /dev/null +++ b/src/renderer/pages/game-details/game-details-skeleton.tsx @@ -0,0 +1,71 @@ +import Skeleton from "react-loading-skeleton"; + +import { Button } from "@renderer/components"; +import { useTranslation } from "react-i18next"; +import * as styles from "./game-details.css"; + +export function GameDetailsSkeleton() { + const { t } = useTranslation("game_details"); + + return ( +
+ +
+
+ + +
+ + +
+
+
+
+
+ + +
+ + +
+
+ +
+
+
+
+ +
+
+ + +
+
+ +
+
+
+
+ ); +} diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 62c5980b3..08c7067db 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -1,26 +1,30 @@ -import { useCallback, useEffect, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; import Color from "color"; import { average } from "color.js"; +import { useCallback, useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; import type { Game, GameShop, ShopDetails, SteamAppDetails } from "@types"; import { AsyncImage, Button } from "@renderer/components"; import { setHeaderTitle } from "@renderer/features"; -import { useAppDispatch, useDownload } from "@renderer/hooks"; import { getSteamLanguage, steamUrlBuilder } from "@renderer/helpers"; +import { useAppDispatch, useDownload } from "@renderer/hooks"; +import { ShareAndroidIcon } from "@primer/octicons-react"; +import { vars } from "@renderer/theme.css"; +import { useTranslation } from "react-i18next"; +import { SkeletonTheme } from "react-loading-skeleton"; +import { GameDetailsSkeleton } from "./game-details-skeleton"; import * as styles from "./game-details.css"; -import { RepacksModal } from "./repacks-modal"; import { HeroPanel } from "./hero-panel"; -import { useTranslation } from "react-i18next"; -import { ShareAndroidIcon } from "@primer/octicons-react"; +import { RepacksModal } from "./repacks-modal"; const OPEN_HYDRA_URL = "https://open.hydralauncher.site"; export function GameDetails() { const { objectID, shop } = useParams(); + const [isLoading, setIsLoading] = useState(false); const [color, setColor] = useState(""); const [clipboardLock, setClipboardLock] = useState(false); const [gameDetails, setGameDetails] = useState(null); @@ -57,6 +61,7 @@ export function GameDetails() { }, [getGame, gameDownloading?.id]); useEffect(() => { + setIsLoading(true); dispatch(setHeaderTitle("")); window.electron @@ -66,9 +71,11 @@ export function GameDetails() { navigate(-1); return; } - setGameDetails(result); dispatch(setHeaderTitle(result.name)); + }) + .finally(() => { + setIsLoading(false); }); getGame(); @@ -84,12 +91,12 @@ export function GameDetails() { shop, encodeURIComponent(gameDetails?.name), i18n.language, - ]) + ]), ), }); navigator.clipboard.writeText( - OPEN_HYDRA_URL + `/?${searchParams.toString()}` + OPEN_HYDRA_URL + `/?${searchParams.toString()}`, ); const zero = performance.now(); @@ -115,7 +122,7 @@ export function GameDetails() { repackId, gameDetails.objectID, gameDetails.name, - shop as GameShop + shop as GameShop, ).then(() => { getGame(); setShowRepacksModal(false); @@ -123,7 +130,7 @@ export function GameDetails() { }; return ( - <> + {gameDetails && ( )} -
-
- -
-
- + {isLoading ? ( + + ) : ( +
+
+ +
+
+ +
-
- setShowRepacksModal(true)} - getGame={getGame} - /> - -
-
-
-
-

- {t("release_date", { - date: gameDetails?.release_date.date, - })} -

-

- {t("publisher", { publisher: gameDetails?.publishers[0] })} -

-
- - -
+ setShowRepacksModal(true)} + getGame={getGame} + /> -
-
-
-
-

{t("requirements")}

+
+
+
+
+

+ {t("release_date", { + date: gameDetails?.release_date.date, + })} +

+

+ {t("publisher", { publisher: gameDetails?.publishers[0] })} +

+
+ + +
+ +
- -
- - +
+
+

{t("requirements")}

+
+ +
+ + +
+
-
-
-
- + + )} +
); } From e3079e69dd9bf55cfde440ca40d1c5c648cda748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lu=C3=ADs?= Date: Mon, 15 Apr 2024 19:21:23 -0300 Subject: [PATCH 2/6] feat: add howlongtobeat in loading skeleton --- .../game-details/game-details-skeleton.tsx | 49 +++++++++++++++---- .../pages/game-details/game-details.tsx | 49 +++++++++---------- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/renderer/pages/game-details/game-details-skeleton.tsx b/src/renderer/pages/game-details/game-details-skeleton.tsx index 209ee7b81..13ec436ff 100644 --- a/src/renderer/pages/game-details/game-details-skeleton.tsx +++ b/src/renderer/pages/game-details/game-details-skeleton.tsx @@ -1,8 +1,8 @@ import Skeleton from "react-loading-skeleton"; import { Button } from "@renderer/components"; -import { useTranslation } from "react-i18next"; import * as styles from "./game-details.css"; +import { useTranslation } from "react-i18next"; export function GameDetailsSkeleton() { const { t } = useTranslation("game_details"); @@ -27,23 +27,54 @@ export function GameDetailsSkeleton() { - -
+
+ +
-
-
- +
+
+

HowLongToBeat

+
+
    + {Array.from({ length: 3 }).map((_, index) => ( + + ))} +
+
+

{t("requirements")}

- +
diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index d3b769d0e..47ecef6e4 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -23,11 +23,8 @@ import { SkeletonTheme } from "react-loading-skeleton"; import { GameDetailsSkeleton } from "./game-details-skeleton"; import * as styles from "./game-details.css"; import { HeroPanel } from "./hero-panel"; -import { RepacksModal } from "./repacks-modal"; -import { HeroPanel } from "./hero-panel"; -import { useTranslation } from "react-i18next"; -import { ShareAndroidIcon } from "@primer/octicons-react"; import { HowLongToBeatSection } from "./how-long-to-beat-section"; +import { RepacksModal } from "./repacks-modal"; const OPEN_HYDRA_URL = "https://open.hydralauncher.site"; @@ -97,7 +94,7 @@ export function GameDetails() { dispatch(setHeaderTitle(result.name)); }) .finally(() => { - setIsLoading(false); + setIsLoading(true); }); getGame(); @@ -115,12 +112,12 @@ export function GameDetails() { shop, encodeURIComponent(gameDetails?.name), i18n.language, - ]), + ]) ), }); navigator.clipboard.writeText( - OPEN_HYDRA_URL + `/?${searchParams.toString()}`, + OPEN_HYDRA_URL + `/?${searchParams.toString()}` ); const zero = performance.now(); @@ -146,7 +143,7 @@ export function GameDetails() { repackId, gameDetails.objectID, gameDetails.name, - shop as GameShop, + shop as GameShop ).then(() => { getGame(); setShowRepacksModal(false); @@ -223,26 +220,26 @@ export function GameDetails() {
-
-
+
+
-
- +
+ -
-

{t("requirements")}

-
+
+

{t("requirements")}

+
+ {t("add_to_library")} + + +
From 0b3e6916b4d343181f1f7a70428f0a6cc9366e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lu=C3=ADs?= Date: Tue, 16 Apr 2024 19:52:57 -0300 Subject: [PATCH 5/6] fix: differences from skeleton to loaded page --- .../game-details/game-details-skeleton.tsx | 60 ++++++++----------- .../pages/game-details/game-details.css.ts | 39 ++++++++++++ 2 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/renderer/pages/game-details/game-details-skeleton.tsx b/src/renderer/pages/game-details/game-details-skeleton.tsx index 863a0bb17..73caef4fe 100644 --- a/src/renderer/pages/game-details/game-details-skeleton.tsx +++ b/src/renderer/pages/game-details/game-details-skeleton.tsx @@ -3,20 +3,24 @@ import Skeleton from "react-loading-skeleton"; import { Button } from "@renderer/components"; import * as styles from "./game-details.css"; import { useTranslation } from "react-i18next"; +import { ShareAndroidIcon } from "@primer/octicons-react"; export function GameDetailsSkeleton() { const { t } = useTranslation("game_details"); return (
- +
+ +
- - + +
-
-
- - - +
+ {Array.from({ length: 3 }).map((_, index) => ( + + ))} + + {Array.from({ length: 2 }).map((_, index) => ( + + ))} + +
@@ -96,8 +86,10 @@ export function GameDetailsSkeleton() { {t("recommended")}
-
- +
+ {Array.from({ length: 6 }).map((_, index) => ( + + ))}
diff --git a/src/renderer/pages/game-details/game-details.css.ts b/src/renderer/pages/game-details/game-details.css.ts index aa2ca1db5..53c0b3b31 100644 --- a/src/renderer/pages/game-details/game-details.css.ts +++ b/src/renderer/pages/game-details/game-details.css.ts @@ -34,6 +34,12 @@ export const heroBackdrop = style({ justifyContent: "space-between", }); +export const heroFooterButtonsSkeleton = style({ + display: "flex", + flexDirection: "row", + gap: `${SPACING_UNIT}px`, +}); + export const heroImage = style({ width: "100%", height: "100%", @@ -47,6 +53,15 @@ export const heroImage = style({ }, }); +export const heroImageSkeleton = style({ + height: "300px", + "@media": { + "(min-width: 1250px)": { + height: "350px", + }, + }, +}); + export const container = style({ width: "100%", height: "100%", @@ -114,6 +129,14 @@ export const requirementsDetails = style({ fontSize: "16px", }); +export const requirementsDetailsSkeleton = style({ + display: "flex", + flexDirection: "column", + gap: "8px", + padding: `${SPACING_UNIT * 2}px`, + fontSize: "16px", +}); + export const description = style({ userSelect: "text", lineHeight: "22px", @@ -130,6 +153,22 @@ export const description = style({ marginRight: "auto", }); +export const descriptionSkeleton = style({ + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT}px`, + padding: `${SPACING_UNIT * 3}px ${SPACING_UNIT * 2}px`, + width: "100%", + // "@media": { + // "(min-width: 1280px)": { + // width: "60%", + // lineHeight: "22px", + // }, + // }, + marginLeft: "auto", + marginRight: "auto", +}); + export const descriptionHeader = style({ width: "100%", padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`, From 5240fe180451d5a48185ee71a1ac0d0fa5a8851b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lu=C3=ADs?= Date: Tue, 16 Apr 2024 20:17:44 -0300 Subject: [PATCH 6/6] feat: add a width 60% to large scales in game details description skeleton --- src/renderer/pages/game-details/game-details.css.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/renderer/pages/game-details/game-details.css.ts b/src/renderer/pages/game-details/game-details.css.ts index 53c0b3b31..6145b9aed 100644 --- a/src/renderer/pages/game-details/game-details.css.ts +++ b/src/renderer/pages/game-details/game-details.css.ts @@ -159,12 +159,12 @@ export const descriptionSkeleton = style({ gap: `${SPACING_UNIT}px`, padding: `${SPACING_UNIT * 3}px ${SPACING_UNIT * 2}px`, width: "100%", - // "@media": { - // "(min-width: 1280px)": { - // width: "60%", - // lineHeight: "22px", - // }, - // }, + "@media": { + "(min-width: 1280px)": { + width: "60%", + lineHeight: "22px", + }, + }, marginLeft: "auto", marginRight: "auto", });