Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI/UX] Improve sidebar #3671

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
"title": "Title"
},
"docs": "Documentation",
"donate": "Donate",
"download-manager": {
"ETA": "Estimated time",
"install-type": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
.currentDownload {
font-size: var(--text-sm);
padding: var(--space-md) 0;
transition: 300ms;
margin-top: var(--space-sm);

& > .gameTitle {
font-size: var(--text-md);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useContext, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import LinearProgress from '@mui/material/LinearProgress'
import Typography from '@mui/material/Typography'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
Expand All @@ -18,6 +17,9 @@ type Props = {
runner: Runner
}

const EOS_APP_NAME = '98bc04bc842e4906993fd6d6644ffb8d'
const EOS_APP_RUNNER = 'legendary'

export default React.memo(function CurrentDownload({ appName, runner }: Props) {
const [progress] = hasProgress(appName)
const [gameTitle, setGameTitle] = useState('')
Expand All @@ -28,10 +30,7 @@ export default React.memo(function CurrentDownload({ appName, runner }: Props) {
const getGameTitle = async () => {
// Hack for EOS Overlay. Not sure if this can be done better
let title
if (
appName === '98bc04bc842e4906993fd6d6644ffb8d' &&
runner === 'legendary'
) {
if (appName === EOS_APP_NAME && runner === EOS_APP_RUNNER) {
title = 'EOS Overlay'
} else {
title = (await getGameInfo(appName, runner))!.title
Expand All @@ -52,37 +51,35 @@ export default React.memo(function CurrentDownload({ appName, runner }: Props) {
}

return (
<>
<Link to={`/download-manager`} className="currentDownload">
<span className="statusIcon" title={`${getStatus()} - ${gameTitle}`}>
<Badge
badgeContent={`${Math.round(progress.percent ?? 0)}%`}
color="primary"
>
<FontAwesomeIcon icon={faDownload} />
</Badge>
</span>
<div className="currentDownload">
<span className="statusIcon" title={`${getStatus()} - ${gameTitle}`}>
<Badge
badgeContent={`${Math.round(progress.percent ?? 0)}%`}
color="primary"
>
<FontAwesomeIcon icon={faDownload} />
</Badge>
</span>

<div className="full-size">
<span className="gameTitle">{gameTitle ?? 'GameName'}</span>
<br />
<span className="downloadStatus">{getStatus()}</span>
<br />
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Box sx={{ width: '100%', mr: 1 }}>
<LinearProgress
variant="determinate"
value={progress.percent || 0}
/>
</Box>
<Box sx={{ minWidth: 35 }}>
<Typography variant="body2">{`${Math.round(
progress.percent || 0
)}%`}</Typography>
</Box>
<div className="full-size">
<span className="gameTitle">{gameTitle ?? 'GameName'}</span>
<br />
<span className="downloadStatus">{getStatus()}</span>
<br />
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Box sx={{ width: '100%', mr: 1 }}>
<LinearProgress
variant="determinate"
value={progress.percent || 0}
/>
</Box>
<Box sx={{ minWidth: 35 }}>
<Typography variant="body2">{`${Math.round(
progress.percent || 0
)}%`}</Typography>
</Box>
</div>
</Link>
</>
</Box>
</div>
</div>
)
})
115 changes: 115 additions & 0 deletions src/frontend/components/UI/Sidebar/components/ExtraLinks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {
faBookOpen,
faCoffee,
faHeart
} from '@fortawesome/free-solid-svg-icons'
import { ExpandMore } from '@mui/icons-material'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { NavLink } from 'react-router-dom'
import classNames from 'classnames'
import React, { useContext, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { faDiscord, faPatreon } from '@fortawesome/free-brands-svg-icons'
import { openDiscordLink } from 'frontend/helpers'

import ContextProvider from 'frontend/state/ContextProvider'
import QuitButton from '../QuitButton'
import { SHOW_EXTERNAL_LINK_DIALOG_STORAGE_KEY } from 'frontend/components/UI/ExternalLinkDialog'
import { Accordion, AccordionDetails, AccordionSummary } from '@mui/material'

export default function ExtraLinks() {
const { t } = useTranslation()

const { handleExternalLinkDialog } = useContext(ContextProvider)

const [isDonateExpanded, setIsDonateExpanded] = useState(false)

function handleExternalLink(linkCallback: () => void) {
const showExternalLinkDialog: boolean = JSON.parse(
localStorage.getItem(SHOW_EXTERNAL_LINK_DIALOG_STORAGE_KEY) ?? 'true'
)
if (showExternalLinkDialog) {
handleExternalLinkDialog({ showDialog: true, linkCallback })
} else {
linkCallback()
}
}

return (
<div className="SidebarLinks Sidebar__section">
<NavLink
data-testid="wiki"
className={({ isActive }) =>
classNames('Sidebar__item', { active: isActive })
}
to={{ pathname: '/wiki' }}
data-tooltip-content={t('docs', 'Documentation')}
>
<div className="Sidebar__itemIcon">
<FontAwesomeIcon
icon={faBookOpen}
title={t('docs', 'Documentation')}
/>
</div>
<span>{t('docs', 'Documentation')}</span>
</NavLink>
<button
className="Sidebar__item"
onClick={() => handleExternalLink(openDiscordLink)}
data-tooltip-content={t('userselector.discord', 'Discord')}
>
<div className="Sidebar__itemIcon">
<FontAwesomeIcon
icon={faDiscord}
title={t('userselector.discord', 'Discord')}
/>
</div>
<span>{t('userselector.discord', 'Discord')}</span>
</button>
<div
className={classNames('Sidebar__item', {
active: isDonateExpanded
})}
data-tooltip-content={t('donate', 'Donate')}
tabIndex={-1}
>
<Accordion
expanded={isDonateExpanded}
onChange={() => setIsDonateExpanded(!isDonateExpanded)}
>
<AccordionSummary expandIcon={<ExpandMore />}>
<div className="Sidebar__itemIcon">
<FontAwesomeIcon icon={faHeart} title={t('donate', 'Donate')} />
</div>
<span>{t('donate', 'Donate')}</span>
</AccordionSummary>
<AccordionDetails>
<div className="SidebarSubmenu">
<button
className="Sidebar__item SidebarLinks__subItem"
onClick={() => handleExternalLink(window.api.openPatreonPage)}
data-tooltip-content="Patreon"
>
<div className="Sidebar__itemIcon">
<FontAwesomeIcon icon={faPatreon} title="Patreon" />
</div>
<span>Patreon</span>
</button>
<button
className="Sidebar__item SidebarLinks__subItem"
onClick={() => handleExternalLink(window.api.openKofiPage)}
data-tooltip-content="Ko-fi"
>
<div className="Sidebar__itemIcon">
<FontAwesomeIcon icon={faCoffee} title="Ko-fi" />
</div>
<span>Ko-fi</span>
</button>
</div>
</AccordionDetails>
</Accordion>
</div>
<QuitButton />
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import ContextProvider from 'frontend/state/ContextProvider'
import { ChangelogModal } from '../../../ChangelogModal'
import { faCircleUp } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

type Release = {
html_url: string
Expand Down Expand Up @@ -48,12 +50,39 @@ export default React.memo(function HeroicVersion() {
const newBeta: Release | undefined = newReleases?.filter(
(r) => r.type === 'beta'
)[0]
const shouldShowUpdates = newBeta || newStable
const releaseInfo = newBeta || newStable
const releaseType = newStable
? t('info.heroic.stable', 'Stable')
: t('info.heroic.beta', 'Beta')

const version = heroicVersion

return (
<>
{releaseInfo && (
<a
className="Sidebar__item"
title={releaseInfo.tag_name}
onClick={() => window.api.openExternalUrl(releaseInfo.html_url)}
data-tooltip-content={t(
'info.heroic.newReleases',
'Update Available!'
)}
>
<div className="Sidebar__itemIcon">
<FontAwesomeIcon
icon={faCircleUp}
title={t('info.heroic.newReleases', 'Update Available!')}
/>
</div>
<div className="heroicNewReleases">
<span>{t('info.heroic.newReleases', 'Update Available!')}</span>
<span className="highlighted">
{releaseType} ({releaseInfo.tag_name})
</span>
</div>
</a>
)}
{((showChangelogModal &&
!hideChangelogsOnStartup &&
heroicVersion !== lastChangelogShown) ||
Expand Down Expand Up @@ -81,27 +110,6 @@ export default React.memo(function HeroicVersion() {
</span>
<strong>{version}</strong>
</span>
{shouldShowUpdates && (
<div className="heroicNewReleases">
<span>{t('info.heroic.newReleases', 'Update Available!')}</span>
{newStable && (
<a
title={newStable.tag_name}
onClick={() => window.api.openExternalUrl(newStable.html_url)}
>
{t('info.heroic.stable', 'Stable')} ({newStable.tag_name})
</a>
)}
{newBeta && (
<a
title={newBeta.tag_name}
onClick={() => window.api.openExternalUrl(newBeta.html_url)}
>
{t('info.heroic.beta', 'Beta')} ({newBeta.tag_name})
</a>
)}
</div>
)}
</>
)
})
Loading
Loading