diff options
| author | EMERALD <hudson.samuels@gmail.com> | 2023-02-01 19:16:42 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-01 17:16:42 -0800 |
| commit | 43b2269ea710c02278f784f28521a99dc9d3915b (patch) | |
| tree | 34dde12638d07f63864c84fabc8654253532b6ae /frontend/src | |
| parent | 0c4e27cd343a81d386c11bc17f93296a2e598a5c (diff) | |
| download | decky-loader-43b2269ea710c02278f784f28521a99dc9d3915b.tar.gz decky-loader-43b2269ea710c02278f784f28521a99dc9d3915b.zip | |
Fix UI inconsistencies, various improvements (#357)
* Make version gray in plugin list
* Settings/store icons together & plugin list fix
* Navigation name/icon improvements
* Decky settings overhaul and other fixes
- Revert the tab icon to a plug
- Rename DeckyFlat function to DeckyIcon
- Add DialogBody to settings pages to improve scrolling
- Add remote debugging settings to the developer settings
- Fix React devtools interactions to work more easily
- Add spacing to React devtools description
- Specify Decky vs. plugin store
- Compact version information by update button
- Add current version to bottom of settings
- Remove unnecessary settings icons
- Change CEF debugger icon to Chrome (bug icon too generic, is Chromium)
- Make buttons/dropdowns in settings have fixed width
- Make download icon act/appear similar to Valve's for Deck
* Final UI adjustments
* Switch plugin settings icon to plug
Diffstat (limited to 'frontend/src')
10 files changed, 204 insertions, 151 deletions
diff --git a/frontend/src/components/DeckyIcon.tsx b/frontend/src/components/DeckyIcon.tsx new file mode 100644 index 00000000..515bd847 --- /dev/null +++ b/frontend/src/components/DeckyIcon.tsx @@ -0,0 +1,37 @@ +export default function DeckyIcon() { + return ( + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 456" width="512" height="456"> + <g> + <path + style={{ fill: 'none' }} + d="M154.33,72.51v49.79c11.78-0.17,23.48,2,34.42,6.39c10.93,4.39,20.89,10.91,29.28,19.18 + c8.39,8.27,15.06,18.13,19.61,29c4.55,10.87,6.89,22.54,6.89,34.32c0,11.78-2.34,23.45-6.89,34.32 + c-4.55,10.87-11.21,20.73-19.61,29c-8.39,8.27-18.35,14.79-29.28,19.18c-10.94,4.39-22.63,6.56-34.42,6.39v49.77 + c36.78,0,72.05-14.61,98.05-40.62c26-26.01,40.61-61.28,40.61-98.05c0-36.78-14.61-72.05-40.61-98.05 + C226.38,87.12,191.11,72.51,154.33,72.51z" + /> + + <ellipse + transform="matrix(0.982 -0.1891 0.1891 0.982 -37.1795 32.9988)" + style={{ fill: 'none' }} + cx="154.33" + cy="211.33" + rx="69.33" + ry="69.33" + /> + <path style={{ fill: 'none' }} d="M430,97h-52v187h52c7.18,0,13-5.82,13-13V110C443,102.82,437.18,97,430,97z" /> + <path + style={{ fill: 'currentColor' }} + d="M432,27h-54V0H0v361c0,52.47,42.53,95,95,95h188c52.47,0,95-42.53,95-95v-7h54c44.18,0,80-35.82,80-80V107 + C512,62.82,476.18,27,432,27z M85,211.33c0-38.29,31.04-69.33,69.33-69.33c38.29,0,69.33,31.04,69.33,69.33 + c0,38.29-31.04,69.33-69.33,69.33C116.04,280.67,85,249.62,85,211.33z M252.39,309.23c-26.01,26-61.28,40.62-98.05,40.62v-49.77 + c11.78,0.17,23.48-2,34.42-6.39c10.93-4.39,20.89-10.91,29.28-19.18c8.39-8.27,15.06-18.13,19.61-29 + c4.55-10.87,6.89-22.53,6.89-34.32c0-11.78-2.34-23.45-6.89-34.32c-4.55-10.87-11.21-20.73-19.61-29 + c-8.39-8.27-18.35-14.79-29.28-19.18c-10.94-4.39-22.63-6.56-34.42-6.39V72.51c36.78,0,72.05,14.61,98.05,40.61 + c26,26.01,40.61,61.28,40.61,98.05C293,247.96,278.39,283.23,252.39,309.23z M443,271c0,7.18-5.82,13-13,13h-52V97h52 + c7.18,0,13,5.82,13,13V271z" + /> + </g> + </svg> + ); +} diff --git a/frontend/src/components/TitleView.tsx b/frontend/src/components/TitleView.tsx index cd1f9eba..7e529d21 100644 --- a/frontend/src/components/TitleView.tsx +++ b/frontend/src/components/TitleView.tsx @@ -1,6 +1,7 @@ import { DialogButton, Focusable, Router, staticClasses } from 'decky-frontend-lib'; import { CSSProperties, VFC } from 'react'; -import { FaArrowLeft, FaCog, FaStore } from 'react-icons/fa'; +import { BsGearFill } from 'react-icons/bs'; +import { FaArrowLeft, FaStore } from 'react-icons/fa'; import { useDeckyState } from './DeckyState'; @@ -26,18 +27,18 @@ const TitleView: VFC = () => { if (activePlugin === null) { return ( <Focusable style={titleStyles} className={staticClasses.Title}> + <div style={{ marginRight: 'auto', flex: 0.9 }}>Decky</div> <DialogButton style={{ height: '28px', width: '40px', minWidth: 0, padding: '10px 12px' }} - onClick={onSettingsClick} + onClick={onStoreClick} > - <FaCog style={{ marginTop: '-4px', display: 'block' }} /> + <FaStore style={{ marginTop: '-4px', display: 'block' }} /> </DialogButton> - <div style={{ marginRight: 'auto', flex: 0.9 }}>Decky</div> <DialogButton style={{ height: '28px', width: '40px', minWidth: 0, padding: '10px 12px' }} - onClick={onStoreClick} + onClick={onSettingsClick} > - <FaStore style={{ marginTop: '-4px', display: 'block' }} /> + <BsGearFill style={{ marginTop: '-4px', display: 'block' }} /> </DialogButton> </Focusable> ); diff --git a/frontend/src/components/settings/index.tsx b/frontend/src/components/settings/index.tsx index 01f7d407..6f104710 100644 --- a/frontend/src/components/settings/index.tsx +++ b/frontend/src/components/settings/index.tsx @@ -1,7 +1,9 @@ import { SidebarNavigation } from 'decky-frontend-lib'; import { lazy } from 'react'; +import { FaCode, FaPlug } from 'react-icons/fa'; import { useSetting } from '../../utils/hooks/useSetting'; +import DeckyIcon from '../DeckyIcon'; import WithSuspense from '../WithSuspense'; import GeneralSettings from './pages/general'; import PluginList from './pages/plugin_list'; @@ -13,19 +15,18 @@ export default function SettingsPage() { const pages = [ { - title: 'General', + title: 'Decky', content: <GeneralSettings isDeveloper={isDeveloper} setIsDeveloper={setIsDeveloper} />, route: '/decky/settings/general', + icon: <DeckyIcon />, }, { title: 'Plugins', content: <PluginList />, route: '/decky/settings/plugins', + icon: <FaPlug />, }, - ]; - - if (isDeveloper) - pages.push({ + { title: 'Developer', content: ( <WithSuspense> @@ -33,7 +34,10 @@ export default function SettingsPage() { </WithSuspense> ), route: '/decky/settings/developer', - }); + icon: <FaCode />, + visible: isDeveloper, + }, + ]; - return <SidebarNavigation title="Decky Settings" showTitle pages={pages} />; + return <SidebarNavigation pages={pages} />; } diff --git a/frontend/src/components/settings/pages/developer/index.tsx b/frontend/src/components/settings/pages/developer/index.tsx index 447c9606..d9859c46 100644 --- a/frontend/src/components/settings/pages/developer/index.tsx +++ b/frontend/src/components/settings/pages/developer/index.tsx @@ -1,9 +1,10 @@ -import { Field, Focusable, TextField, Toggle } from 'decky-frontend-lib'; +import { DialogBody, Field, TextField, Toggle } from 'decky-frontend-lib'; import { useRef } from 'react'; import { FaReact, FaSteamSymbol } from 'react-icons/fa'; import { setShouldConnectToReactDevTools, setShowValveInternal } from '../../../../developer'; import { useSetting } from '../../../../utils/hooks/useSetting'; +import RemoteDebuggingSettings from '../general/RemoteDebugging'; export default function DeveloperSettings() { const [enableValveInternal, setEnableValveInternal] = useSetting<boolean>('developer.valve_internal', false); @@ -12,7 +13,8 @@ export default function DeveloperSettings() { const textRef = useRef<HTMLDivElement>(null); return ( - <> + <DialogBody> + <RemoteDebuggingSettings /> <Field label="Enable Valve Internal" description={ @@ -30,55 +32,33 @@ export default function DeveloperSettings() { setShowValveInternal(toggleValue); }} /> - </Field>{' '} - <Focusable - onTouchEnd={ - reactDevtoolsIP == '' - ? () => { - (textRef.current?.childNodes[0] as HTMLInputElement)?.focus(); - } - : undefined - } - onClick={ - reactDevtoolsIP == '' - ? () => { - (textRef.current?.childNodes[0] as HTMLInputElement)?.focus(); - } - : undefined - } - onOKButton={ - reactDevtoolsIP == '' - ? () => { - (textRef.current?.childNodes[0] as HTMLInputElement)?.focus(); - } - : undefined + </Field> + <Field + label="Enable React DevTools" + description={ + <> + <span style={{ whiteSpace: 'pre-line' }}> + Enables connection to a computer running React DevTools. Changing this setting will reload Steam. Set the + IP address before enabling. + </span> + <br /> + <br /> + <div ref={textRef}> + <TextField label={'IP'} value={reactDevtoolsIP} onChange={(e) => setReactDevtoolsIP(e?.target.value)} /> + </div> + </> } + icon={<FaReact style={{ display: 'block' }} />} > - <Field - label="Enable React DevTools" - description={ - <> - <span style={{ whiteSpace: 'pre-line' }}> - Enables connection to a computer running React DevTools. Changing this setting will reload Steam. Set - the IP address before enabling. - </span> - <div ref={textRef}> - <TextField label={'IP'} value={reactDevtoolsIP} onChange={(e) => setReactDevtoolsIP(e?.target.value)} /> - </div> - </> - } - icon={<FaReact style={{ display: 'block' }} />} - > - <Toggle - value={reactDevtoolsEnabled} - disabled={reactDevtoolsIP == ''} - onChange={(toggleValue) => { - setReactDevtoolsEnabled(toggleValue); - setShouldConnectToReactDevTools(toggleValue); - }} - /> - </Field> - </Focusable> - </> + <Toggle + value={reactDevtoolsEnabled} + disabled={reactDevtoolsIP == ''} + onChange={(toggleValue) => { + setReactDevtoolsEnabled(toggleValue); + setShouldConnectToReactDevTools(toggleValue); + }} + /> + </Field> + </DialogBody> ); } diff --git a/frontend/src/components/settings/pages/general/BranchSelect.tsx b/frontend/src/components/settings/pages/general/BranchSelect.tsx index 27db6229..5387b655 100644 --- a/frontend/src/components/settings/pages/general/BranchSelect.tsx +++ b/frontend/src/components/settings/pages/general/BranchSelect.tsx @@ -19,7 +19,7 @@ const BranchSelect: FunctionComponent<{}> = () => { return ( // Returns numerical values from 0 to 2 (with current branch setup as of 8/28/22) // 0 being stable, 1 being pre-release and 2 being nightly - <Field label="Update Channel"> + <Field label="Decky Update Channel" childrenContainerWidth={'fixed'}> <Dropdown rgOptions={Object.values(UpdateBranch) .filter((branch) => typeof branch == 'string') diff --git a/frontend/src/components/settings/pages/general/RemoteDebugging.tsx b/frontend/src/components/settings/pages/general/RemoteDebugging.tsx index 36badf45..db604c69 100644 --- a/frontend/src/components/settings/pages/general/RemoteDebugging.tsx +++ b/frontend/src/components/settings/pages/general/RemoteDebugging.tsx @@ -1,5 +1,5 @@ import { Field, Toggle } from 'decky-frontend-lib'; -import { FaBug } from 'react-icons/fa'; +import { FaChrome } from 'react-icons/fa'; import { useSetting } from '../../../../utils/hooks/useSetting'; @@ -11,10 +11,10 @@ export default function RemoteDebuggingSettings() { label="Allow Remote CEF Debugging" description={ <span style={{ whiteSpace: 'pre-line' }}> - Allow unauthenticated access to the CEF debugger to anyone in your network + Allows unauthenticated access to the CEF debugger to anyone in your network. </span> } - icon={<FaBug style={{ display: 'block' }} />} + icon={<FaChrome style={{ display: 'block' }} />} > <Toggle value={allowRemoteDebugging || false} diff --git a/frontend/src/components/settings/pages/general/StoreSelect.tsx b/frontend/src/components/settings/pages/general/StoreSelect.tsx index c24bacb9..40e70301 100644 --- a/frontend/src/components/settings/pages/general/StoreSelect.tsx +++ b/frontend/src/components/settings/pages/general/StoreSelect.tsx @@ -16,7 +16,7 @@ const StoreSelect: FunctionComponent<{}> = () => { // 0 being Default, 1 being Testing and 2 being Custom return ( <> - <Field label="Store Channel"> + <Field label="Plugin Store Channel" childrenContainerWidth={'fixed'}> <Dropdown rgOptions={Object.values(Store) .filter((store) => typeof store == 'string') diff --git a/frontend/src/components/settings/pages/general/Updater.tsx b/frontend/src/components/settings/pages/general/Updater.tsx index f617e0ff..b38b6d01 100644 --- a/frontend/src/components/settings/pages/general/Updater.tsx +++ b/frontend/src/components/settings/pages/general/Updater.tsx @@ -11,7 +11,7 @@ import { import { useCallback } from 'react'; import { Suspense, lazy } from 'react'; import { useEffect, useState } from 'react'; -import { FaArrowDown } from 'react-icons/fa'; +import { FaExclamation } from 'react-icons/fa'; import { VerInfo, callUpdaterMethod, finishUpdate } from '../../../../updater'; import { findSP } from '../../../../utils/windows'; @@ -95,21 +95,21 @@ export default function UpdaterSettings() { <Field onOptionsActionDescription={versionInfo?.all ? 'Patch Notes' : undefined} onOptionsButton={versionInfo?.all ? showPatchNotes : undefined} - label="Updates" + label="Decky Updates" description={ - versionInfo && ( - <span style={{ whiteSpace: 'pre-line' }}>{`Current version: ${versionInfo.current}\n${ - versionInfo.updatable ? `Latest version: ${versionInfo.remote?.tag_name}` : '' - }`}</span> + checkingForUpdates || versionInfo?.remote?.tag_name != versionInfo?.current || !versionInfo?.remote ? ( + '' + ) : ( + <span>Up to date: running {versionInfo?.current}</span> ) } icon={ - !versionInfo ? ( - <Spinner style={{ width: '1em', height: 20, display: 'block' }} /> - ) : ( - <FaArrowDown style={{ display: 'block' }} /> + versionInfo?.remote && + versionInfo?.remote?.tag_name != versionInfo?.current && ( + <FaExclamation color="var(--gpColor-Yellow)" style={{ display: 'block' }} /> ) } + childrenContainerWidth={'fixed'} > {updateProgress == -1 && !isLoaderUpdating ? ( <DialogButton @@ -144,7 +144,7 @@ export default function UpdaterSettings() { /> )} </Field> - {versionInfo?.remote && ( + {versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current && ( <InlinePatchNotes title={versionInfo?.remote.name} date={new Intl.RelativeTimeFormat('en-US', { diff --git a/frontend/src/components/settings/pages/general/index.tsx b/frontend/src/components/settings/pages/general/index.tsx index d661b779..e0bd9691 100644 --- a/frontend/src/components/settings/pages/general/index.tsx +++ b/frontend/src/components/settings/pages/general/index.tsx @@ -1,10 +1,17 @@ -import { DialogButton, Field, TextField, Toggle } from 'decky-frontend-lib'; +import { + DialogBody, + DialogButton, + DialogControlsSection, + DialogControlsSectionHeader, + Field, + TextField, + Toggle, +} from 'decky-frontend-lib'; import { useState } from 'react'; -import { FaShapes, FaTools } from 'react-icons/fa'; import { installFromURL } from '../../../../store'; +import { useDeckyState } from '../../../DeckyState'; import BranchSelect from './BranchSelect'; -import RemoteDebuggingSettings from './RemoteDebugging'; import StoreSelect from './StoreSelect'; import UpdaterSettings from './Updater'; @@ -16,34 +23,44 @@ export default function GeneralSettings({ setIsDeveloper: (val: boolean) => void; }) { const [pluginURL, setPluginURL] = useState(''); + const { versionInfo } = useDeckyState(); return ( - <div> - <UpdaterSettings /> - <BranchSelect /> - <StoreSelect /> - <RemoteDebuggingSettings /> - <Field - label="Developer mode" - description={<span style={{ whiteSpace: 'pre-line' }}>Enables Decky's developer settings.</span>} - icon={<FaTools style={{ display: 'block' }} />} - > - <Toggle - value={isDeveloper} - onChange={(toggleValue) => { - setIsDeveloper(toggleValue); - }} - /> - </Field> - <Field - label="Manual plugin install" - description={<TextField label={'URL'} value={pluginURL} onChange={(e) => setPluginURL(e?.target.value)} />} - icon={<FaShapes style={{ display: 'block' }} />} - > - <DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}> - Install - </DialogButton> - </Field> - </div> + <DialogBody> + <DialogControlsSection> + <DialogControlsSectionHeader>Updates</DialogControlsSectionHeader> + <UpdaterSettings /> + </DialogControlsSection> + <DialogControlsSection> + <DialogControlsSectionHeader>Beta Participation</DialogControlsSectionHeader> + <BranchSelect /> + <StoreSelect /> + </DialogControlsSection> + <DialogControlsSection> + <DialogControlsSectionHeader>Other</DialogControlsSectionHeader> + <Field label="Enable Developer Mode"> + <Toggle + value={isDeveloper} + onChange={(toggleValue) => { + setIsDeveloper(toggleValue); + }} + /> + </Field> + <Field + label="Install plugin from URL" + description={<TextField label={'URL'} value={pluginURL} onChange={(e) => setPluginURL(e?.target.value)} />} + > + <DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}> + Install + </DialogButton> + </Field> + </DialogControlsSection> + <DialogControlsSection> + <DialogControlsSectionHeader>About</DialogControlsSectionHeader> + <Field label="Decky Version" focusable={true}> + <div style={{ color: 'var(--gpSystemLighterGrey)' }}>{versionInfo?.current}</div> + </Field> + </DialogControlsSection> + </DialogBody> ); } diff --git a/frontend/src/components/settings/pages/plugin_list/index.tsx b/frontend/src/components/settings/pages/plugin_list/index.tsx index 4eb89615..48894031 100644 --- a/frontend/src/components/settings/pages/plugin_list/index.tsx +++ b/frontend/src/components/settings/pages/plugin_list/index.tsx @@ -1,4 +1,12 @@ -import { DialogButton, Focusable, Menu, MenuItem, showContextMenu } from 'decky-frontend-lib'; +import { + DialogBody, + DialogButton, + DialogControlsSection, + Focusable, + Menu, + MenuItem, + showContextMenu, +} from 'decky-frontend-lib'; import { useEffect } from 'react'; import { FaDownload, FaEllipsisH } from 'react-icons/fa'; @@ -21,46 +29,52 @@ export default function PluginList() { } return ( - <ul style={{ listStyleType: 'none' }}> - {plugins.map(({ name, version }) => { - const update = updates?.get(name); - return ( - <li style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', paddingBottom: '10px' }}> - <span> - {name} {version} - </span> - <Focusable style={{ marginLeft: 'auto', boxShadow: 'none', display: 'flex', justifyContent: 'right' }}> - {update && ( - <DialogButton - style={{ height: '40px', minWidth: '60px', marginRight: '10px' }} - onClick={() => requestPluginInstall(name, update)} - > - <div style={{ display: 'flex', flexDirection: 'row' }}> - Update to {update.name} - <FaDownload style={{ paddingLeft: '2rem' }} /> - </div> - </DialogButton> - )} - <DialogButton - style={{ height: '40px', width: '40px', padding: '10px 12px', minWidth: '40px' }} - onClick={(e: MouseEvent) => - showContextMenu( - <Menu label="Plugin Actions"> - <MenuItem onSelected={() => window.DeckyPluginLoader.importPlugin(name, version)}> - Reload - </MenuItem> - <MenuItem onSelected={() => window.DeckyPluginLoader.uninstallPlugin(name)}>Uninstall</MenuItem> - </Menu>, - e.currentTarget ?? window, - ) - } - > - <FaEllipsisH /> - </DialogButton> - </Focusable> - </li> - ); - })} - </ul> + <DialogBody> + <DialogControlsSection> + <ul style={{ listStyleType: 'none', padding: '0' }}> + {plugins.map(({ name, version }) => { + const update = updates?.get(name); + return ( + <li style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', paddingBottom: '10px' }}> + <span> + {name} <span style={{ opacity: '50%' }}>{'(' + version + ')'}</span> + </span> + <Focusable style={{ marginLeft: 'auto', boxShadow: 'none', display: 'flex', justifyContent: 'right' }}> + {update && ( + <DialogButton + style={{ height: '40px', minWidth: '60px', marginRight: '10px' }} + onClick={() => requestPluginInstall(name, update)} + > + <div style={{ display: 'flex', flexDirection: 'row' }}> + Update to {update.name} + <FaDownload style={{ paddingLeft: '2rem' }} /> + </div> + </DialogButton> + )} + <DialogButton + style={{ height: '40px', width: '40px', padding: '10px 12px', minWidth: '40px' }} + onClick={(e: MouseEvent) => + showContextMenu( + <Menu label="Plugin Actions"> + <MenuItem onSelected={() => window.DeckyPluginLoader.importPlugin(name, version)}> + Reload + </MenuItem> + <MenuItem onSelected={() => window.DeckyPluginLoader.uninstallPlugin(name)}> + Uninstall + </MenuItem> + </Menu>, + e.currentTarget ?? window, + ) + } + > + <FaEllipsisH /> + </DialogButton> + </Focusable> + </li> + ); + })} + </ul> + </DialogControlsSection> + </DialogBody> ); } |
