mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: comparing achievements
This commit is contained in:
parent
694e0cd12c
commit
c24f6be1b7
2 changed files with 121 additions and 74 deletions
|
@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||||
import * as styles from "./achievements.css";
|
import * as styles from "./achievements.css";
|
||||||
import { formatDownloadProgress } from "@renderer/helpers";
|
import { formatDownloadProgress } from "@renderer/helpers";
|
||||||
import { TrophyIcon } from "@primer/octicons-react";
|
import { TrophyIcon } from "@primer/octicons-react";
|
||||||
import { vars } from "@renderer/theme.css";
|
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||||
import { gameDetailsContext } from "@renderer/context";
|
import { gameDetailsContext } from "@renderer/context";
|
||||||
import { GameShop, UserAchievement } from "@types";
|
import { GameShop, UserAchievement } from "@types";
|
||||||
import { average } from "color.js";
|
import { average } from "color.js";
|
||||||
|
@ -19,6 +19,107 @@ interface AchievementsContentProps {
|
||||||
displayName: string | null;
|
displayName: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AchievementListProps {
|
||||||
|
achievements: UserAchievement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AchievementPanelProps {
|
||||||
|
achievements: UserAchievement[];
|
||||||
|
displayName: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function AchievementPanel({
|
||||||
|
achievements,
|
||||||
|
displayName,
|
||||||
|
}: AchievementPanelProps) {
|
||||||
|
const { t } = useTranslation("achievement");
|
||||||
|
|
||||||
|
const unlockedAchievementCount = achievements.filter(
|
||||||
|
(achievement) => achievement.unlocked
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const totalAchievementCount = achievements.length;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
width: "100%",
|
||||||
|
padding: `0 ${SPACING_UNIT * 2}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h1 style={{ fontSize: "1.2em", marginBottom: "8px" }}>
|
||||||
|
{displayName
|
||||||
|
? t("user_achievements", {
|
||||||
|
displayName,
|
||||||
|
})
|
||||||
|
: t("your_achievements")}
|
||||||
|
</h1>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginBottom: 8,
|
||||||
|
width: "100%",
|
||||||
|
color: vars.color.muted,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TrophyIcon size={13} />
|
||||||
|
<span>
|
||||||
|
{unlockedAchievementCount} / {totalAchievementCount}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{formatDownloadProgress(
|
||||||
|
unlockedAchievementCount / totalAchievementCount
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<progress
|
||||||
|
max={1}
|
||||||
|
value={unlockedAchievementCount / totalAchievementCount}
|
||||||
|
className={styles.achievementsProgressBar}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AchievementList({ achievements }: AchievementListProps) {
|
||||||
|
const { formatDateTime } = useDate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul className={styles.list}>
|
||||||
|
{achievements.map((achievement, index) => (
|
||||||
|
<li key={index} className={styles.listItem}>
|
||||||
|
<img
|
||||||
|
className={styles.listItemImage({
|
||||||
|
unlocked: achievement.unlocked,
|
||||||
|
})}
|
||||||
|
src={achievement.icon}
|
||||||
|
alt={achievement.displayName}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p>{achievement.displayName}</p>
|
||||||
|
<p>{achievement.description}</p>
|
||||||
|
<small>
|
||||||
|
{achievement.unlockTime && formatDateTime(achievement.unlockTime)}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function AchievementsContent({
|
export function AchievementsContent({
|
||||||
userId,
|
userId,
|
||||||
displayName,
|
displayName,
|
||||||
|
@ -31,13 +132,9 @@ export function AchievementsContent({
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { t } = useTranslation("achievement");
|
|
||||||
|
|
||||||
const { gameTitle, objectId, shop, achievements, gameColor, setGameColor } =
|
const { gameTitle, objectId, shop, achievements, gameColor, setGameColor } =
|
||||||
useContext(gameDetailsContext);
|
useContext(gameDetailsContext);
|
||||||
|
|
||||||
const { formatDateTime } = useDate();
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -93,12 +190,6 @@ export function AchievementsContent({
|
||||||
|
|
||||||
const userAchievements = userId ? pageAchievements : achievements;
|
const userAchievements = userId ? pageAchievements : achievements;
|
||||||
|
|
||||||
const unlockedAchievementCount = userAchievements.filter(
|
|
||||||
(achievement) => achievement.unlocked
|
|
||||||
).length;
|
|
||||||
|
|
||||||
const totalAchievementCount = userAchievements.length;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<img
|
<img
|
||||||
|
@ -137,70 +228,26 @@ export function AchievementsContent({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.panel({ stuck: isHeaderStuck })}>
|
<div className={styles.panel({ stuck: isHeaderStuck })}>
|
||||||
<h1 style={{ fontSize: "1.2em", marginBottom: "8px" }}>
|
<AchievementPanel
|
||||||
{displayName
|
displayName={displayName}
|
||||||
? t("user_achievements", {
|
achievements={userAchievements}
|
||||||
displayName,
|
/>
|
||||||
})
|
{pageAchievements.length > 0 && (
|
||||||
: t("your_achievements")}
|
<AchievementPanel displayName={null} achievements={achievements} />
|
||||||
</h1>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginBottom: 8,
|
|
||||||
width: "100%",
|
|
||||||
color: vars.color.muted,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 8,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TrophyIcon size={13} />
|
|
||||||
<span>
|
|
||||||
{unlockedAchievementCount} / {totalAchievementCount}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{formatDownloadProgress(
|
|
||||||
unlockedAchievementCount / totalAchievementCount
|
|
||||||
)}
|
)}
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<progress
|
|
||||||
max={1}
|
|
||||||
value={unlockedAchievementCount / totalAchievementCount}
|
|
||||||
className={styles.achievementsProgressBar}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{pageAchievements.length > 0 && (
|
||||||
|
<AchievementList achievements={pageAchievements} />
|
||||||
|
)}
|
||||||
|
|
||||||
<ul className={styles.list}>
|
<AchievementList achievements={achievements} />
|
||||||
{userAchievements.map((achievement, index) => (
|
|
||||||
<li key={index} className={styles.listItem}>
|
|
||||||
<img
|
|
||||||
className={styles.listItemImage({
|
|
||||||
unlocked: achievement.unlocked,
|
|
||||||
})}
|
|
||||||
src={achievement.icon}
|
|
||||||
alt={achievement.displayName}
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<p>{achievement.displayName}</p>
|
|
||||||
<p>{achievement.description}</p>
|
|
||||||
<small>
|
|
||||||
{achievement.unlockTime &&
|
|
||||||
formatDateTime(achievement.unlockTime)}
|
|
||||||
</small>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -66,10 +66,10 @@ export const panel = recipe({
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100px",
|
height: "100px",
|
||||||
minHeight: "100px",
|
minHeight: "100px",
|
||||||
padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`,
|
padding: `${SPACING_UNIT * 2}px 0`,
|
||||||
backgroundColor: vars.color.darkBackground,
|
backgroundColor: vars.color.darkBackground,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "row",
|
||||||
transition: "all ease 0.2s",
|
transition: "all ease 0.2s",
|
||||||
borderBottom: `solid 1px ${vars.color.border}`,
|
borderBottom: `solid 1px ${vars.color.border}`,
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue