From 2ce0e45af45ae1ecafcb8e9d1c4a7f485e02eb4b Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 13:44:53 -0300 Subject: [PATCH 01/13] Delete settings scren code unused since the game settings were moved to a modal --- src/frontend/screens/Settings/index.tsx | 51 +++++-------------------- 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/src/frontend/screens/Settings/index.tsx b/src/frontend/screens/Settings/index.tsx index 72f91136a7..eac77c7528 100644 --- a/src/frontend/screens/Settings/index.tsx +++ b/src/frontend/screens/Settings/index.tsx @@ -2,7 +2,7 @@ import './index.css' import React, { useEffect, useState } from 'react' -import { NavLink, useLocation, useParams } from 'react-router-dom' +import { NavLink, useParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import ArrowCircleLeftIcon from '@mui/icons-material/ArrowCircleLeft' @@ -19,7 +19,7 @@ import { } from './sections' import { AppSettings, WineInstallation } from 'common/types' import { UpdateComponent } from 'frontend/components/UI' -import { LocationState, SettingsContextType } from 'frontend/types' +import { SettingsContextType } from 'frontend/types' import useSettingsContext from 'frontend/hooks/useSettingsContext' import { hasHelp } from 'frontend/hooks/hasHelp' @@ -31,34 +31,23 @@ export const defaultWineVersion: WineInstallation = { function Settings() { const { t, i18n } = useTranslation() - const { - state: { fromGameCard, runner, gameInfo } - } = useLocation() as { state: LocationState } const [title, setTitle] = useState('') const [currentConfig, setCurrentConfig] = useState>({}) const { appName = '', type = '' } = useParams() - const isDefault = appName === 'default' const isGeneralSettings = type === 'general' const isSyncSettings = type === 'sync' const isGamesSettings = type === 'games_settings' const isLogSettings = type === 'log' - const isAdvancedSetting = type === 'advanced' && isDefault - const isSystemInfo = type === 'systeminfo' && isDefault + const isAdvancedSetting = type === 'advanced' + const isSystemInfo = type === 'systeminfo' let helpContent = t( 'help.content.settingsDefault', 'Shows all settings of Heroic and defaults for games.' ) - if (!isDefault) { - helpContent = t( - 'help.content.settingsGame', - 'Show all settings for a game.' - ) - } - hasHelp( 'settings', t('help.title.settings', 'Settings'), @@ -68,34 +57,17 @@ function Settings() { // Load Heroic's or game's config, only if not loaded already useEffect(() => { const getSettings = async () => { - const config = isDefault - ? await window.api.requestAppSettings() - : await window.api.requestGameSettings(appName) + const config = await window.api.requestAppSettings() setCurrentConfig(config) - if (!isDefault) { - setTitle(gameInfo?.title ?? appName) - } else { - setTitle(t('globalSettings', 'Global Settings')) - } + setTitle(t('globalSettings', 'Global Settings')) } getSettings() - }, [appName, isDefault, i18n.language]) - - // generate return path - let returnPath = '/' - if (!fromGameCard) { - returnPath = `/gamepage/${runner}/${appName}` - if (returnPath.includes('default')) { - returnPath = '/' - } - } + }, [appName, i18n.language]) // create setting context functions const contextValues: SettingsContextType | null = useSettingsContext({ - appName, - gameInfo, - runner + appName }) // render `loading` while we fetch the settings @@ -127,12 +99,7 @@ function Settings() {
- +

From 15293ca1d050fe607bd22758ffceeb54ee08780b Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 13:45:34 -0300 Subject: [PATCH 02/13] These changes are needed for the previous commit too --- src/frontend/hooks/useSettingsContext.ts | 4 ++-- src/frontend/types.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontend/hooks/useSettingsContext.ts b/src/frontend/hooks/useSettingsContext.ts index cd0b704471..43f8489063 100644 --- a/src/frontend/hooks/useSettingsContext.ts +++ b/src/frontend/hooks/useSettingsContext.ts @@ -6,8 +6,8 @@ import ContextProvider from 'frontend/state/ContextProvider' type Props = { appName: string - gameInfo: GameInfo - runner: Runner + gameInfo?: GameInfo + runner?: Runner } const useSettingsContext = ({ appName, gameInfo, runner }: Props) => { diff --git a/src/frontend/types.ts b/src/frontend/types.ts index b80f2f8c28..1701b9f3be 100644 --- a/src/frontend/types.ts +++ b/src/frontend/types.ts @@ -188,8 +188,8 @@ export interface SettingsContextType { config: Partial isDefault: boolean appName: string - runner: Runner - gameInfo: GameInfo | null + runner?: Runner + gameInfo?: GameInfo isMacNative: boolean isLinuxNative: boolean } From 1850db172d18ca5b96d5f9fc5efb51b38b7f1723 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 13:46:26 -0300 Subject: [PATCH 03/13] Create a SidebarItem to cleanup the SidebarLinks component --- .../Sidebar/components/SidebarItem/index.tsx | 60 +++ .../Sidebar/components/SidebarLinks/index.tsx | 397 ++++++------------ 2 files changed, 191 insertions(+), 266 deletions(-) create mode 100644 src/frontend/components/UI/Sidebar/components/SidebarItem/index.tsx diff --git a/src/frontend/components/UI/Sidebar/components/SidebarItem/index.tsx b/src/frontend/components/UI/Sidebar/components/SidebarItem/index.tsx new file mode 100644 index 0000000000..2bf3e21955 --- /dev/null +++ b/src/frontend/components/UI/Sidebar/components/SidebarItem/index.tsx @@ -0,0 +1,60 @@ +import React, { MouseEventHandler } from 'react' +import classNames from 'classnames' +import { NavLink } from 'react-router-dom' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { IconProp } from '@fortawesome/fontawesome-svg-core' +import './index.css' + +interface SidebarItemProps { + label: string + url?: string + icon?: IconProp + isActiveFallback?: boolean + onClick?: MouseEventHandler + className?: string + elementType?: 'a' | 'button' +} + +export default function SidebarItem({ + icon, + label, + url = '', + isActiveFallback = false, + onClick, + className, + elementType +}: SidebarItemProps) { + const itemContent = ( + <> + {icon && ( +
+ +
+ )} + {label} + + ) + + switch (elementType) { + case 'button': + return ( + + ) + default: + return ( + + classNames('Sidebar__item', className, { + active: isActive || isActiveFallback + }) + } + to={url} + onClick={onClick} + > + {itemContent} + + ) + } +} diff --git a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx index d89e47e78c..276bcdbe5c 100644 --- a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx +++ b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx @@ -10,9 +10,7 @@ import { faWineGlass, faBarsProgress } from '@fortawesome/free-solid-svg-icons' -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { NavLink, useLocation } from 'react-router-dom' -import classNames from 'classnames' +import { useLocation } from 'react-router-dom' import React, { useContext } from 'react' import { useTranslation } from 'react-i18next' import { faDiscord, faPatreon } from '@fortawesome/free-brands-svg-icons' @@ -20,10 +18,9 @@ import { openDiscordLink } from 'frontend/helpers' import ContextProvider from 'frontend/state/ContextProvider' import { Runner } from 'common/types' -import './index.css' import QuitButton from '../QuitButton' -import { LocationState } from 'frontend/types' import { SHOW_EXTERNAL_LINK_DIALOG_STORAGE_KEY } from 'frontend/components/UI/ExternalLinkDialog' +import SidebarItem from '../SidebarItem' type PathSplit = [ a: undefined, @@ -35,9 +32,8 @@ type PathSplit = [ export default function SidebarLinks() { const { t } = useTranslation() - const { state } = useLocation() as { state: LocationState } const location = useLocation() as { pathname: string } - const [, , runner, appName, type] = location.pathname.split('/') as PathSplit + const [, , , , type] = location.pathname.split('/') as PathSplit const { amazon, @@ -54,8 +50,6 @@ export default function SidebarLinks() { const isSettings = location.pathname.includes('settings') const isWin = platform === 'win32' - const settingsPath = '/settings/app/default/general' - const loggedIn = epic.username || gog.username || amazon.user_id async function handleRefresh() { @@ -101,288 +95,159 @@ export default function SidebarLinks() { return (
{!loggedIn && ( - - classNames('Sidebar__item', { active: isActive }) - } - to={'/login'} - > - <> -
- -
- {t('button.login', 'Login')} - -
+ )} - - classNames('Sidebar__item', { - active: isActive || location.pathname.includes('gamepage') - }) - } - to={'/'} + handleRefresh()} - > - <> -
- -
- {t('Library')} - -
+ /> +
- - classNames('Sidebar__item', { - active: isActive || location.pathname.includes('store') - }) - } - to={`/store/${defaultStore}`} - > - <> -
- -
- {t('stores', 'Stores')} - -
+ {inWebviewScreen && (
- - classNames('Sidebar__item', 'SidebarLinks__subItem', { - active: isActive - }) - } - to="/store/epic" - > - {t('store', 'Epic Store')} - - - classNames('Sidebar__item', 'SidebarLinks__subItem', { - active: isActive - }) - } - to="/store/gog" - > - {t('gog-store', 'GOG Store')} - - - classNames('Sidebar__item', 'SidebarLinks__subItem', { - active: isActive - }) - } - to="/store/amazon" - > - {t('prime-gaming', 'Prime Gaming')} - + + +
)}
- - classNames('Sidebar__item', { - active: isActive || location.pathname.includes('settings') - }) - } - to={{ pathname: settingsPath }} - state={{ - fromGameCard: false - }} - > - <> -
- -
- {t('Settings', 'Settings')} - -
+ {isSettings && (
- - {t('settings.navbar.general')} - + + {!isWin && ( - - - {t( - 'settings.navbar.games_settings_defaults', - 'Game Defaults' - )} - - + )} - - {t('settings.navbar.advanced', 'Advanced')} - - - - {t('settings.navbar.systemInformation', 'System Information')} - - - - {t('settings.navbar.log', 'Log')} - + + + + + +
)}
- - classNames('Sidebar__item', { active: isActive }) - } - to={{ pathname: '/download-manager' }} - > - <> -
- -
- {t('download-manager.link', 'Downloads')} - -
+ + {!isWin && ( - - classNames('Sidebar__item', { active: isActive }) - } - to={{ pathname: '/wine-manager' }} - > - <> -
- -
- {t('wine.manager.link', 'Wine Manager')} - -
+ )} + {loggedIn && ( - -
- -
- {t('userselector.manageaccounts', 'Manage Accounts')} -
+ )} - - classNames('Sidebar__item', { active: isActive }) - } - to={{ pathname: '/accessibility' }} - > - <> -
- -
- {t('accessibility.title', 'Accessibility')} - -
+ + +
- - classNames('Sidebar__item', { active: isActive }) - } - to={{ pathname: '/wiki' }} - > - <> -
- -
- {t('docs', 'Documentation')} - -
- - - + icon={faCoffee} + label="Ko-fi" + /> +
) From c521950a78ee1ba4e0e441bb96ebf97adc83fc7f Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 13:46:41 -0300 Subject: [PATCH 04/13] Update/cleanup CSS for all sidebar components --- .../components/CurrentDownload/index.css | 52 ++++ .../components/CurrentDownload/index.scss | 40 --- .../components/CurrentDownload/index.tsx | 60 ++--- .../components/HeroicVersion/index.css | 47 ++++ .../components/HeroicVersion/index.tsx | 1 + .../Sidebar/components/SidebarItem/index.css | 111 ++++++++ .../Sidebar/components/SidebarLinks/index.css | 35 --- src/frontend/components/UI/Sidebar/index.css | 140 ++++++++++ src/frontend/components/UI/Sidebar/index.scss | 251 ------------------ src/frontend/components/UI/Sidebar/index.tsx | 2 +- 10 files changed, 381 insertions(+), 358 deletions(-) create mode 100644 src/frontend/components/UI/Sidebar/components/CurrentDownload/index.css delete mode 100644 src/frontend/components/UI/Sidebar/components/CurrentDownload/index.scss create mode 100644 src/frontend/components/UI/Sidebar/components/HeroicVersion/index.css create mode 100644 src/frontend/components/UI/Sidebar/components/SidebarItem/index.css delete mode 100644 src/frontend/components/UI/Sidebar/components/SidebarLinks/index.css create mode 100644 src/frontend/components/UI/Sidebar/index.css delete mode 100644 src/frontend/components/UI/Sidebar/index.scss diff --git a/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.css b/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.css new file mode 100644 index 0000000000..ba2d772af7 --- /dev/null +++ b/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.css @@ -0,0 +1,52 @@ +.Sidebar { + .currentDownload { + font-size: var(--text-sm); + padding: var(--space-md) 0; + transition: 300ms; + margin-top: var(--space-sm); + align-self: end; + + & > .gameTitle { + font-size: var(--text-md); + transition: 600ms; + font-weight: var(--bold); + } + + &:hover > .gameTitle { + color: var(--accent-overlay); + transition: 600ms; + } + + .downloadStatus { + color: var(--success); + font-family: var(--secondary-font-family); + font-style: italic; + font-weight: normal; + font-size: var(--text-sm); + line-height: var(--text-sm); + } + + .MuiLinearProgress-bar1Determinate { + background-color: var(--success); + } + + .statusIcon { + display: none; + margin-inline-end: 10px; + svg { + width: 27px; + height: auto; + color: var(--success); + } + } + } + + &.collapsed { + .statusIcon { + display: block; + } + .full-size { + display: none; + } + } +} diff --git a/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.scss b/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.scss deleted file mode 100644 index 14375cd181..0000000000 --- a/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.scss +++ /dev/null @@ -1,40 +0,0 @@ -.currentDownload { - font-size: var(--text-sm); - padding: var(--space-md) 0; - transition: 300ms; - margin-top: var(--space-sm); - - & > .gameTitle { - font-size: var(--text-md); - transition: 600ms; - font-weight: var(--bold); - } - - &:hover > .gameTitle { - color: var(--accent-overlay); - transition: 600ms; - } - - .downloadStatus { - color: var(--success); - font-family: var(--secondary-font-family); - font-style: italic; - font-weight: normal; - font-size: var(--text-sm); - line-height: var(--text-sm); - } - - .MuiLinearProgress-bar1Determinate { - background-color: var(--success); - } - - .statusIcon { - display: none; - margin-inline-end: 10px; - svg { - width: 27px; - height: auto; - color: var(--success); - } - } -} diff --git a/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.tsx b/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.tsx index 77ea259484..c56a0fcae9 100644 --- a/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.tsx +++ b/src/frontend/components/UI/Sidebar/components/CurrentDownload/index.tsx @@ -8,7 +8,7 @@ import Box from '@mui/material/Box' import { getGameInfo } from 'frontend/helpers' import { hasProgress } from 'frontend/hooks/hasProgress' import { Runner } from 'common/types' -import './index.scss' +import './index.css' import { useTranslation } from 'react-i18next' import ContextProvider from 'frontend/state/ContextProvider' import Badge from '@mui/material/Badge' @@ -52,37 +52,35 @@ export default React.memo(function CurrentDownload({ appName, runner }: Props) { } return ( - <> - - - - - - + + + + + + -
- {gameTitle ?? 'GameName'} -
- {getStatus()} -
- - - - - - {`${Math.round( - progress.percent || 0 - )}%`} - +
+ {gameTitle ?? 'GameName'} +
+ {getStatus()} +
+ + + -
- - + + {`${Math.round( + progress.percent || 0 + )}%`} + +
+
+ ) }) diff --git a/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.css b/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.css new file mode 100644 index 0000000000..e3a3626036 --- /dev/null +++ b/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.css @@ -0,0 +1,47 @@ +.Sidebar { + .heroicVersion { + display: flex; + gap: 5px; + font-size: var(--text-sm); + cursor: pointer; + transition: 300ms; + color: var(--brand-text-01); + + &:hover { + color: var(--accent); + } + } + + .heroicNewReleases { + display: flex; + flex-direction: column; + justify-content: space-around; + font-size: var(--text-sm); + + & > a { + color: var(--accent); + transition: 300ms; + -webkit-app-region: no-drag; + cursor: pointer; + + &:hover { + color: var(--accent-overlay); + } + } + } + + &.collapsed { + .heroicVersion { + font-size: var(--text-xs); + text-align: center; + } + + .heroicVersion__title { + display: none; + } + + .heroicNewReleases { + display: none; + } + } +} diff --git a/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.tsx b/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.tsx index d594b4fb94..7001f3e6e5 100644 --- a/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.tsx +++ b/src/frontend/components/UI/Sidebar/components/HeroicVersion/index.tsx @@ -2,6 +2,7 @@ import React, { useContext, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import ContextProvider from 'frontend/state/ContextProvider' import { ChangelogModal } from '../../../ChangelogModal' +import './index.css' type Release = { html_url: string diff --git a/src/frontend/components/UI/Sidebar/components/SidebarItem/index.css b/src/frontend/components/UI/Sidebar/components/SidebarItem/index.css new file mode 100644 index 0000000000..c11a3e1988 --- /dev/null +++ b/src/frontend/components/UI/Sidebar/components/SidebarItem/index.css @@ -0,0 +1,111 @@ +.Sidebar { + .Sidebar__item { + --sidebar-item-inactive-text-color: var( + --navbar-inactive, + var(--navbar-accent) + ); + --sidebar-hover-text-color: var(--text-hover); + --sidebar-item-active-text-color: var( + --navbar-active, + var(--accent-overlay, var(--accent)) + ); + --sidebar-active-item-background: var(--navbar-active-background); + + display: flex; + gap: 10px; + width: 100%; + padding: var(--space-xs) var(--sidebar-horizontal-padding); + border: none; + background: none; + cursor: pointer; + font-size: var(--text-md); + color: var(--sidebar-item-inactive-text-color); + transition: color 250ms; + text-align: start; + font-family: var(--primary-font-family); + + .Sidebar__itemIcon { + width: 24px; + display: inline-flex; + justify-content: center; + } + + &:focus-visible { + outline: 2px solid var(--sidebar-hover-text-color); + outline-offset: -2px; + } + + &.active { + color: var(--sidebar-item-active-text-color); + + .Sidebar__itemIcon { + color: currentColor; + } + + &.SidebarLinks__subItem { + font-weight: var(--bold); + } + } + &.active:not(.SidebarLinks__subItem) { + background-color: var(--sidebar-active-item-background); + } + + &.SidebarLinks__subItem { + &, + &:hover { + padding-block: var(--space-3xs); + padding-inline: var(--space-xl) var(--sidebar-horizontal-padding); + font-size: var(--text-sm); + line-height: 20px; + white-space: break-spaces; + } + &::before { + content: '• '; + } + & + .Sidebar__item:not(.SidebarLinks__subItem) { + margin-top: 4px; + } + } + + &:hover { + background-color: var(--navbar-active-background); + transition: 0.1s; + padding-inline-start: 12px; + } + + @media screen and (max-width: 730px) { + &, + &:hover { + padding: var(--space-3xs) var(--sidebar-horizontal-padding) + var(--space-3xs) var(--space-lg); + } + } + } + + &.collapsed { + .Sidebar__item { + padding: var(--space-xs) 0; + + & > span { + display: none; + } + + &.SidebarLinks__subItem { + padding: var(--space-xs) var(--sidebar-horizontal-padding); + &::before { + display: none; + } + } + + &.active svg, + & svg { + transform: scale(1.2); + padding: var(--space-2xs) 0; + } + + .Sidebar__itemIcon { + margin: 0 auto; + } + } + } +} diff --git a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.css b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.css deleted file mode 100644 index f34fd1c38b..0000000000 --- a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.css +++ /dev/null @@ -1,35 +0,0 @@ -.SidebarLinks { - grid-area: links; - font-size: var(--text-lg); -} - -.Sidebar__item.SidebarLinks__subItem, -.Sidebar__item.SidebarLinks__subItem:hover { - padding-block: var(--space-3xs); - padding-inline: var(--space-xl) var(--sidebar-horizontal-padding); - font-size: var(--text-sm); - line-height: 20px; - white-space: break-spaces; -} - -.Sidebar__item:hover { - background-color: var(--navbar-active-background); - transition: 0.1s; - padding-inline-start: 12px; -} - -.Sidebar__item.SidebarLinks__subItem::before { - content: '• '; -} - -.SidebarLinks__subItem + .Sidebar__item:not(.SidebarLinks__subItem) { - margin-top: 4px; -} - -@media screen and (max-width: 730px) { - .Sidebar__item.SidebarLinks__subItem, - .Sidebar__item.SidebarLinks__subItem:hover { - padding: var(--space-3xs) var(--sidebar-horizontal-padding) var(--space-3xs) - var(--space-lg); - } -} diff --git a/src/frontend/components/UI/Sidebar/index.css b/src/frontend/components/UI/Sidebar/index.css new file mode 100644 index 0000000000..f08e0dea5d --- /dev/null +++ b/src/frontend/components/UI/Sidebar/index.css @@ -0,0 +1,140 @@ +.Sidebar { + --sidebar-horizontal-padding: var(--space-md); + --sidebar-vertical-padding: var(--space-lg); + --sidebar-width: 350px; + --sidebar-background: var(--navbar-background); + --sidebar-divider-color: var(--divider); + + width: var(--sidebar-width); + position: relative; + z-index: 10; + display: grid; + grid-template-rows: min-content 2fr min-content min-content; + grid-template-areas: 'icon' 'links' 'utils' 'updates' 'version'; + grid-area: sidebar; + padding: 0; + font-family: var(--secondary-font-family); + text-align: start; + background: var(--sidebar-background); + overflow: auto; + overflow-x: hidden; + -webkit-app-region: drag; + + .heroicIcon { + grid-area: icon; + width: 50px; + height: 68px; + margin-top: var(--space-xs); + justify-self: center; + } + + .SidebarLinks { + grid-area: links; + } + + .heroicVersion { + grid-area: version; + margin-block: 0 var(--sidebar-vertical-padding); + margin-inline: var(--sidebar-horizontal-padding) var(--space-3xs); + -webkit-app-region: no-drag; + } + + .heroicNewReleases { + grid-area: updates; + margin-block: 0 var(--space-sm); + margin-inline: var(--sidebar-horizontal-padding) var(--space-3xs); + } + + .Sidebar__section { + -webkit-app-region: no-drag; + } + + .currentDownloads { + grid-area: utils; + margin-block: 0 var(--sidebar-vertical-padding); + margin-inline: var(--sidebar-horizontal-padding) var(--space-3xs); + } + + .divider { + height: 1px; + margin: var(--space-3xs) var(--space-xs); + background-color: var(--sidebar-divider-color); + } + + .resizer { + position: absolute; + top: 0; + right: 0; + width: 10px; + height: 100%; + z-index: 1; + cursor: col-resize; + } + + &.collapsed { + --sidebar-vertical-padding: var(--space-xs); + --sidebar-horizontal-padding: var(--space-lg); + overflow-x: hidden; + overflow-y: auto; + + .currentDownloads { + margin-inline: auto; + } + + .heroicVersion { + margin: var(--space-sm); + } + + .divider { + margin: var(--space-3xs) 0; + } + + .SidebarItemWithSubmenu { + &:has(.SidebarSubmenu) { + position: relative; + z-index: 2; + } + + .SidebarSubmenu { + display: none; + } + + &:hover, + &:focus-within { + .SidebarSubmenu { + display: block; + position: fixed; + left: var(--sidebar-width); + top: 66px; + background-color: var(--sidebar-background); + padding: var(--space-2xs) 0; + + & span { + display: block; + } + + &.settings { + top: 114px; + } + } + } + } + } +} + +.isRTL .Sidebar { + &.collapsed .SidebarItemWithSubmenu { + &:hover, + &:focus-within { + .SidebarSubmenu { + right: var(--sidebar-width); + left: auto; + } + } + } + + & .resizer { + left: 0; + right: auto; + } +} diff --git a/src/frontend/components/UI/Sidebar/index.scss b/src/frontend/components/UI/Sidebar/index.scss deleted file mode 100644 index 50c1ac6bea..0000000000 --- a/src/frontend/components/UI/Sidebar/index.scss +++ /dev/null @@ -1,251 +0,0 @@ -.Sidebar { - --sidebar-horizontal-padding: var(--space-md); - --sidebar-vertical-padding: var(--space-lg); - position: relative; - z-index: 10; - display: grid; - grid-template-rows: min-content 2fr min-content min-content; - grid-template-areas: 'icon' 'links' 'utils' 'updates' 'version'; - grid-area: sidebar; - height: 100%; - padding: 0; - font-family: var(--secondary-font-family); - text-align: start; - background: var(--navbar-background); - overflow: auto; - overflow-x: hidden; - --sidebar-width: 350px; - width: var(--sidebar-width); - -webkit-app-region: drag; - - .heroicIcon { - grid-area: icon; - width: 50px; - height: 68px; - display: flex; - margin-top: var(--space-xs); - justify-self: center; - } -} - -.Sidebar.collapsed { - --sidebar-vertical-padding: var(--space-xs); - --sidebar-horizontal-padding: var(--space-lg); - overflow-x: hidden; - overflow-y: auto; -} - -.Sidebar__section { - display: flex; - width: 100%; - height: fit-content; - font-family: var(--secondary-font-family); - flex-direction: column; - -webkit-app-region: no-drag; -} - -.Sidebar__item { - display: flex; - width: 100%; - padding: var(--space-xs) var(--sidebar-horizontal-padding); - border: none; - background: none; - cursor: pointer; - font-size: var(--text-md); - color: var(--navbar-accent); - color: var(--navbar-inactive, var(--navbar-accent)); - transition: color 250ms; - text-align: start; - font-family: var(--primary-font-family); - border-radius: 0; -} - -.collapsed .Sidebar__item { - padding: var(--space-xs) 0; -} - -.collapsed .Sidebar__itemIcon { - margin: 0 auto; -} -.Sidebar__item:focus-visible { - outline: 2px solid var(--text-hover); - outline-offset: -2px; -} - -.Sidebar__item.active { - color: var(--accent); - color: var(--navbar-active, var(--accent-overlay)); - - .Sidebar__itemIcon { - color: var(--accent); - color: var(--navbar-active, var(--accent-overlay)); - } -} - -.Sidebar__item.active:not(.SidebarLinks__subItem) { - background-color: var(--navbar-active-background); -} - -.Sidebar__item.active.SidebarLinks__subItem { - font-weight: var(--bold); -} - -.Sidebar__itemIcon { - box-sizing: border-box; - width: 24px; - margin-inline-end: 10px; - display: inline-flex; - justify-content: center; - color: var(--accent); - color: var(--navbar-inactive, var(--accent)); -} - -.currentDownloads { - grid-area: utils; - align-self: end; - margin-block: 0 var(--sidebar-vertical-padding); - margin-inline: var(--sidebar-horizontal-padding) var(--space-3xs); -} - -.divider { - height: 1px; - opacity: 0.5; - margin: var(--space-3xs) var(--space-xs); - background-color: var(--divider); -} - -.heroicVersion { - display: flex; - gap: 5px; - grid-area: version; - margin-block: 0 var(--sidebar-vertical-padding); - margin-inline: var(--sidebar-horizontal-padding) var(--space-3xs); - font-size: var(--text-sm); - cursor: pointer; - transition: 300ms; - color: var(--brand-text-01); - -webkit-app-region: no-drag; -} - -.heroicVersion:hover { - color: var(--accent); -} - -.heroicNewReleases { - grid-area: updates; - display: flex; - flex-direction: column; - justify-content: space-around; - margin-block: 0 var(--space-sm); - margin-inline: var(--space-3xs) var(--sidebar-horizontal-padding); - font-size: var(--text-sm); -} - -.heroicNewReleases > a { - color: var(--accent); - transition: 300ms; - -webkit-app-region: no-drag; -} - -.heroicNewReleases > a:hover { - color: var(--accent-overlay); -} - -.Sidebar.collapsed { - .heroicVersion { - margin: var(--space-sm); - font-size: var(--text-xs); - text-align: center; - &__title { - display: none; - } - } - - .heroicNewReleases { - display: none; - } - - .currentDownloads { - margin-inline: auto; - .statusIcon { - display: block; - } - .full-size { - display: none; - } - } -} - -.Sidebar.collapsed .divider { - margin: var(--space-3xs) 0; -} - -.Sidebar.collapsed .Sidebar__item.active span, -.Sidebar.collapsed .Sidebar__item > span { - display: none; -} - -.Sidebar.collapsed .SidebarItemWithSubmenu:has(.SidebarSubmenu) { - position: relative; - z-index: 2; -} - -.Sidebar.collapsed .SidebarItemWithSubmenu .SidebarSubmenu { - display: none; -} - -.Sidebar.collapsed .SidebarItemWithSubmenu:hover .SidebarSubmenu span, -.Sidebar.collapsed .SidebarItemWithSubmenu:focus-within .SidebarSubmenu span { - display: block; -} - -.Sidebar.collapsed .SidebarItemWithSubmenu:hover .SidebarSubmenu, -.Sidebar.collapsed .SidebarItemWithSubmenu:focus-within .SidebarSubmenu { - display: block; - position: fixed; - left: var(--sidebar-width); - top: 66px; - background-color: var(--navbar-background); - padding: var(--space-2xs) 0; -} - -.isRTL .Sidebar.collapsed .SidebarItemWithSubmenu:hover .SidebarSubmenu, -.isRTL .Sidebar.collapsed .SidebarItemWithSubmenu:focus-within .SidebarSubmenu { - right: var(--sidebar-width); - left: auto; -} - -.Sidebar.collapsed .SidebarItemWithSubmenu:hover .SidebarSubmenu.settings, -.Sidebar.collapsed - .SidebarItemWithSubmenu:focus-within - .SidebarSubmenu.settings { - top: 114px; -} - -.Sidebar.collapsed .Sidebar__item.SidebarLinks__subItem::before { - display: none; -} - -.Sidebar.collapsed .Sidebar__item.SidebarLinks__subItem { - padding: var(--space-xs) var(--sidebar-horizontal-padding); -} -.Sidebar.collapsed .Sidebar__item.active svg, -.Sidebar.collapsed .Sidebar__item svg { - transform: scale(1.2); - padding: var(--space-2xs) 0; -} - -.resizer { - position: absolute; - top: 0; - right: 0; - width: 10px; - height: 100%; - z-index: 1; - cursor: col-resize; -} - -.isRTL .resizer { - left: 0; - right: auto; -} diff --git a/src/frontend/components/UI/Sidebar/index.tsx b/src/frontend/components/UI/Sidebar/index.tsx index 8477ba77fe..4617b04306 100644 --- a/src/frontend/components/UI/Sidebar/index.tsx +++ b/src/frontend/components/UI/Sidebar/index.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react' import CurrentDownload from './components/CurrentDownload' import SidebarLinks from './components/SidebarLinks' -import './index.scss' +import './index.css' import HeroicVersion from './components/HeroicVersion' import { DMQueueElement } from 'common/types' From 9c28fbc7604e33cf54b605362024a837e930053a Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 13:50:56 -0300 Subject: [PATCH 05/13] Tell typescript these places do have a valid runner --- src/frontend/components/UI/Winetricks/index.tsx | 8 ++++---- src/frontend/screens/Settings/SettingsContext.tsx | 2 +- src/frontend/screens/Settings/components/OfflineMode.tsx | 2 +- src/frontend/screens/Settings/components/Tools/index.tsx | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/frontend/components/UI/Winetricks/index.tsx b/src/frontend/components/UI/Winetricks/index.tsx index 2047fdcae7..aede2aa2e3 100644 --- a/src/frontend/components/UI/Winetricks/index.tsx +++ b/src/frontend/components/UI/Winetricks/index.tsx @@ -21,7 +21,7 @@ export default function Winetricks({ onClose }: Props) { setLoading(true) try { const components = await window.api.winetricksListInstalled( - runner, + runner!, appName ) setInstalled(components) @@ -39,7 +39,7 @@ export default function Winetricks({ onClose }: Props) { async function listComponents() { try { const components = await window.api.winetricksListAvailable( - runner, + runner!, appName ) setAllComponents(components) @@ -55,7 +55,7 @@ export default function Winetricks({ onClose }: Props) { const [installingComponent, setInstallingComponent] = useState('') const [logs, setLogs] = useState([]) function install(component: string) { - window.api.winetricksInstall(runner, appName, component) + window.api.winetricksInstall(runner!, appName, component) } useEffect(() => { @@ -100,7 +100,7 @@ export default function Winetricks({ onClose }: Props) { window.api.callTool({ tool: 'winetricks', appName, - runner + runner: runner! }) } diff --git a/src/frontend/screens/Settings/SettingsContext.tsx b/src/frontend/screens/Settings/SettingsContext.tsx index 0a28dff343..cff8965bd4 100644 --- a/src/frontend/screens/Settings/SettingsContext.tsx +++ b/src/frontend/screens/Settings/SettingsContext.tsx @@ -9,7 +9,7 @@ const initialContext: SettingsContextType = { isDefault: true, appName: 'default', runner: 'legendary', - gameInfo: null, + gameInfo: undefined, isMacNative: false, isLinuxNative: false } diff --git a/src/frontend/screens/Settings/components/OfflineMode.tsx b/src/frontend/screens/Settings/components/OfflineMode.tsx index a3af91e6b7..175d23fe49 100644 --- a/src/frontend/screens/Settings/components/OfflineMode.tsx +++ b/src/frontend/screens/Settings/components/OfflineMode.tsx @@ -14,7 +14,7 @@ const OfflineMode = () => { useEffect(() => { const getInfo = async () => { - const info = await getGameInfo(appName, runner) + const info = await getGameInfo(appName, runner!) if (info) { const { canRunOffline: can_run_offline } = info setCanRunOffline(can_run_offline) diff --git a/src/frontend/screens/Settings/components/Tools/index.tsx b/src/frontend/screens/Settings/components/Tools/index.tsx index 8ea01942af..2ab97c4bce 100644 --- a/src/frontend/screens/Settings/components/Tools/index.tsx +++ b/src/frontend/screens/Settings/components/Tools/index.tsx @@ -37,7 +37,7 @@ export default function Tools() { tool, exe, appName, - runner + runner: runner! }) if (tool in toolStates) { @@ -47,7 +47,7 @@ export default function Tools() { const handleRunExe = async () => { let exe = '' - const gameinfo = await getGameInfo(appName, runner) + const gameinfo = await getGameInfo(appName, runner!) if (!gameinfo) return const defaultPath = gameinfo.runner === 'sideload' ? undefined : gameinfo.install.install_path From 818f20f00fd3ee3386713f7b749f2778742bbae4 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 14:10:50 -0300 Subject: [PATCH 06/13] Fix linter offense --- src/frontend/screens/Settings/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/screens/Settings/index.tsx b/src/frontend/screens/Settings/index.tsx index eac77c7528..b68b0af4b6 100644 --- a/src/frontend/screens/Settings/index.tsx +++ b/src/frontend/screens/Settings/index.tsx @@ -43,7 +43,7 @@ function Settings() { const isAdvancedSetting = type === 'advanced' const isSystemInfo = type === 'systeminfo' - let helpContent = t( + const helpContent = t( 'help.content.settingsDefault', 'Shows all settings of Heroic and defaults for games.' ) From 733cc2f98df19c36d1afb30d6017bdfe9a2240bb Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 14:14:19 -0300 Subject: [PATCH 07/13] Add translation back --- src/frontend/screens/Settings/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/frontend/screens/Settings/index.tsx b/src/frontend/screens/Settings/index.tsx index b68b0af4b6..4fd5a60f5a 100644 --- a/src/frontend/screens/Settings/index.tsx +++ b/src/frontend/screens/Settings/index.tsx @@ -43,6 +43,11 @@ function Settings() { const isAdvancedSetting = type === 'advanced' const isSystemInfo = type === 'systeminfo' + // TODO: Adding this comment translation here for now to not lose the + // translation. This should be removed from here when the help is added + // to the SettingsModal component + // t('help.content.settingsGame', 'Show all settings for a game.') + const helpContent = t( 'help.content.settingsDefault', 'Shows all settings of Heroic and defaults for games.' From 4ad21a6f6694eedfcc935206b05bec6b2d21ff18 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Sat, 10 Feb 2024 14:33:04 -0300 Subject: [PATCH 08/13] Remove deadcode --- src/frontend/types.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/frontend/types.ts b/src/frontend/types.ts index 1701b9f3be..958e6bcea2 100644 --- a/src/frontend/types.ts +++ b/src/frontend/types.ts @@ -272,14 +272,6 @@ export interface GameContextType { wikiInfo: WikiInfo | null } -export interface LocationState { - fromGameCard: boolean - runner: Runner - isLinuxNative: boolean - isMacNative: boolean - gameInfo: GameInfo -} - export type DMQueue = { elements: DMQueueElement[] finished: DMQueueElement[] From 1ae89d75f1ec5a1ba51ffd45a0998c7543dc7780 Mon Sep 17 00:00:00 2001 From: Ariel Juodziukynas Date: Mon, 12 Feb 2024 11:47:45 -0300 Subject: [PATCH 09/13] Don't do `runner!`. Fix game_defaults url. Use `/library`. --- .../UI/Sidebar/components/SidebarLinks/index.tsx | 2 +- src/frontend/components/UI/Winetricks/index.tsx | 14 ++++++++------ .../screens/Settings/components/OfflineMode.tsx | 9 +++++---- .../screens/Settings/components/Tools/index.tsx | 14 ++++++++------ src/frontend/screens/Settings/index.tsx | 2 +- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx index 276bcdbe5c..86ca8c56e0 100644 --- a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx +++ b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx @@ -155,7 +155,7 @@ export default function SidebarLinks() { {!isWin && ( void + runner: Runner } -export default function Winetricks({ onClose }: Props) { - const { appName, runner } = useContext(SettingsContext) +export default function Winetricks({ onClose, runner }: Props) { + const { appName } = useContext(SettingsContext) const { t } = useTranslation() const [loading, setLoading] = useState(true) @@ -21,7 +23,7 @@ export default function Winetricks({ onClose }: Props) { setLoading(true) try { const components = await window.api.winetricksListInstalled( - runner!, + runner, appName ) setInstalled(components) @@ -39,7 +41,7 @@ export default function Winetricks({ onClose }: Props) { async function listComponents() { try { const components = await window.api.winetricksListAvailable( - runner!, + runner, appName ) setAllComponents(components) @@ -55,7 +57,7 @@ export default function Winetricks({ onClose }: Props) { const [installingComponent, setInstallingComponent] = useState('') const [logs, setLogs] = useState([]) function install(component: string) { - window.api.winetricksInstall(runner!, appName, component) + window.api.winetricksInstall(runner, appName, component) } useEffect(() => { @@ -100,7 +102,7 @@ export default function Winetricks({ onClose }: Props) { window.api.callTool({ tool: 'winetricks', appName, - runner: runner! + runner }) } diff --git a/src/frontend/screens/Settings/components/OfflineMode.tsx b/src/frontend/screens/Settings/components/OfflineMode.tsx index 175d23fe49..c6f31a6fae 100644 --- a/src/frontend/screens/Settings/components/OfflineMode.tsx +++ b/src/frontend/screens/Settings/components/OfflineMode.tsx @@ -14,16 +14,17 @@ const OfflineMode = () => { useEffect(() => { const getInfo = async () => { - const info = await getGameInfo(appName, runner!) + if (!runner) { + return + } + const info = await getGameInfo(appName, runner) if (info) { const { canRunOffline: can_run_offline } = info setCanRunOffline(can_run_offline) } } - if (!isDefault) { - getInfo() - } + getInfo() }, []) const [offlineMode, setOfflineMode] = useSetting('offlineMode', false) diff --git a/src/frontend/screens/Settings/components/Tools/index.tsx b/src/frontend/screens/Settings/components/Tools/index.tsx index 2ab97c4bce..9caab7f93e 100644 --- a/src/frontend/screens/Settings/components/Tools/index.tsx +++ b/src/frontend/screens/Settings/components/Tools/index.tsx @@ -19,11 +19,11 @@ export default function Tools() { const { platform } = useContext(ContextProvider) const isWindows = platform === 'win32' - if (isDefault || isWindows) { + if (isDefault || isWindows || !runner) { return <> } - async function callTools(tool: 'winecfg' | 'runExe', exe?: string) { + const callTools = async (tool: 'winecfg' | 'runExe', exe?: string) => { const toolStates = { winecfg: setWinecfgRunning, runExe: setRunExeRunning @@ -37,7 +37,7 @@ export default function Tools() { tool, exe, appName, - runner: runner! + runner }) if (tool in toolStates) { @@ -47,7 +47,7 @@ export default function Tools() { const handleRunExe = async () => { let exe = '' - const gameinfo = await getGameInfo(appName, runner!) + const gameinfo = await getGameInfo(appName, runner) if (!gameinfo) return const defaultPath = gameinfo.runner === 'sideload' ? undefined : gameinfo.install.install_path @@ -64,7 +64,7 @@ export default function Tools() { } } - async function dropHandler(ev: React.DragEvent) { + const dropHandler = async (ev: React.DragEvent) => { // Prevent default behavior (Prevent file from being opened) ev.preventDefault() @@ -97,7 +97,9 @@ export default function Tools() { return ( <>
- {winetricksRunning && } + {winetricksRunning && ( + + )}