refactor: remove vanilla-extract

This commit is contained in:
Hachi-R 2025-02-01 03:00:14 -03:00
parent e4631bba7b
commit f6e4852f4a
16 changed files with 373 additions and 547 deletions

View File

@ -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",

View File

@ -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",
});

View File

@ -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;
}

View File

@ -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

View 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;
}
}

View File

@ -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>

View File

@ -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",
},
});

View File

@ -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 />
) : (

View File

@ -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);
}
}

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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",
},
});