diff --git a/src/renderer/src/app.css.ts b/src/renderer/src/app.css.ts index cadab243..65264240 100644 --- a/src/renderer/src/app.css.ts +++ b/src/renderer/src/app.css.ts @@ -7,6 +7,7 @@ globalStyle("*", { globalStyle("::-webkit-scrollbar", { width: "9px", + backgroundColor: vars.color.darkBackground, }); globalStyle("::-webkit-scrollbar-track", { diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 325e1506..67df3084 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -10,7 +10,6 @@ import { } from "@renderer/hooks"; import * as styles from "./app.css"; -import { themeClass } from "./theme.css"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; import { @@ -21,8 +20,6 @@ import { closeToast, } from "@renderer/features"; -document.body.classList.add(themeClass); - export interface AppProps { children: React.ReactNode; } diff --git a/src/renderer/src/components/backdrop/backdrop.css.ts b/src/renderer/src/components/backdrop/backdrop.css.ts index 3b8cc4e2..1c95717e 100644 --- a/src/renderer/src/components/backdrop/backdrop.css.ts +++ b/src/renderer/src/components/backdrop/backdrop.css.ts @@ -1,5 +1,6 @@ import { keyframes } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; + import { SPACING_UNIT } from "../../theme.css"; export const backdropFadeIn = keyframes({ diff --git a/src/renderer/src/components/badge/badge.css.ts b/src/renderer/src/components/badge/badge.css.ts index 5cc674b5..46cb7b87 100644 --- a/src/renderer/src/components/badge/badge.css.ts +++ b/src/renderer/src/components/badge/badge.css.ts @@ -1,4 +1,5 @@ import { style } from "@vanilla-extract/css"; + import { SPACING_UNIT } from "../../theme.css"; export const badge = style({ diff --git a/src/renderer/src/components/bottom-panel/bottom-panel.css.ts b/src/renderer/src/components/bottom-panel/bottom-panel.css.ts index 22f71fe4..a1f5d1a8 100644 --- a/src/renderer/src/components/bottom-panel/bottom-panel.css.ts +++ b/src/renderer/src/components/bottom-panel/bottom-panel.css.ts @@ -1,4 +1,5 @@ import { style } from "@vanilla-extract/css"; + import { SPACING_UNIT, vars } from "../../theme.css"; export const bottomPanel = style({ diff --git a/src/renderer/src/components/checkbox-field/checkbox-field.css.ts b/src/renderer/src/components/checkbox-field/checkbox-field.css.ts index 1aa7ee0e..606b226a 100644 --- a/src/renderer/src/components/checkbox-field/checkbox-field.css.ts +++ b/src/renderer/src/components/checkbox-field/checkbox-field.css.ts @@ -1,6 +1,7 @@ -import { SPACING_UNIT, vars } from "../../theme.css"; import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT, vars } from "../../theme.css"; + export const checkboxField = style({ display: "flex", flexDirection: "row", diff --git a/src/renderer/src/components/game-card/game-card.css.ts b/src/renderer/src/components/game-card/game-card.css.ts index b05b38b6..c810130d 100644 --- a/src/renderer/src/components/game-card/game-card.css.ts +++ b/src/renderer/src/components/game-card/game-card.css.ts @@ -1,4 +1,5 @@ import { style } from "@vanilla-extract/css"; + import { SPACING_UNIT, vars } from "../../theme.css"; export const card = style({ diff --git a/src/renderer/src/components/hero/hero.css.ts b/src/renderer/src/components/hero/hero.css.ts index fb8f6833..cdb36ee2 100644 --- a/src/renderer/src/components/hero/hero.css.ts +++ b/src/renderer/src/components/hero/hero.css.ts @@ -1,4 +1,5 @@ import { style } from "@vanilla-extract/css"; + import { SPACING_UNIT, vars } from "../../theme.css"; export const hero = style({ diff --git a/src/renderer/src/components/modal/modal.css.ts b/src/renderer/src/components/modal/modal.css.ts index 110f16f8..45154015 100644 --- a/src/renderer/src/components/modal/modal.css.ts +++ b/src/renderer/src/components/modal/modal.css.ts @@ -1,5 +1,6 @@ import { keyframes, style } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; + import { SPACING_UNIT, vars } from "../../theme.css"; export const scaleFadeIn = keyframes({ diff --git a/src/renderer/src/components/modal/modal.tsx b/src/renderer/src/components/modal/modal.tsx index a71b781e..eb2894de 100644 --- a/src/renderer/src/components/modal/modal.tsx +++ b/src/renderer/src/components/modal/modal.tsx @@ -14,6 +14,7 @@ export interface ModalProps { onClose: () => void; large?: boolean; children: React.ReactNode; + clickOutsideToClose?: boolean; } export function Modal({ @@ -23,6 +24,7 @@ export function Modal({ onClose, large, children, + clickOutsideToClose = true, }: ModalProps) { const [isClosing, setIsClosing] = useState(false); const modalContentRef = useRef(null); @@ -60,6 +62,18 @@ export function Modal({ } }; + window.addEventListener("keydown", onKeyDown); + + return () => { + window.removeEventListener("keydown", onKeyDown); + }; + } + + return () => {}; + }, [handleCloseClick, visible]); + + useEffect(() => { + if (clickOutsideToClose) { const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; if (modalContentRef.current) { @@ -73,17 +87,15 @@ export function Modal({ } }; - window.addEventListener("keydown", onKeyDown); window.addEventListener("mousedown", onMouseDown); return () => { - window.removeEventListener("keydown", onKeyDown); window.removeEventListener("mousedown", onMouseDown); }; } return () => {}; - }, [handleCloseClick, visible]); + }, [clickOutsideToClose, handleCloseClick]); if (!visible) return null; diff --git a/src/renderer/src/components/select-field/select-field.css.ts b/src/renderer/src/components/select-field/select-field.css.ts index 83a21c37..7acd4e98 100644 --- a/src/renderer/src/components/select-field/select-field.css.ts +++ b/src/renderer/src/components/select-field/select-field.css.ts @@ -1,7 +1,8 @@ -import { SPACING_UNIT, vars } from "../../theme.css"; import { style } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; +import { SPACING_UNIT, vars } from "../../theme.css"; + export const select = recipe({ base: { display: "inline-flex", diff --git a/src/renderer/src/components/sidebar/routes.tsx b/src/renderer/src/components/sidebar/routes.tsx index 8f54bac0..5535c243 100644 --- a/src/renderer/src/components/sidebar/routes.tsx +++ b/src/renderer/src/components/sidebar/routes.tsx @@ -1,4 +1,5 @@ import { AppsIcon, GearIcon, HomeIcon } from "@primer/octicons-react"; + import { DownloadIcon } from "./download-icon"; export const routes = [ diff --git a/src/renderer/src/components/sidebar/sidebar.css.ts b/src/renderer/src/components/sidebar/sidebar.css.ts index 929241fa..6677bf63 100644 --- a/src/renderer/src/components/sidebar/sidebar.css.ts +++ b/src/renderer/src/components/sidebar/sidebar.css.ts @@ -1,5 +1,6 @@ import { style } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; + import { SPACING_UNIT, vars } from "../../theme.css"; export const sidebar = recipe({ @@ -11,6 +12,7 @@ export const sidebar = recipe({ transition: "opacity ease 0.2s", borderRight: `solid 1px ${vars.color.border}`, position: "relative", + overflow: "hidden", }, variants: { resizing: { @@ -123,3 +125,46 @@ export const section = style({ flexDirection: "column", paddingBottom: `${SPACING_UNIT}px`, }); + +export const profileButton = style({ + display: "flex", + cursor: "pointer", + transition: "all ease 0.1s", + gap: `${SPACING_UNIT + SPACING_UNIT / 2}px`, + alignItems: "center", + padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`, + color: vars.color.muted, + borderBottom: `solid 1px ${vars.color.border}`, + boxShadow: "0px 0px 15px 0px #000000", + ":hover": { + backgroundColor: "rgba(255, 255, 255, 0.15)", + }, +}); + +export const profileAvatar = style({ + width: "30px", + height: "30px", + borderRadius: "50%", + display: "flex", + justifyContent: "center", + alignItems: "center", + backgroundColor: vars.color.background, + position: "relative", +}); + +export const profileButtonInformation = style({ + display: "flex", + flexDirection: "column", + alignItems: "flex-start", +}); + +export const statusBadge = style({ + width: "9px", + height: "9px", + borderRadius: "50%", + backgroundColor: vars.color.danger, + position: "absolute", + bottom: "-2px", + right: "-3px", + zIndex: "1", +}); diff --git a/src/renderer/src/components/sidebar/sidebar.tsx b/src/renderer/src/components/sidebar/sidebar.tsx index 3032359e..897d6b18 100644 --- a/src/renderer/src/components/sidebar/sidebar.tsx +++ b/src/renderer/src/components/sidebar/sidebar.tsx @@ -13,6 +13,7 @@ import * as styles from "./sidebar.css"; import { buildGameDetailsPath } from "@renderer/helpers"; import SteamLogo from "@renderer/assets/steam-logo.svg?react"; +import { PersonIcon } from "@primer/octicons-react"; const SIDEBAR_MIN_WIDTH = 200; const SIDEBAR_INITIAL_WIDTH = 250; @@ -143,93 +144,109 @@ export function Sidebar() { }; return ( - + - - - ); -} diff --git a/src/renderer/src/pages/game-details/modals/installation-guides/index.ts b/src/renderer/src/pages/game-details/modals/installation-guides/index.ts deleted file mode 100644 index ff5b129e..00000000 --- a/src/renderer/src/pages/game-details/modals/installation-guides/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./online-fix-installation-guide"; -export * from "./dodi-installation-guide"; -export * from "./constants"; diff --git a/src/renderer/src/pages/game-details/modals/installation-guides/online-fix-installation-guide.css.ts b/src/renderer/src/pages/game-details/modals/installation-guides/online-fix-installation-guide.css.ts deleted file mode 100644 index b7665d7d..00000000 --- a/src/renderer/src/pages/game-details/modals/installation-guides/online-fix-installation-guide.css.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { SPACING_UNIT } from "../../../../theme.css"; -import { style } from "@vanilla-extract/css"; - -export const passwordField = style({ - display: "flex", - gap: `${SPACING_UNIT}px`, -}); diff --git a/src/renderer/src/pages/game-details/modals/installation-guides/online-fix-installation-guide.tsx b/src/renderer/src/pages/game-details/modals/installation-guides/online-fix-installation-guide.tsx deleted file mode 100644 index 3460eaec..00000000 --- a/src/renderer/src/pages/game-details/modals/installation-guides/online-fix-installation-guide.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { Button, CheckboxField, Modal, TextField } from "@renderer/components"; -import { SPACING_UNIT } from "@renderer/theme.css"; - -import * as styles from "./online-fix-installation-guide.css"; -import { CopyIcon } from "@primer/octicons-react"; -import { DONT_SHOW_ONLINE_FIX_INSTRUCTIONS_KEY } from "./constants"; - -const ONLINE_FIX_PASSWORD = "online-fix.me"; - -export interface OnlineFixInstallationGuideProps { - visible: boolean; - onClose: () => void; -} - -export function OnlineFixInstallationGuide({ - visible, - onClose, -}: OnlineFixInstallationGuideProps) { - const [clipboardLocked, setClipboardLocked] = useState(false); - const { t } = useTranslation("game_details"); - - const [dontShowAgain, setDontShowAgain] = useState(false); - - const handleCopyToClipboard = () => { - setClipboardLocked(true); - - navigator.clipboard.writeText(ONLINE_FIX_PASSWORD); - - const zero = performance.now(); - - requestAnimationFrame(function holdLock(time) { - if (time - zero <= 3000) { - requestAnimationFrame(holdLock); - } else { - setClipboardLocked(false); - } - }); - }; - - const handleClose = () => { - if (dontShowAgain) { - window.localStorage.setItem(DONT_SHOW_ONLINE_FIX_INSTRUCTIONS_KEY, "1"); - } - - onClose(); - }; - - return ( - -
-

{t("online_fix_instruction")}

-
- - - -
- - setDontShowAgain(!dontShowAgain)} - checked={dontShowAgain} - /> - - -
-
- ); -} diff --git a/src/renderer/src/pages/game-details/modals/remove-from-library-modal.css.ts b/src/renderer/src/pages/game-details/modals/remove-from-library-modal.css.ts index eb676e57..2c70717d 100644 --- a/src/renderer/src/pages/game-details/modals/remove-from-library-modal.css.ts +++ b/src/renderer/src/pages/game-details/modals/remove-from-library-modal.css.ts @@ -1,6 +1,7 @@ -import { SPACING_UNIT } from "../../../theme.css"; import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT } from "../../../theme.css"; + export const deleteActionsButtonsCtn = style({ display: "flex", width: "100%", diff --git a/src/renderer/src/pages/game-details/modals/repacks-modal.css.ts b/src/renderer/src/pages/game-details/modals/repacks-modal.css.ts index 897d88f0..8d54e402 100644 --- a/src/renderer/src/pages/game-details/modals/repacks-modal.css.ts +++ b/src/renderer/src/pages/game-details/modals/repacks-modal.css.ts @@ -1,4 +1,5 @@ import { style } from "@vanilla-extract/css"; + import { SPACING_UNIT, vars } from "../../../theme.css"; export const repacks = style({ diff --git a/src/renderer/src/pages/game-details/modals/repacks-modal.tsx b/src/renderer/src/pages/game-details/modals/repacks-modal.tsx index 6c7a30eb..feae8e0e 100644 --- a/src/renderer/src/pages/game-details/modals/repacks-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/repacks-modal.tsx @@ -7,10 +7,10 @@ import type { GameRepack } from "@types"; import * as styles from "./repacks-modal.css"; -import { SPACING_UNIT } from "../../../theme.css"; +import { SPACING_UNIT } from "@renderer/theme.css"; import { format } from "date-fns"; import { DownloadSettingsModal } from "./download-settings-modal"; -import { gameDetailsContext } from "../game-details.context"; +import { gameDetailsContext } from "@renderer/context"; import { Downloader } from "@shared"; export interface RepacksModalProps { @@ -32,7 +32,7 @@ export function RepacksModal({ const [repack, setRepack] = useState(null); const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); - const [infoHash, setInfoHash] = useState(""); + const [infoHash, setInfoHash] = useState(null); const { repacks, game } = useContext(gameDetailsContext); @@ -40,7 +40,7 @@ export function RepacksModal({ const getInfoHash = useCallback(async () => { const torrent = await parseTorrent(game?.uri ?? ""); - setInfoHash(torrent.infoHash ?? ""); + if (torrent.infoHash) setInfoHash(torrent.infoHash); }, [game]); useEffect(() => { @@ -89,29 +89,35 @@ export function RepacksModal({
- {filteredRepacks.map((repack) => ( - - ))} + {isLastDownloadedOption && ( + {t("last_downloaded_option")} + )} + +

+ {repack.fileSize} - {repack.repacker} -{" "} + {repack.uploadDate + ? format(repack.uploadDate, "dd/MM/yyyy") + : ""} +

+ + ); + })}
diff --git a/src/renderer/src/pages/game-details/sidebar/how-long-to-beat-section.tsx b/src/renderer/src/pages/game-details/sidebar/how-long-to-beat-section.tsx index ab4e7a4c..ffd148e5 100644 --- a/src/renderer/src/pages/game-details/sidebar/how-long-to-beat-section.tsx +++ b/src/renderer/src/pages/game-details/sidebar/how-long-to-beat-section.tsx @@ -1,7 +1,8 @@ import Skeleton, { SkeletonTheme } from "react-loading-skeleton"; import { useTranslation } from "react-i18next"; import type { HowLongToBeatCategory } from "@types"; -import { vars } from "../../../theme.css"; +import { vars } from "@renderer/theme.css"; + import * as styles from "./sidebar.css"; const durationTranslation: Record = { diff --git a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx index 780f5964..6c963ee9 100644 --- a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx +++ b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next"; import { Button } from "@renderer/components"; import * as styles from "./sidebar.css"; -import { gameDetailsContext } from "../game-details.context"; +import { gameDetailsContext } from "@renderer/context"; export function Sidebar() { const [howLongToBeat, setHowLongToBeat] = useState<{ diff --git a/src/renderer/src/pages/home/catalogue-home.css.ts b/src/renderer/src/pages/home/catalogue-home.css.ts index c9f00cd7..8096bf97 100644 --- a/src/renderer/src/pages/home/catalogue-home.css.ts +++ b/src/renderer/src/pages/home/catalogue-home.css.ts @@ -1,5 +1,6 @@ import { style } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; + import { SPACING_UNIT } from "../../theme.css"; export const catalogueCategories = style({ diff --git a/src/renderer/src/pages/home/home.css.ts b/src/renderer/src/pages/home/home.css.ts index b44da04a..7c6597ab 100644 --- a/src/renderer/src/pages/home/home.css.ts +++ b/src/renderer/src/pages/home/home.css.ts @@ -1,4 +1,5 @@ import { style } from "@vanilla-extract/css"; + import { SPACING_UNIT, vars } from "../../theme.css"; export const homeHeader = style({ diff --git a/src/renderer/src/pages/home/home.tsx b/src/renderer/src/pages/home/home.tsx index 4ae2184e..d8c10917 100644 --- a/src/renderer/src/pages/home/home.tsx +++ b/src/renderer/src/pages/home/home.tsx @@ -10,7 +10,7 @@ import type { Steam250Game, CatalogueEntry } from "@types"; import starsAnimation from "@renderer/assets/lottie/stars.json"; import * as styles from "./home.css"; -import { vars } from "../../theme.css"; +import { vars } from "@renderer/theme.css"; import Lottie from "lottie-react"; import { buildGameDetailsPath } from "@renderer/helpers"; diff --git a/src/renderer/src/pages/home/search-results.tsx b/src/renderer/src/pages/home/search-results.tsx index be461918..30b3ea68 100644 --- a/src/renderer/src/pages/home/search-results.tsx +++ b/src/renderer/src/pages/home/search-results.tsx @@ -9,13 +9,14 @@ import { debounce } from "lodash"; import { InboxIcon } from "@primer/octicons-react"; import { clearSearch } from "@renderer/features"; import { useAppDispatch } from "@renderer/hooks"; -import { vars } from "../../theme.css"; import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate, useSearchParams } from "react-router-dom"; import * as styles from "./home.css"; import { buildGameDetailsPath } from "@renderer/helpers"; +import { vars } from "@renderer/theme.css"; + export function SearchResults() { const dispatch = useAppDispatch(); diff --git a/src/renderer/src/pages/settings/settings-real-debrid.tsx b/src/renderer/src/pages/settings/settings-real-debrid.tsx index d774de7e..3dc4186d 100644 --- a/src/renderer/src/pages/settings/settings-real-debrid.tsx +++ b/src/renderer/src/pages/settings/settings-real-debrid.tsx @@ -4,9 +4,10 @@ import { Trans, useTranslation } from "react-i18next"; import { Button, CheckboxField, Link, TextField } from "@renderer/components"; import * as styles from "./settings-real-debrid.css"; import type { UserPreferences } from "@types"; -import { SPACING_UNIT } from "@renderer/theme.css"; import { useAppSelector, useToast } from "@renderer/hooks"; +import { SPACING_UNIT } from "@renderer/theme.css"; + const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken"; export interface SettingsRealDebridProps { diff --git a/src/renderer/src/pages/settings/settings.css.ts b/src/renderer/src/pages/settings/settings.css.ts index b73ba786..9f607ece 100644 --- a/src/renderer/src/pages/settings/settings.css.ts +++ b/src/renderer/src/pages/settings/settings.css.ts @@ -1,6 +1,7 @@ -import { SPACING_UNIT, vars } from "../../theme.css"; import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT, vars } from "../../theme.css"; + export const container = style({ padding: "24px", width: "100%", diff --git a/src/renderer/src/pages/shared-modals/binary-not-found-modal.tsx b/src/renderer/src/pages/shared-modals/binary-not-found-modal.tsx index 06a216cb..eeb0983a 100644 --- a/src/renderer/src/pages/shared-modals/binary-not-found-modal.tsx +++ b/src/renderer/src/pages/shared-modals/binary-not-found-modal.tsx @@ -1,6 +1,7 @@ -import { Modal } from "@renderer/components"; import { useTranslation } from "react-i18next"; +import { Modal } from "@renderer/components"; + interface BinaryNotFoundModalProps { visible: boolean; onClose: () => void; diff --git a/src/renderer/src/theme.css.ts b/src/renderer/src/theme.css.ts index 1789e8a4..c748c1c7 100644 --- a/src/renderer/src/theme.css.ts +++ b/src/renderer/src/theme.css.ts @@ -1,8 +1,8 @@ -import { createTheme } from "@vanilla-extract/css"; +import { createGlobalTheme } from "@vanilla-extract/css"; export const SPACING_UNIT = 8; -export const [themeClass, vars] = createTheme({ +export const vars = createGlobalTheme(":root", { color: { background: "#1c1c1c", darkBackground: "#151515",