mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-09 03:37:45 +03:00
refactor: remove vanilla-extract
This commit is contained in:
parent
e4631bba7b
commit
f6e4852f4a
@ -42,9 +42,6 @@
|
||||
"@reduxjs/toolkit": "^2.2.3",
|
||||
"@sentry/react": "^8.47.0",
|
||||
"@sentry/vite-plugin": "^2.22.7",
|
||||
"@vanilla-extract/css": "^1.14.2",
|
||||
"@vanilla-extract/dynamic": "^2.1.2",
|
||||
"@vanilla-extract/recipes": "^0.5.2",
|
||||
"auto-launch": "^5.0.6",
|
||||
"axios": "^1.7.9",
|
||||
"better-sqlite3": "^11.7.0",
|
||||
@ -101,7 +98,6 @@
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/sound-play": "^1.1.3",
|
||||
"@types/user-agents": "^1.0.4",
|
||||
"@vanilla-extract/vite-plugin": "^4.0.7",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"electron": "^31.7.6",
|
||||
"electron-builder": "^25.1.8",
|
||||
|
@ -1,134 +0,0 @@
|
||||
import {
|
||||
ComplexStyleRule,
|
||||
createContainer,
|
||||
globalStyle,
|
||||
style,
|
||||
} from "@vanilla-extract/css";
|
||||
import { SPACING_UNIT, vars } from "./theme.css";
|
||||
|
||||
export const appContainer = createContainer();
|
||||
|
||||
globalStyle("*", {
|
||||
boxSizing: "border-box",
|
||||
});
|
||||
|
||||
globalStyle("::-webkit-scrollbar", {
|
||||
width: "9px",
|
||||
backgroundColor: vars.color.darkBackground,
|
||||
});
|
||||
|
||||
globalStyle("::-webkit-scrollbar-track", {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.03)",
|
||||
});
|
||||
|
||||
globalStyle("::-webkit-scrollbar-thumb", {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.08)",
|
||||
borderRadius: "24px",
|
||||
});
|
||||
|
||||
globalStyle("::-webkit-scrollbar-thumb:hover", {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.16)",
|
||||
});
|
||||
|
||||
globalStyle("html, body, #root, main", {
|
||||
height: "100%",
|
||||
});
|
||||
|
||||
globalStyle("body", {
|
||||
overflow: "hidden",
|
||||
userSelect: "none",
|
||||
fontFamily: "Noto Sans, sans-serif",
|
||||
fontSize: vars.size.body,
|
||||
color: vars.color.body,
|
||||
margin: "0",
|
||||
});
|
||||
|
||||
globalStyle("button", {
|
||||
padding: "0",
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
fontFamily: "inherit",
|
||||
});
|
||||
|
||||
globalStyle("h1, h2, h3, h4, h5, h6, p", {
|
||||
margin: 0,
|
||||
});
|
||||
|
||||
globalStyle("p", {
|
||||
lineHeight: "20px",
|
||||
});
|
||||
|
||||
globalStyle("#root, main", {
|
||||
display: "flex",
|
||||
});
|
||||
|
||||
globalStyle("#root", {
|
||||
flexDirection: "column",
|
||||
});
|
||||
|
||||
globalStyle("main", {
|
||||
overflow: "hidden",
|
||||
});
|
||||
|
||||
globalStyle(
|
||||
"input::-webkit-outer-spin-button, input::-webkit-inner-spin-button",
|
||||
{
|
||||
WebkitAppearance: "none",
|
||||
margin: "0",
|
||||
}
|
||||
);
|
||||
|
||||
globalStyle("label", {
|
||||
fontSize: vars.size.body,
|
||||
});
|
||||
|
||||
globalStyle("input[type=number]", {
|
||||
MozAppearance: "textfield",
|
||||
});
|
||||
|
||||
globalStyle("img", {
|
||||
WebkitUserDrag: "none",
|
||||
} as Record<string, string>);
|
||||
|
||||
globalStyle("progress[value]", {
|
||||
WebkitAppearance: "none",
|
||||
});
|
||||
|
||||
export const container = style({
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
containerName: appContainer,
|
||||
containerType: "inline-size",
|
||||
});
|
||||
|
||||
export const content = style({
|
||||
overflowY: "auto",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
height: "100%",
|
||||
background: `linear-gradient(0deg, ${vars.color.darkBackground} 50%, ${vars.color.background} 100%)`,
|
||||
});
|
||||
|
||||
export const titleBar = style({
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
height: "35px",
|
||||
minHeight: "35px",
|
||||
backgroundColor: vars.color.darkBackground,
|
||||
alignItems: "center",
|
||||
padding: `0 ${SPACING_UNIT * 2}px`,
|
||||
WebkitAppRegion: "drag",
|
||||
zIndex: "4",
|
||||
borderBottom: `1px solid ${vars.color.border}`,
|
||||
} as ComplexStyleRule);
|
||||
|
||||
export const cloudText = style({
|
||||
background: "linear-gradient(270deg, #16B195 50%, #3E62C0 100%)",
|
||||
backgroundClip: "text",
|
||||
color: "transparent",
|
||||
});
|
@ -35,12 +35,23 @@ $toast-height: 80px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__message-container {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__message {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&__progress {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
|
||||
&::-webkit-progress-bar {
|
||||
background-color: globals.$dark-background-color;
|
||||
}
|
||||
|
||||
&::-webkit-progress-value {
|
||||
background-color: globals.$muted-color;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
} from "@primer/octicons-react";
|
||||
|
||||
import "./toast.scss";
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import cn from "classnames";
|
||||
|
||||
export interface ToastProps {
|
||||
@ -84,7 +83,7 @@ export function Toast({ visible, message, type, onClose }: ToastProps) {
|
||||
})}
|
||||
>
|
||||
<div className="toast__content">
|
||||
<div style={{ display: "flex", gap: `${SPACING_UNIT}px` }}>
|
||||
<div className="toast__message-container">
|
||||
{type === "success" && (
|
||||
<CheckCircleFillIcon className="toast__success-icon" />
|
||||
)}
|
||||
@ -94,7 +93,7 @@ export function Toast({ visible, message, type, onClose }: ToastProps) {
|
||||
)}
|
||||
|
||||
{type === "warning" && <AlertIcon className="toast__warning-icon" />}
|
||||
<span style={{ fontWeight: "bold" }}>{message}</span>
|
||||
<span className="toast__message">{message}</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
248
src/renderer/src/pages/achievements/achievements-content.scss
Normal file
248
src/renderer/src/pages/achievements/achievements-content.scss
Normal file
@ -0,0 +1,248 @@
|
||||
@use "../../scss/globals.scss";
|
||||
|
||||
$hero-height: 150px;
|
||||
$logo-height: 100px;
|
||||
$logo-max-width: 200px;
|
||||
|
||||
.achievements-content {
|
||||
&__comparison {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit * 2;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: globals.$spacing-unit;
|
||||
|
||||
&__container {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: globals.$spacing-unit;
|
||||
border-radius: 4px;
|
||||
justify-content: center;
|
||||
|
||||
&__subscription-required-button {
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: globals.$spacing-unit / 2;
|
||||
color: globals.$body-color;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__blured-avatar {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit * 2;
|
||||
align-items: center;
|
||||
height: 62px;
|
||||
position: relative;
|
||||
filter: blur(4px);
|
||||
|
||||
h1 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__small-avatar {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
&__subscription-required-button {
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
color: globals.$body-color;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&__user-summary {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit * 2;
|
||||
align-items: center;
|
||||
padding: globals.$spacing-unit globals.$spacing-unit * 2;
|
||||
|
||||
&__container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
h1 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__stats {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
color: globals.$muted-color;
|
||||
|
||||
&__trophy-count {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__progress-bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
&::-webkit-progress-bar {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-progress-value {
|
||||
background-color: globals.$muted-color;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__achievements-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&__image {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__section {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
|
||||
&__container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
globals.$background-color 0%,
|
||||
globals.$background-color 100%
|
||||
);
|
||||
|
||||
&__hero {
|
||||
width: 100%;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
&__content {
|
||||
padding: globals.$spacing-unit * 2;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&__game-logo {
|
||||
width: $logo-max-width;
|
||||
height: $logo-height;
|
||||
object-fit: contain;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__achievements-summary-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: globals.$spacing-unit;
|
||||
padding: globals.$spacing-unit;
|
||||
}
|
||||
}
|
||||
|
||||
&__table-header {
|
||||
width: 100%;
|
||||
background-color: globals.$background-color;
|
||||
transition: all ease 0.2s;
|
||||
border-bottom: 1px solid globals.$border-color;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
|
||||
&--stuck {
|
||||
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
&__container {
|
||||
display: grid;
|
||||
gap: globals.$spacing-unit * 2;
|
||||
padding: globals.$spacing-unit * 3;
|
||||
|
||||
&--has-no-active-subscription {
|
||||
grid-template-columns: 3fr 2fr;
|
||||
}
|
||||
|
||||
&--has-active-subscription {
|
||||
grid-template-columns: 3fr 1fr 1fr;
|
||||
}
|
||||
|
||||
&__user-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__other-user-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__profile-avatar {
|
||||
height: 54px;
|
||||
width: 54px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: globals.$background-color;
|
||||
position: relative;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
@ -8,18 +8,17 @@ import {
|
||||
formatDownloadProgress,
|
||||
} from "@renderer/helpers";
|
||||
import { LockIcon, PersonIcon, TrophyIcon } from "@primer/octicons-react";
|
||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||
import { gameDetailsContext } from "@renderer/context";
|
||||
import type { ComparedAchievements } from "@types";
|
||||
import { average } from "color.js";
|
||||
import Color from "color";
|
||||
import { Link } from "@renderer/components";
|
||||
import { ComparedAchievementList } from "./compared-achievement-list";
|
||||
import * as styles from "./achievements.css";
|
||||
import { AchievementList } from "./achievement-list";
|
||||
import { AchievementPanel } from "./achievement-panel";
|
||||
import { ComparedAchievementPanel } from "./compared-achievement-panel";
|
||||
import { useSubscription } from "@renderer/hooks/use-subscription";
|
||||
import "./achievements-content.scss";
|
||||
|
||||
interface UserInfo {
|
||||
id: string;
|
||||
@ -48,10 +47,10 @@ function AchievementSummary({ user, isComparison }: AchievementSummaryProps) {
|
||||
user: Pick<UserInfo, "profileImageUrl" | "displayName">
|
||||
) => {
|
||||
return (
|
||||
<div className={styles.profileAvatar}>
|
||||
<div className="achievements-content__profile-avatar">
|
||||
{user.profileImageUrl ? (
|
||||
<img
|
||||
className={styles.profileAvatar}
|
||||
className="achievements-content__profile-avatar"
|
||||
src={user.profileImageUrl}
|
||||
alt={user.displayName}
|
||||
/>
|
||||
@ -64,91 +63,33 @@ function AchievementSummary({ user, isComparison }: AchievementSummaryProps) {
|
||||
|
||||
if (isComparison && userDetails?.id == user.id && !hasActiveSubscription) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
alignItems: "center",
|
||||
position: "relative",
|
||||
padding: `${SPACING_UNIT}px`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 2,
|
||||
inset: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
background: "rgba(0, 0, 0, 0.7)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
borderRadius: "4px",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<div className="achievements-content__comparison">
|
||||
<div className="achievements-content__comparison__container">
|
||||
<LockIcon size={24} />
|
||||
<h3>
|
||||
<button
|
||||
className={styles.subscriptionRequiredButton}
|
||||
className="achievements-content__comparison__container__subscription-required-button"
|
||||
onClick={() => showHydraCloudModal("achievements")}
|
||||
>
|
||||
{t("subscription_needed")}
|
||||
</button>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
alignItems: "center",
|
||||
height: "62px",
|
||||
position: "relative",
|
||||
filter: "blur(4px)",
|
||||
}}
|
||||
>
|
||||
<div className="achievements-content__comparison__blured-avatar">
|
||||
{getProfileImage(user)}
|
||||
<h1 style={{ marginBottom: "8px" }}>{user.displayName}</h1>
|
||||
<h1>{user.displayName}</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
alignItems: "center",
|
||||
padding: `${SPACING_UNIT}px`,
|
||||
}}
|
||||
>
|
||||
<div className="achievements-content__user-summary">
|
||||
{getProfileImage(user)}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<h1 style={{ marginBottom: "8px" }}>{user.displayName}</h1>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 8,
|
||||
color: vars.color.muted,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div className="achievements-content__user-summary__container">
|
||||
<h1>{user.displayName}</h1>
|
||||
<div className="achievements-content__user-summary__container__stats">
|
||||
<div className="achievements-content__user-summary__container__stats__trophy-count">
|
||||
<TrophyIcon size={13} />
|
||||
<span>
|
||||
{user.unlockedAchievementCount} / {user.totalAchievementCount}
|
||||
@ -164,7 +105,7 @@ function AchievementSummary({ user, isComparison }: AchievementSummaryProps) {
|
||||
<progress
|
||||
max={1}
|
||||
value={user.unlockedAchievementCount / user.totalAchievementCount}
|
||||
className={styles.achievementsProgressBar}
|
||||
className="achievements-content__user-summary__container__stats__progress-bar"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -203,7 +144,7 @@ export function AchievementsContent({
|
||||
};
|
||||
|
||||
const onScroll: React.UIEventHandler<HTMLElement> = (event) => {
|
||||
const heroHeight = heroRef.current?.clientHeight ?? styles.HERO_HEIGHT;
|
||||
const heroHeight = heroRef.current?.clientHeight ?? 150;
|
||||
|
||||
const scrollY = (event.target as HTMLDivElement).scrollTop;
|
||||
if (scrollY >= heroHeight && !isHeaderStuck) {
|
||||
@ -219,10 +160,10 @@ export function AchievementsContent({
|
||||
user: Pick<UserInfo, "profileImageUrl" | "displayName">
|
||||
) => {
|
||||
return (
|
||||
<div className={styles.profileAvatarSmall}>
|
||||
<div className="achievements-content__comparison__small-avatar">
|
||||
{user.profileImageUrl ? (
|
||||
<img
|
||||
className={styles.profileAvatarSmall}
|
||||
className="achievements-content__comparison__small-avatar"
|
||||
src={user.profileImageUrl}
|
||||
alt={user.displayName}
|
||||
/>
|
||||
@ -236,10 +177,10 @@ export function AchievementsContent({
|
||||
if (!objectId || !shop || !gameTitle || !userDetails) return null;
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div className="achievements-content__achievements-list">
|
||||
<img
|
||||
src={steamUrlBuilder.libraryHero(objectId)}
|
||||
style={{ display: "none" }}
|
||||
className="achievements-content__achievements-list__image"
|
||||
alt={gameTitle}
|
||||
onLoad={handleHeroLoad}
|
||||
/>
|
||||
@ -247,38 +188,32 @@ export function AchievementsContent({
|
||||
<section
|
||||
ref={containerRef}
|
||||
onScroll={onScroll}
|
||||
className={styles.container}
|
||||
className="achievements-content__achievements-list__section"
|
||||
>
|
||||
<div
|
||||
className="achievements-content__achievements-list__section__container"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
background: `linear-gradient(0deg, ${vars.color.darkBackground} 0%, ${gameColor} 100%)`,
|
||||
background: `linear-gradient(0deg, #151515 0%, ${gameColor} 100%)`,
|
||||
}}
|
||||
>
|
||||
<div ref={heroRef} className={styles.hero}>
|
||||
<div className={styles.heroContent}>
|
||||
<div
|
||||
ref={heroRef}
|
||||
className="achievements-content__achievements-list__section__container__hero"
|
||||
>
|
||||
<div className="achievements-content__achievements-list__section__container__hero__content">
|
||||
<Link
|
||||
to={buildGameDetailsPath({ shop, objectId, title: gameTitle })}
|
||||
>
|
||||
<img
|
||||
src={steamUrlBuilder.logo(objectId)}
|
||||
className={styles.gameLogo}
|
||||
className="achievements-content__achievements-list__section__container__hero__content__game-logo"
|
||||
alt={gameTitle}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
padding: `${SPACING_UNIT}px`,
|
||||
}}
|
||||
>
|
||||
<div className="achievements-content__achievements-list__section__container__achievements-summary-wrapper">
|
||||
<AchievementSummary
|
||||
user={{
|
||||
...userDetails,
|
||||
@ -298,24 +233,19 @@ export function AchievementsContent({
|
||||
</div>
|
||||
|
||||
{otherUser && (
|
||||
<div className={styles.tableHeader({ stuck: isHeaderStuck })}>
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: hasActiveSubscription
|
||||
? "3fr 1fr 1fr"
|
||||
: "3fr 2fr",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
padding: `${SPACING_UNIT}px ${SPACING_UNIT * 3}px`,
|
||||
}}
|
||||
className={`achievements-content__achievements-list__section__table-header ${isHeaderStuck ? "achievements-content__achievements-list__section__table-header--stuck" : ""}`}
|
||||
>
|
||||
<div
|
||||
className={`achievements-content__achievements-list__section__table-header__container ${hasActiveSubscription ? "achievements-content__achievements-list__section__table-header__container--has-active-subscription" : "achievements-content__achievements-list__section__table-header__container--has-no-active-subscription"}`}
|
||||
>
|
||||
<div></div>
|
||||
{hasActiveSubscription && (
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div className="achievements-content__achievements-list__section__table-header__container__user-avatar">
|
||||
{getProfileImage({ ...userDetails })}
|
||||
</div>
|
||||
)}
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div className="achievements-content__achievements-list__section__table-header__container__other-user-avatar">
|
||||
{getProfileImage(otherUser)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,197 +0,0 @@
|
||||
import { SPACING_UNIT, vars } from "../../theme.css";
|
||||
import { style } from "@vanilla-extract/css";
|
||||
import { recipe } from "@vanilla-extract/recipes";
|
||||
|
||||
export const HERO_HEIGHT = 150;
|
||||
const LOGO_HEIGHT = 100;
|
||||
const LOGO_MAX_WIDTH = 200;
|
||||
|
||||
export const wrapper = style({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
transition: "all ease 0.3s",
|
||||
});
|
||||
|
||||
export const hero = style({
|
||||
width: "100%",
|
||||
height: `${HERO_HEIGHT}px`,
|
||||
minHeight: `${HERO_HEIGHT}px`,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
transition: "all ease 0.2s",
|
||||
});
|
||||
|
||||
export const heroContent = style({
|
||||
padding: `${SPACING_UNIT * 2}px`,
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
});
|
||||
|
||||
export const gameLogo = style({
|
||||
width: LOGO_MAX_WIDTH,
|
||||
height: LOGO_HEIGHT,
|
||||
objectFit: "contain",
|
||||
transition: "all ease 0.2s",
|
||||
":hover": {
|
||||
transform: "scale(1.05)",
|
||||
},
|
||||
});
|
||||
|
||||
export const container = style({
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "auto",
|
||||
zIndex: "1",
|
||||
});
|
||||
|
||||
export const tableHeader = recipe({
|
||||
base: {
|
||||
width: "100%",
|
||||
backgroundColor: vars.color.darkBackground,
|
||||
transition: "all ease 0.2s",
|
||||
borderBottom: `solid 1px ${vars.color.border}`,
|
||||
position: "sticky",
|
||||
top: "0",
|
||||
zIndex: "1",
|
||||
},
|
||||
variants: {
|
||||
stuck: {
|
||||
true: {
|
||||
boxShadow: "0px 0px 15px 0px rgba(0, 0, 0, 0.8)",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const list = style({
|
||||
listStyle: "none",
|
||||
margin: "0",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
padding: `${SPACING_UNIT * 2}px`,
|
||||
width: "100%",
|
||||
backgroundColor: vars.color.background,
|
||||
});
|
||||
|
||||
export const listItem = style({
|
||||
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%)",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const achievementsProgressBar = style({
|
||||
width: "100%",
|
||||
height: "8px",
|
||||
transition: "all ease 0.2s",
|
||||
"::-webkit-progress-bar": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
||||
borderRadius: "4px",
|
||||
},
|
||||
"::-webkit-progress-value": {
|
||||
backgroundColor: vars.color.muted,
|
||||
borderRadius: "4px",
|
||||
},
|
||||
});
|
||||
|
||||
export const heroLogoBackdrop = style({
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "flex-end",
|
||||
});
|
||||
|
||||
export const heroImageSkeleton = style({
|
||||
height: "150px",
|
||||
});
|
||||
|
||||
export const heroPanelSkeleton = style({
|
||||
width: "100%",
|
||||
padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: vars.color.background,
|
||||
height: "72px",
|
||||
borderBottom: `solid 1px ${vars.color.border}`,
|
||||
});
|
||||
|
||||
export const listItemSkeleton = style({
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
borderRadius: "4px",
|
||||
padding: `${SPACING_UNIT}px ${SPACING_UNIT}px`,
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
});
|
||||
|
||||
export const profileAvatar = style({
|
||||
height: "54px",
|
||||
width: "54px",
|
||||
borderRadius: "4px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: vars.color.background,
|
||||
position: "relative",
|
||||
objectFit: "cover",
|
||||
});
|
||||
|
||||
export const profileAvatarSmall = style({
|
||||
height: "32px",
|
||||
width: "32px",
|
||||
borderRadius: "4px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: vars.color.background,
|
||||
position: "relative",
|
||||
objectFit: "cover",
|
||||
});
|
||||
|
||||
export const subscriptionRequiredButton = style({
|
||||
textDecoration: "none",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
gap: `${SPACING_UNIT / 2}px`,
|
||||
color: vars.color.body,
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
textDecoration: "underline",
|
||||
},
|
||||
});
|
@ -3,7 +3,6 @@ import { useAppDispatch, useUserDetails } from "@renderer/hooks";
|
||||
import type { ComparedAchievements, GameShop } from "@types";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { vars } from "@renderer/theme.css";
|
||||
import {
|
||||
GameDetailsContextConsumer,
|
||||
GameDetailsContextProvider,
|
||||
@ -75,10 +74,7 @@ export default function Achievements() {
|
||||
(otherUserId && comparedAchievements === null);
|
||||
|
||||
return (
|
||||
<SkeletonTheme
|
||||
baseColor={vars.color.background}
|
||||
highlightColor="#444"
|
||||
>
|
||||
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
|
||||
{showSkeleton ? (
|
||||
<AchievementsSkeleton />
|
||||
) : (
|
||||
|
@ -19,4 +19,62 @@
|
||||
border: 1px solid globals.$border-color;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__filters-wrapper {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__filters-list {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
gap: calc(globals.$spacing-unit * 2);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__games-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__pagination-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
&__result-count {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&__filters-sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__skeleton {
|
||||
height: 105px;
|
||||
border-radius: 4px;
|
||||
border: solid 1px rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import "./catalogue.scss";
|
||||
|
||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||
import { downloadSourcesTable } from "@renderer/dexie";
|
||||
import { FilterSection } from "./filter-section";
|
||||
import { setFilters, setPage } from "@renderer/features";
|
||||
@ -230,25 +229,9 @@ export default function Catalogue() {
|
||||
|
||||
return (
|
||||
<div className="catalogue" ref={cataloguePageRef}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
|
||||
<ul
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
flexWrap: "wrap",
|
||||
listStyle: "none",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
}}
|
||||
>
|
||||
<div className="catalogue__header">
|
||||
<div className="catalogue__filters-wrapper">
|
||||
<ul className="catalogue__filters-list">
|
||||
{groupedFilters.map((filter) => (
|
||||
<li key={`${filter.key}-${filter.value}`}>
|
||||
<FilterItem
|
||||
@ -270,50 +253,20 @@ export default function Catalogue() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: SPACING_UNIT * 2,
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div className="catalogue__content">
|
||||
<div className="catalogue__games-container">
|
||||
{isLoading ? (
|
||||
<SkeletonTheme
|
||||
baseColor={vars.color.darkBackground}
|
||||
highlightColor={vars.color.background}
|
||||
>
|
||||
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
|
||||
{Array.from({ length: PAGE_SIZE }).map((_, i) => (
|
||||
<Skeleton
|
||||
key={i}
|
||||
style={{
|
||||
height: 105,
|
||||
borderRadius: 4,
|
||||
border: `solid 1px ${vars.color.border}`,
|
||||
}}
|
||||
/>
|
||||
<Skeleton key={i} className="catalogue__skeleton" />
|
||||
))}
|
||||
</SkeletonTheme>
|
||||
) : (
|
||||
results.map((game) => <GameItem key={game.id} game={game} />)
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
marginTop: 16,
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 12 }}>
|
||||
<div className="catalogue__pagination-container">
|
||||
<span className="catalogue__result-count">
|
||||
{t("result_count", {
|
||||
resultCount: formatNumber(itemsCount),
|
||||
})}
|
||||
@ -333,7 +286,7 @@ export default function Catalogue() {
|
||||
</div>
|
||||
|
||||
<div className="catalogue__filters-container">
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||
<div className="catalogue__filters-sections">
|
||||
{filterSections.map((section) => (
|
||||
<FilterSection
|
||||
key={section.key}
|
||||
|
@ -12,8 +12,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { SkeletonTheme } from "react-loading-skeleton";
|
||||
import { GameDetailsSkeleton } from "./game-details-skeleton";
|
||||
|
||||
import { vars } from "@renderer/theme.css";
|
||||
|
||||
import { GameDetailsContent } from "./game-details-content";
|
||||
import {
|
||||
CloudSyncContextConsumer,
|
||||
@ -148,10 +146,7 @@ export default function GameDetails() {
|
||||
)}
|
||||
</CloudSyncContextConsumer>
|
||||
|
||||
<SkeletonTheme
|
||||
baseColor={vars.color.background}
|
||||
highlightColor="#444"
|
||||
>
|
||||
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
|
||||
{isLoading ? <GameDetailsSkeleton /> : <GameDetailsContent />}
|
||||
|
||||
<RepacksModal
|
||||
|
@ -1,6 +1,10 @@
|
||||
@use "../../../scss/globals.scss";
|
||||
|
||||
.repacks-modal {
|
||||
&__filter-container {
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
|
||||
&__repacks {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
|
@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { Badge, Button, Modal, TextField } from "@renderer/components";
|
||||
import type { GameRepack } from "@types";
|
||||
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { DownloadSettingsModal } from "./download-settings-modal";
|
||||
import { gameDetailsContext } from "@renderer/context";
|
||||
import { Downloader } from "@shared";
|
||||
@ -85,7 +84,7 @@ export function RepacksModal({
|
||||
description={t("repacks_modal_description")}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div style={{ marginBottom: `${SPACING_UNIT * 2}px` }}>
|
||||
<div className="repacks-modal__filter-container">
|
||||
<TextField placeholder={t("filter")} onChange={handleFilter} />
|
||||
</div>
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Skeleton, { SkeletonTheme } from "react-loading-skeleton";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { HowLongToBeatCategory } from "@types";
|
||||
import { vars } from "@renderer/theme.css";
|
||||
import { SidebarSection } from "../sidebar-section/sidebar-section";
|
||||
import "./sidebar.scss";
|
||||
|
||||
@ -29,7 +28,7 @@ export function HowLongToBeatSection({
|
||||
if (!howLongToBeatData && !isLoading) return null;
|
||||
|
||||
return (
|
||||
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
||||
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
|
||||
<SidebarSection title="HowLongToBeat">
|
||||
<ul className="how-long-to-beat__categories-list">
|
||||
{howLongToBeatData
|
||||
|
@ -11,7 +11,6 @@ import flameIconStatic from "@renderer/assets/icons/flame-static.png";
|
||||
import flameIconAnimated from "@renderer/assets/icons/flame-animated.gif";
|
||||
import starsIconAnimated from "@renderer/assets/icons/stars-animated.gif";
|
||||
|
||||
import { vars } from "@renderer/theme.css";
|
||||
import { buildGameDetailsPath } from "@renderer/helpers";
|
||||
import { CatalogueCategory } from "@shared";
|
||||
import "./home.scss";
|
||||
@ -94,7 +93,7 @@ export default function Home() {
|
||||
};
|
||||
|
||||
return (
|
||||
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
||||
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
|
||||
<section className="home__content">
|
||||
<h2>{t("featured")}</h2>
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
import { createGlobalTheme } from "@vanilla-extract/css";
|
||||
|
||||
export const SPACING_UNIT = 8;
|
||||
|
||||
export const vars = createGlobalTheme(":root", {
|
||||
color: {
|
||||
background: "#1c1c1c",
|
||||
darkBackground: "#151515",
|
||||
muted: "#c0c1c7",
|
||||
body: "#8e919b",
|
||||
border: "rgba(255, 255, 255, 0.15)",
|
||||
success: "#1c9749",
|
||||
danger: "#e11d48",
|
||||
warning: "#ffc107",
|
||||
},
|
||||
opacity: {
|
||||
disabled: "0.5",
|
||||
active: "0.7",
|
||||
},
|
||||
size: {
|
||||
body: "14px",
|
||||
small: "12px",
|
||||
},
|
||||
zIndex: {
|
||||
toast: "5",
|
||||
bottomPanel: "3",
|
||||
titleBar: "4",
|
||||
backdrop: "4",
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue
Block a user