mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
first commit
This commit is contained in:
commit
91b1341271
165 changed files with 20993 additions and 0 deletions
127
src/renderer/components/game-card/game-card.css.ts
Normal file
127
src/renderer/components/game-card/game-card.css.ts
Normal 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",
|
||||
});
|
87
src/renderer/components/game-card/game-card.tsx
Normal file
87
src/renderer/components/game-card/game-card.tsx
Normal 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>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue