first commit

This commit is contained in:
Hydra 2024-04-18 08:46:06 +01:00
commit 91b1341271
No known key found for this signature in database
165 changed files with 20993 additions and 0 deletions

View file

@ -0,0 +1,127 @@
import { style } from "@vanilla-extract/css";
import { recipe } from "@vanilla-extract/recipes";
import { SPACING_UNIT, vars } from "../../theme.css";
export const card = recipe({
base: {
width: "100%",
height: "180px",
boxShadow: "0px 0px 15px 0px #000000",
overflow: "hidden",
borderRadius: "4px",
transition: "all ease 0.2s",
border: `solid 1px ${vars.color.borderColor}`,
cursor: "pointer",
zIndex: "1",
":active": {
opacity: vars.opacity.active,
},
},
variants: {
disabled: {
true: {
pointerEvents: "none",
boxShadow: "none",
opacity: vars.opacity.disabled,
filter: "grayscale(50%)",
},
},
},
});
export const backdrop = style({
background: "linear-gradient(0deg, rgba(0, 0, 0, 0.7) 50%, transparent 100%)",
width: "100%",
height: "100%",
display: "flex",
justifyContent: "flex-end",
flexDirection: "column",
position: "relative",
});
export const cover = style({
width: "100%",
height: "100%",
objectFit: "cover",
objectPosition: "center",
position: "absolute",
zIndex: "-1",
transition: "all ease 0.2s",
selectors: {
[`${card({})}:hover &`]: {
transform: "scale(1.05)",
},
},
});
export const content = style({
color: "#DADBE1",
padding: `${SPACING_UNIT}px ${SPACING_UNIT * 2}px`,
display: "flex",
alignItems: "flex-start",
gap: `${SPACING_UNIT}px`,
flexDirection: "column",
transition: "all ease 0.2s",
transform: "translateY(24px)",
selectors: {
[`${card({})}:hover &`]: {
transform: "translateY(0px)",
},
},
});
export const title = style({
fontSize: "16px",
fontWeight: "bold",
textAlign: "left",
});
export const downloadOptions = style({
display: "flex",
margin: "0",
padding: "0",
gap: `${SPACING_UNIT}px`,
flexWrap: "wrap",
});
export const downloadOption = style({
color: "#c0c1c7",
fontSize: "10px",
padding: `${SPACING_UNIT / 2}px ${SPACING_UNIT}px`,
border: "solid 1px #c0c1c7",
borderRadius: "4px",
display: "flex",
alignItems: "center",
});
export const specifics = style({
display: "flex",
gap: `${SPACING_UNIT * 2}px`,
justifyContent: "center",
});
export const specificsItem = style({
gap: `${SPACING_UNIT}px`,
display: "flex",
color: "#c0c1c7",
fontSize: "12px",
alignItems: "flex-end",
});
export const titleContainer = style({
display: "flex",
alignItems: "center",
gap: `${SPACING_UNIT}px`,
color: "#c0c1c7",
});
export const shopIcon = style({
width: "20px",
height: "20px",
minWidth: "20px",
});
export const noDownloadsLabel = style({
color: vars.color.bodyText,
fontWeight: "bold",
});

View file

@ -0,0 +1,87 @@
import { DownloadIcon, FileDirectoryIcon } from "@primer/octicons-react";
import type { CatalogueEntry } from "@types";
import SteamLogo from "@renderer/assets/steam-logo.svg";
import EpicGamesLogo from "@renderer/assets/epic-games-logo.svg";
import { AsyncImage } from "../async-image/async-image";
import * as styles from "./game-card.css";
import { useAppSelector } from "@renderer/hooks";
import { useTranslation } from "react-i18next";
export interface GameCardProps
extends React.DetailedHTMLProps<
React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
> {
game: CatalogueEntry;
disabled?: boolean;
}
const shopIcon = {
epic: <EpicGamesLogo className={styles.shopIcon} />,
steam: <SteamLogo className={styles.shopIcon} />,
};
export function GameCard({ game, disabled, ...props }: GameCardProps) {
const { t } = useTranslation("game_card");
const repackersFriendlyNames = useAppSelector(
(state) => state.repackersFriendlyNames.value
);
const uniqueRepackers = Array.from(
new Set(game.repacks.map(({ repacker }) => repacker))
);
return (
<button
{...props}
type="button"
className={styles.card({ disabled })}
disabled={disabled}
>
<div className={styles.backdrop}>
<AsyncImage
src={game.cover}
alt={game.title}
className={styles.cover}
/>
<div className={styles.content}>
<div className={styles.titleContainer}>
{shopIcon[game.shop]}
<p className={styles.title}>{game.title}</p>
</div>
{uniqueRepackers.length > 0 ? (
<ul className={styles.downloadOptions}>
{uniqueRepackers.map((repacker) => (
<li key={repacker} className={styles.downloadOption}>
<span>{repackersFriendlyNames[repacker]}</span>
</li>
))}
</ul>
) : (
<p className={styles.noDownloadsLabel}>{t("no_downloads")}</p>
)}
<div className={styles.specifics}>
<div className={styles.specificsItem}>
<DownloadIcon />
<span>{game.repacks.length}</span>
</div>
{game.repacks.length > 0 && (
<div className={styles.specificsItem}>
<FileDirectoryIcon />
<span>{game.repacks.at(0)?.fileSize}</span>
</div>
)}
</div>
</div>
</div>
</button>
);
}