mirror of
				https://github.com/hydralauncher/hydra.git
				synced 2025-03-09 15:40:26 +00:00 
			
		
		
		
	feat: update achievements on sidebar
This commit is contained in:
		
							parent
							
								
									446b03eeff
								
							
						
					
					
						commit
						ffac677e3f
					
				
					 9 changed files with 143 additions and 57 deletions
				
			
		| 
						 | 
				
			
			@ -39,6 +39,7 @@ export function Header({ onSearch, onClear, search }: HeaderProps) {
 | 
			
		|||
 | 
			
		||||
  const title = useMemo(() => {
 | 
			
		||||
    if (location.pathname.startsWith("/game")) return headerTitle;
 | 
			
		||||
    if (location.pathname.startsWith("/achievements")) return headerTitle;
 | 
			
		||||
    if (location.pathname.startsWith("/profile")) return headerTitle;
 | 
			
		||||
    if (location.pathname.startsWith("/search")) return t("search_results");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import { useDate } from "@renderer/hooks";
 | 
			
		||||
import { setHeaderTitle } from "@renderer/features";
 | 
			
		||||
import { useAppDispatch, useDate } from "@renderer/hooks";
 | 
			
		||||
import { SPACING_UNIT } from "@renderer/theme.css";
 | 
			
		||||
import { GameAchievement, GameShop } from "@types";
 | 
			
		||||
import { useEffect, useState } from "react";
 | 
			
		||||
| 
						 | 
				
			
			@ -8,10 +9,13 @@ export function Achievement() {
 | 
			
		|||
  const [searchParams] = useSearchParams();
 | 
			
		||||
  const objectId = searchParams.get("objectId");
 | 
			
		||||
  const shop = searchParams.get("shop");
 | 
			
		||||
  const title = searchParams.get("title");
 | 
			
		||||
  const userId = searchParams.get("userId");
 | 
			
		||||
 | 
			
		||||
  const { format } = useDate();
 | 
			
		||||
 | 
			
		||||
  const dispatch = useAppDispatch();
 | 
			
		||||
 | 
			
		||||
  const [achievements, setAchievements] = useState<GameAchievement[]>([]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +28,12 @@ export function Achievement() {
 | 
			
		|||
    }
 | 
			
		||||
  }, [objectId, shop, userId]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (title) {
 | 
			
		||||
      dispatch(setHeaderTitle(title + " Achievements"));
 | 
			
		||||
    }
 | 
			
		||||
  }, [dispatch, title]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      <h1>Achievement</h1>
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +71,7 @@ export function Achievement() {
 | 
			
		|||
            />
 | 
			
		||||
            <div>
 | 
			
		||||
              <p>{achievement.displayName}</p>
 | 
			
		||||
              <p>{achievement.description}</p>
 | 
			
		||||
              {achievement.unlockTime && format(achievement.unlockTime)}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
import { globalStyle, style } from "@vanilla-extract/css";
 | 
			
		||||
 | 
			
		||||
import { SPACING_UNIT, vars } from "../../../theme.css";
 | 
			
		||||
import { recipe } from "@vanilla-extract/recipes";
 | 
			
		||||
 | 
			
		||||
export const contentSidebar = style({
 | 
			
		||||
  borderLeft: `solid 1px ${vars.color.border}`,
 | 
			
		||||
| 
						 | 
				
			
			@ -110,3 +111,46 @@ globalStyle(`${requirementsDetails} a`, {
 | 
			
		|||
  display: "flex",
 | 
			
		||||
  color: vars.color.body,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const list = style({
 | 
			
		||||
  listStyle: "none",
 | 
			
		||||
  margin: "0",
 | 
			
		||||
  display: "flex",
 | 
			
		||||
  flexDirection: "column",
 | 
			
		||||
  gap: `${SPACING_UNIT * 2}px`,
 | 
			
		||||
  padding: `${SPACING_UNIT * 2}px`,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const listItem = style({
 | 
			
		||||
  display: "flex",
 | 
			
		||||
  cursor: "pointer",
 | 
			
		||||
  transition: "all ease 0.1s",
 | 
			
		||||
  color: vars.color.muted,
 | 
			
		||||
  width: "100%",
 | 
			
		||||
  overflow: "hidden",
 | 
			
		||||
  borderRadius: "4px",
 | 
			
		||||
  padding: `${SPACING_UNIT}px ${SPACING_UNIT}px`,
 | 
			
		||||
  gap: `${SPACING_UNIT * 2}px`,
 | 
			
		||||
  alignItems: "center",
 | 
			
		||||
  textAlign: "left",
 | 
			
		||||
  ":hover": {
 | 
			
		||||
    backgroundColor: "rgba(255, 255, 255, 0.15)",
 | 
			
		||||
    textDecoration: "none",
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const listItemImage = recipe({
 | 
			
		||||
  base: {
 | 
			
		||||
    width: "54px",
 | 
			
		||||
    height: "54px",
 | 
			
		||||
    borderRadius: "4px",
 | 
			
		||||
    objectFit: "cover",
 | 
			
		||||
  },
 | 
			
		||||
  variants: {
 | 
			
		||||
    unlocked: {
 | 
			
		||||
      false: {
 | 
			
		||||
        filter: "grayscale(100%)",
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,10 +7,10 @@ import * as styles from "./sidebar.css";
 | 
			
		|||
import { gameDetailsContext } from "@renderer/context";
 | 
			
		||||
import { useDate, useFormat } from "@renderer/hooks";
 | 
			
		||||
import { DownloadIcon, PeopleIcon } from "@primer/octicons-react";
 | 
			
		||||
import { SPACING_UNIT } from "@renderer/theme.css";
 | 
			
		||||
import { HowLongToBeatSection } from "./how-long-to-beat-section";
 | 
			
		||||
import { howLongToBeatEntriesTable } from "@renderer/dexie";
 | 
			
		||||
import { SidebarSection } from "../sidebar-section/sidebar-section";
 | 
			
		||||
import { useNavigate } from "react-router-dom";
 | 
			
		||||
 | 
			
		||||
export function Sidebar() {
 | 
			
		||||
  const [howLongToBeat, setHowLongToBeat] = useState<{
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,12 @@ export function Sidebar() {
 | 
			
		|||
  const { numberFormatter } = useFormat();
 | 
			
		||||
 | 
			
		||||
  const buildGameAchievementPath = () => {
 | 
			
		||||
    const urlParams = new URLSearchParams({ objectId: objectId!, shop });
 | 
			
		||||
    const urlParams = new URLSearchParams({
 | 
			
		||||
      objectId: objectId!,
 | 
			
		||||
      shop,
 | 
			
		||||
      title: gameTitle,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return `/achievements?${urlParams.toString()}`;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,49 +85,43 @@ export function Sidebar() {
 | 
			
		|||
            achievementsCount: achievements.length,
 | 
			
		||||
          })}
 | 
			
		||||
        >
 | 
			
		||||
          <span>
 | 
			
		||||
            <Link to={buildGameAchievementPath()}>Ver todas</Link>
 | 
			
		||||
          </span>
 | 
			
		||||
          <div
 | 
			
		||||
            style={{
 | 
			
		||||
              display: "flex",
 | 
			
		||||
              flexDirection: "column",
 | 
			
		||||
              gap: `${SPACING_UNIT}px`,
 | 
			
		||||
              padding: `${SPACING_UNIT * 2}px`,
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            {achievements.slice(0, 6).map((achievement, index) => (
 | 
			
		||||
              <div
 | 
			
		||||
                key={index}
 | 
			
		||||
                style={{
 | 
			
		||||
                  display: "flex",
 | 
			
		||||
                  flexDirection: "row",
 | 
			
		||||
                  alignItems: "center",
 | 
			
		||||
                  gap: `${SPACING_UNIT}px`,
 | 
			
		||||
                }}
 | 
			
		||||
                title={achievement.description}
 | 
			
		||||
              >
 | 
			
		||||
                <img
 | 
			
		||||
                  style={{
 | 
			
		||||
                    height: "60px",
 | 
			
		||||
                    width: "60px",
 | 
			
		||||
                    filter: achievement.unlocked ? "none" : "grayscale(100%)",
 | 
			
		||||
                  }}
 | 
			
		||||
                  src={
 | 
			
		||||
                    achievement.unlocked
 | 
			
		||||
                      ? achievement.icon
 | 
			
		||||
                      : achievement.icongray
 | 
			
		||||
                  }
 | 
			
		||||
                  alt={achievement.displayName}
 | 
			
		||||
                  loading="lazy"
 | 
			
		||||
                />
 | 
			
		||||
                <div>
 | 
			
		||||
                  <p>{achievement.displayName}</p>
 | 
			
		||||
                  {achievement.unlockTime && format(achievement.unlockTime)}
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
          <ul className={styles.list}>
 | 
			
		||||
            {achievements.slice(0, 4).map((achievement, index) => (
 | 
			
		||||
              <li key={index}>
 | 
			
		||||
                <Link
 | 
			
		||||
                  to={buildGameAchievementPath()}
 | 
			
		||||
                  className={styles.listItem}
 | 
			
		||||
                  title={achievement.description}
 | 
			
		||||
                >
 | 
			
		||||
                  <img
 | 
			
		||||
                    className={styles.listItemImage({
 | 
			
		||||
                      unlocked: achievement.unlocked,
 | 
			
		||||
                    })}
 | 
			
		||||
                    src={
 | 
			
		||||
                      achievement.unlocked
 | 
			
		||||
                        ? achievement.icon
 | 
			
		||||
                        : achievement.icongray
 | 
			
		||||
                    }
 | 
			
		||||
                    alt={achievement.displayName}
 | 
			
		||||
                    loading="lazy"
 | 
			
		||||
                  />
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <p>{achievement.displayName}</p>
 | 
			
		||||
                    <small>
 | 
			
		||||
                      {achievement.unlockTime && format(achievement.unlockTime)}
 | 
			
		||||
                    </small>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </Link>
 | 
			
		||||
              </li>
 | 
			
		||||
            ))}
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
            <Link
 | 
			
		||||
              style={{ textAlign: "center" }}
 | 
			
		||||
              to={buildGameAchievementPath()}
 | 
			
		||||
            >
 | 
			
		||||
              {t("see_all_achievements")}
 | 
			
		||||
            </Link>
 | 
			
		||||
          </ul>
 | 
			
		||||
        </SidebarSection>
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue