Skip to content

Commit

Permalink
[UI] Redesign Game page (Heroic-Games-Launcher#2884)
Browse files Browse the repository at this point in the history
* Some work for the Game Page redesign

* Game Page Redesign: update translation

* Game Page Redesign: game scores, report problem, some paddings

* Game Page Red: hide non-functional uninstall button

* GamePage redesign: some fixes for small windows

* feat: add backgrounds to game page

* improv: give more control over image load animations to CSS

added simple hook that allows to conveniently add load animation to any img component

* fix: minor bugs

- download size indicators not displayed untill gameInstallInfo was fetched
- old design bug
- cutoff under new design image on left panel

* Game Page Redesign: limit size for big screens

* Game Page Redesign: Use cached image for background

* Game Page Redesign: Fix anticheat info in big screens

---------

Co-authored-by: Paweł Lidwin <[email protected]>
  • Loading branch information
arielj and imLinguin authored Oct 3, 2023
1 parent 695f1c6 commit 221fa0d
Show file tree
Hide file tree
Showing 26 changed files with 1,078 additions and 462 deletions.
2 changes: 1 addition & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@
"esync": "Enable Esync",
"exit-to-tray": "Exit to System Tray",
"experimental_features": {
"enableNewShinyFeature": "New shiny feature"
"enableNewDesign": "New design"
},
"FsrSharpnessStrenght": "FSR Sharpness Strength",
"fsync": "Enable Fsync",
Expand Down
3 changes: 3 additions & 0 deletions src/backend/storeManagers/gog/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,9 @@ export async function gogToUnifiedInfo(
art_square: info.game.vertical_cover.url_format
.replace('{formatter}', '')
.replace('{ext}', 'jpg'),
art_background: info.game.background.url_format
.replace('{formatter}', '')
.replace('{ext}', 'webp'),
cloud_save_enabled: false,
extra: {
about: { description: info.summary['*'], shortDescription: '' },
Expand Down
3 changes: 2 additions & 1 deletion src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export type Release = {
}

export type ExperimentalFeatures = {
enableNewShinyFeature: boolean // remove this when adding a real experimental feature
enableNewDesign: boolean
}

export interface AppSettings extends GameSettings {
Expand Down Expand Up @@ -109,6 +109,7 @@ export interface GameInfo {
app_name: string
art_cover: string
art_logo?: string
art_background?: string
art_square: string
cloud_save_enabled?: boolean
developer?: string
Expand Down
9 changes: 9 additions & 0 deletions src/frontend/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ svg.disabled {
color: var(--background);
}

img.loading {
opacity: 0;
}

img.loaded {
transition: opacity 500ms;
opacity: 1;
}

.react-contextmenu--visible {
background-color: var(--input-background);
padding: var(--space-md) var(--space-lg);
Expand Down
6 changes: 4 additions & 2 deletions src/frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import ExternalLinkDialog from './components/UI/ExternalLinkDialog'
import classNames from 'classnames'

function App() {
const { isSettingsModalOpen, isRTL } = useContext(ContextProvider)
const { isSettingsModalOpen, isRTL, experimentalFeatures } =
useContext(ContextProvider)

return (
<div
id="app"
className={classNames('App', {
isRTL
isRTL,
oldDesign: !experimentalFeatures.enableNewDesign
})}
>
<HashRouter>
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/components/UI/Anticheat/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
.statusInfo {
flex-direction: column;
display: flex;
padding-inline-start: var(--space-md);
margin-inline: auto;
text-align: start;
}
}

Expand Down
13 changes: 12 additions & 1 deletion src/frontend/components/UI/CachedImage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { useState } from 'react'
interface CachedImageProps {
src: string
fallback?: string
className?: string
}

type Props = React.ImgHTMLAttributes<HTMLImageElement> & CachedImageProps
Expand All @@ -11,6 +12,7 @@ const CachedImage = (props: Props) => {
const [useCache, setUseCache] = useState(
props.src?.startsWith('http') || false
)
const [loaded, setLoaded] = useState(false)
const [useFallback, setUseFallback] = useState(false)

const onError = () => {
Expand All @@ -29,7 +31,16 @@ const CachedImage = (props: Props) => {
let src = useFallback ? props.fallback : props.src
src = useCache ? `imagecache://${src}` : src

return <img loading="lazy" {...props} src={src} onError={onError} />
return (
<img
loading="lazy"
onLoad={() => setLoaded(true)}
{...props}
src={src}
onError={onError}
className={`${props.className} ${loaded ? 'loaded' : 'loading'}`}
/>
)
}

export default CachedImage
9 changes: 1 addition & 8 deletions src/frontend/components/UI/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useRef, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'

import CurrentDownload from './components/CurrentDownload'
import SidebarLinks from './components/SidebarLinks'
Expand All @@ -8,7 +8,6 @@ import { DMQueueElement } from 'common/types'

import { ReactComponent as HeroicIcon } from 'frontend/assets/heroic-icon.svg'
import { useNavigate } from 'react-router-dom'
import ContextProvider from 'frontend/state/ContextProvider'

let sidebarSize = localStorage.getItem('sidebar-width') || 240
const minWidth = 60
Expand All @@ -18,7 +17,6 @@ const collapsedWidth = 120
export default React.memo(function Sidebar() {
const sidebarEl = useRef<HTMLDivElement | null>(null)
const [currentDMElement, setCurrentDMElement] = useState<DMQueueElement>()
const { experimentalFeatures } = useContext(ContextProvider)

const navigate = useNavigate()

Expand Down Expand Up @@ -146,11 +144,6 @@ export default React.memo(function Sidebar() {
)}
</div>
<HeroicVersion />
{/* remove this when adding a real experimental feature */}
{experimentalFeatures.enableNewShinyFeature && (
<p>New Shiny Feature enabled</p>
)}
{/* remove */}
<div className="resizer" onMouseDown={handleDragStart} />
</aside>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React from 'react'
import React, { useContext } from 'react'
import './index.scss'
import { PCGamingWikiInfo } from 'common/types'
import classNames from 'classnames'
import { createNewWindow } from 'frontend/helpers'
import ContextProvider from 'frontend/state/ContextProvider'

type Props = {
title: string
info: PCGamingWikiInfo
}

export default function GameScore({ title, info }: Props) {
const { experimentalFeatures } = useContext(ContextProvider)

if (!info || (!info.metacritic && !info.opencritic && !info.igdb)) {
return null
}
Expand All @@ -34,6 +37,63 @@ export default function GameScore({ title, info }: Props) {
return null
}

if (experimentalFeatures.enableNewDesign) {
return (
<>
{metacritic.score && (
<a
onClick={() => {
if (metacritic.urlid) {
createNewWindow(
`https://www.metacritic.com/game/pc/${metacritic.urlid}`
)
} else {
createNewWindow(
`https://www.metacritic.com/search/all/${title}/results`
)
}
}}
>
<b>MetaCritic</b>
{`${metacritic.score}`}
</a>
)}
{opencritic.score && (
<a
className={classNames('circle', getColorClass(opencritic.score))}
onClick={() => {
if (opencritic.urlid) {
createNewWindow(
`https://opencritic.com/game/${opencritic.urlid}`
)
}
}}
>
<b>OpenCritic</b>
{`${opencritic.score}`}
</a>
)}
{igdb.score && (
<a
className={classNames('circle', getColorClass(igdb.score))}
onClick={() => {
if (metacritic.urlid) {
createNewWindow(
`https://www.igdb.com/games/${metacritic.urlid}`
)
} else {
createNewWindow(`https://www.igdb.com/search?type=1&q=${title}`)
}
}}
>
<b>IGDB</b>
{`${igdb.score}`}
</a>
)}
</>
)
}

return (
<>
<div className="gamescore">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const AppleWikiInfo = ({ gameInfo }: Props) => {
}}
>
<WineBar />
{t('info.apple-gaming-wiki', 'AppleGamingWiki Rating')}:{' '}
<b>{t('info.apple-gaming-wiki', 'AppleGamingWiki Rating')}:</b>
{applegamingwiki.crossoverRating.charAt(0).toUpperCase() +
applegamingwiki.crossoverRating.slice(1)}
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ const CloudSavesSync = ({ gameInfo }: Props) => {
className="iconWithText"
>
<CloudQueue />
<b>{t('info.syncsaves')}</b>
{': '}
<b>{t('info.syncsaves')}:</b>
{autoSyncSaves ? t('enabled') : t('disabled')}
</p>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,21 @@ const CompatibilityInfo = ({ gameInfo }: Props) => {
className="iconWithText"
>
<WineBar />
{t(
'info.protondb-compatibility-info',
'Proton Compatibility Tier'
)}:{' '}
<b>
{t('info.protondb-compatibility-info', 'Proton Compatibility Tier')}
:
</b>
{steamInfo!.compatibilityLevel!.charAt(0).toUpperCase() +
steamInfo!.compatibilityLevel!.slice(1)}
</a>
)}
{hasSteamDeckCompat && (
<a className="iconWithText" style={{ cursor: 'default' }}>
<WineBar />
{t(
'info.steamdeck-compatibility-info',
'SteamDeck Compatibility'
)}: {steamLevelNames[steamInfo?.steamDeckCatagory ?? 3]}
<b>
{t('info.steamdeck-compatibility-info', 'SteamDeck Compatibility')}:
</b>
{steamLevelNames[steamInfo?.steamDeckCatagory ?? 3]}
</a>
)}
</>
Expand Down
14 changes: 7 additions & 7 deletions src/frontend/screens/Game/GamePage/components/Description.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ const Description = () => {
const { t } = useTranslation('gamepage')
const { gameExtraInfo, runner } = useContext(GameContext)

if (runner === 'sideload') {
return null
}
let description = ''

const description =
gameExtraInfo?.about?.shortDescription ||
gameExtraInfo?.about?.description ||
t('generic.noDescription', 'No description available')
if (runner !== 'sideload') {
description =
gameExtraInfo?.about?.shortDescription ||
gameExtraInfo?.about?.description ||
t('generic.noDescription', 'No description available')
}

return <div className="summary">{description}</div>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ const DownloadSizeInfo = ({ gameInfo }: Props) => {
return null
}

if (!gameInstallInfo) {
return null
}

if (gameInfo.thirdPartyManagedApp) {
return null
}
Expand All @@ -50,19 +46,16 @@ const DownloadSizeInfo = ({ gameInfo }: Props) => {
<>
<div className="iconWithText">
<CloudDownload />
<b>{t('game.downloadSize', 'Download Size')}</b>
{': '}
<b>{t('game.downloadSize', 'Download Size')}:</b>
{downloadSize ??
`${t('game.getting-download-size', 'Geting download size')}...`}
</div>
<div className="iconWithText">
<Storage />
<b>{t('game.installSize', 'Install Size')}</b>
{': '}
<b>{t('game.installSize', 'Install Size')}:</b>
{installSize ??
`${t('game.getting-install-size', 'Geting install size')}...`}
</div>
<br />
</>
)
}
Expand Down
Loading

0 comments on commit 221fa0d

Please sign in to comment.