mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 22:01:59 +00:00
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
This commit is contained in:
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { DialogButton, Focusable, Router, staticClasses } from 'decky-frontend-lib';
|
import { DialogButton, Focusable, Router, staticClasses } from 'decky-frontend-lib';
|
||||||
import { CSSProperties, VFC } from 'react';
|
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';
|
import { useDeckyState } from './DeckyState';
|
||||||
|
|
||||||
@@ -26,12 +27,6 @@ const TitleView: VFC = () => {
|
|||||||
if (activePlugin === null) {
|
if (activePlugin === null) {
|
||||||
return (
|
return (
|
||||||
<Focusable style={titleStyles} className={staticClasses.Title}>
|
<Focusable style={titleStyles} className={staticClasses.Title}>
|
||||||
<DialogButton
|
|
||||||
style={{ height: '28px', width: '40px', minWidth: 0, padding: '10px 12px' }}
|
|
||||||
onClick={onSettingsClick}
|
|
||||||
>
|
|
||||||
<FaCog style={{ marginTop: '-4px', display: 'block' }} />
|
|
||||||
</DialogButton>
|
|
||||||
<div style={{ marginRight: 'auto', flex: 0.9 }}>Decky</div>
|
<div style={{ marginRight: 'auto', flex: 0.9 }}>Decky</div>
|
||||||
<DialogButton
|
<DialogButton
|
||||||
style={{ height: '28px', width: '40px', minWidth: 0, padding: '10px 12px' }}
|
style={{ height: '28px', width: '40px', minWidth: 0, padding: '10px 12px' }}
|
||||||
@@ -39,6 +34,12 @@ const TitleView: VFC = () => {
|
|||||||
>
|
>
|
||||||
<FaStore style={{ marginTop: '-4px', display: 'block' }} />
|
<FaStore style={{ marginTop: '-4px', display: 'block' }} />
|
||||||
</DialogButton>
|
</DialogButton>
|
||||||
|
<DialogButton
|
||||||
|
style={{ height: '28px', width: '40px', minWidth: 0, padding: '10px 12px' }}
|
||||||
|
onClick={onSettingsClick}
|
||||||
|
>
|
||||||
|
<BsGearFill style={{ marginTop: '-4px', display: 'block' }} />
|
||||||
|
</DialogButton>
|
||||||
</Focusable>
|
</Focusable>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { SidebarNavigation } from 'decky-frontend-lib';
|
import { SidebarNavigation } from 'decky-frontend-lib';
|
||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
|
import { FaCode, FaPlug } from 'react-icons/fa';
|
||||||
|
|
||||||
import { useSetting } from '../../utils/hooks/useSetting';
|
import { useSetting } from '../../utils/hooks/useSetting';
|
||||||
|
import DeckyIcon from '../DeckyIcon';
|
||||||
import WithSuspense from '../WithSuspense';
|
import WithSuspense from '../WithSuspense';
|
||||||
import GeneralSettings from './pages/general';
|
import GeneralSettings from './pages/general';
|
||||||
import PluginList from './pages/plugin_list';
|
import PluginList from './pages/plugin_list';
|
||||||
@@ -13,19 +15,18 @@ export default function SettingsPage() {
|
|||||||
|
|
||||||
const pages = [
|
const pages = [
|
||||||
{
|
{
|
||||||
title: 'General',
|
title: 'Decky',
|
||||||
content: <GeneralSettings isDeveloper={isDeveloper} setIsDeveloper={setIsDeveloper} />,
|
content: <GeneralSettings isDeveloper={isDeveloper} setIsDeveloper={setIsDeveloper} />,
|
||||||
route: '/decky/settings/general',
|
route: '/decky/settings/general',
|
||||||
|
icon: <DeckyIcon />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Plugins',
|
title: 'Plugins',
|
||||||
content: <PluginList />,
|
content: <PluginList />,
|
||||||
route: '/decky/settings/plugins',
|
route: '/decky/settings/plugins',
|
||||||
|
icon: <FaPlug />,
|
||||||
},
|
},
|
||||||
];
|
{
|
||||||
|
|
||||||
if (isDeveloper)
|
|
||||||
pages.push({
|
|
||||||
title: 'Developer',
|
title: 'Developer',
|
||||||
content: (
|
content: (
|
||||||
<WithSuspense>
|
<WithSuspense>
|
||||||
@@ -33,7 +34,10 @@ export default function SettingsPage() {
|
|||||||
</WithSuspense>
|
</WithSuspense>
|
||||||
),
|
),
|
||||||
route: '/decky/settings/developer',
|
route: '/decky/settings/developer',
|
||||||
});
|
icon: <FaCode />,
|
||||||
|
visible: isDeveloper,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return <SidebarNavigation title="Decky Settings" showTitle pages={pages} />;
|
return <SidebarNavigation pages={pages} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { useRef } from 'react';
|
||||||
import { FaReact, FaSteamSymbol } from 'react-icons/fa';
|
import { FaReact, FaSteamSymbol } from 'react-icons/fa';
|
||||||
|
|
||||||
import { setShouldConnectToReactDevTools, setShowValveInternal } from '../../../../developer';
|
import { setShouldConnectToReactDevTools, setShowValveInternal } from '../../../../developer';
|
||||||
import { useSetting } from '../../../../utils/hooks/useSetting';
|
import { useSetting } from '../../../../utils/hooks/useSetting';
|
||||||
|
import RemoteDebuggingSettings from '../general/RemoteDebugging';
|
||||||
|
|
||||||
export default function DeveloperSettings() {
|
export default function DeveloperSettings() {
|
||||||
const [enableValveInternal, setEnableValveInternal] = useSetting<boolean>('developer.valve_internal', false);
|
const [enableValveInternal, setEnableValveInternal] = useSetting<boolean>('developer.valve_internal', false);
|
||||||
@@ -12,7 +13,8 @@ export default function DeveloperSettings() {
|
|||||||
const textRef = useRef<HTMLDivElement>(null);
|
const textRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DialogBody>
|
||||||
|
<RemoteDebuggingSettings />
|
||||||
<Field
|
<Field
|
||||||
label="Enable Valve Internal"
|
label="Enable Valve Internal"
|
||||||
description={
|
description={
|
||||||
@@ -30,55 +32,33 @@ export default function DeveloperSettings() {
|
|||||||
setShowValveInternal(toggleValue);
|
setShowValveInternal(toggleValue);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Field>{' '}
|
</Field>
|
||||||
<Focusable
|
<Field
|
||||||
onTouchEnd={
|
label="Enable React DevTools"
|
||||||
reactDevtoolsIP == ''
|
description={
|
||||||
? () => {
|
<>
|
||||||
(textRef.current?.childNodes[0] as HTMLInputElement)?.focus();
|
<span style={{ whiteSpace: 'pre-line' }}>
|
||||||
}
|
Enables connection to a computer running React DevTools. Changing this setting will reload Steam. Set the
|
||||||
: undefined
|
IP address before enabling.
|
||||||
}
|
</span>
|
||||||
onClick={
|
<br />
|
||||||
reactDevtoolsIP == ''
|
<br />
|
||||||
? () => {
|
<div ref={textRef}>
|
||||||
(textRef.current?.childNodes[0] as HTMLInputElement)?.focus();
|
<TextField label={'IP'} value={reactDevtoolsIP} onChange={(e) => setReactDevtoolsIP(e?.target.value)} />
|
||||||
}
|
</div>
|
||||||
: undefined
|
</>
|
||||||
}
|
|
||||||
onOKButton={
|
|
||||||
reactDevtoolsIP == ''
|
|
||||||
? () => {
|
|
||||||
(textRef.current?.childNodes[0] as HTMLInputElement)?.focus();
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
|
icon={<FaReact style={{ display: 'block' }} />}
|
||||||
>
|
>
|
||||||
<Field
|
<Toggle
|
||||||
label="Enable React DevTools"
|
value={reactDevtoolsEnabled}
|
||||||
description={
|
disabled={reactDevtoolsIP == ''}
|
||||||
<>
|
onChange={(toggleValue) => {
|
||||||
<span style={{ whiteSpace: 'pre-line' }}>
|
setReactDevtoolsEnabled(toggleValue);
|
||||||
Enables connection to a computer running React DevTools. Changing this setting will reload Steam. Set
|
setShouldConnectToReactDevTools(toggleValue);
|
||||||
the IP address before enabling.
|
}}
|
||||||
</span>
|
/>
|
||||||
<div ref={textRef}>
|
</Field>
|
||||||
<TextField label={'IP'} value={reactDevtoolsIP} onChange={(e) => setReactDevtoolsIP(e?.target.value)} />
|
</DialogBody>
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
icon={<FaReact style={{ display: 'block' }} />}
|
|
||||||
>
|
|
||||||
<Toggle
|
|
||||||
value={reactDevtoolsEnabled}
|
|
||||||
disabled={reactDevtoolsIP == ''}
|
|
||||||
onChange={(toggleValue) => {
|
|
||||||
setReactDevtoolsEnabled(toggleValue);
|
|
||||||
setShouldConnectToReactDevTools(toggleValue);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</Focusable>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const BranchSelect: FunctionComponent<{}> = () => {
|
|||||||
return (
|
return (
|
||||||
// Returns numerical values from 0 to 2 (with current branch setup as of 8/28/22)
|
// 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
|
// 0 being stable, 1 being pre-release and 2 being nightly
|
||||||
<Field label="Update Channel">
|
<Field label="Decky Update Channel" childrenContainerWidth={'fixed'}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
rgOptions={Object.values(UpdateBranch)
|
rgOptions={Object.values(UpdateBranch)
|
||||||
.filter((branch) => typeof branch == 'string')
|
.filter((branch) => typeof branch == 'string')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Field, Toggle } from 'decky-frontend-lib';
|
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';
|
import { useSetting } from '../../../../utils/hooks/useSetting';
|
||||||
|
|
||||||
@@ -11,10 +11,10 @@ export default function RemoteDebuggingSettings() {
|
|||||||
label="Allow Remote CEF Debugging"
|
label="Allow Remote CEF Debugging"
|
||||||
description={
|
description={
|
||||||
<span style={{ whiteSpace: 'pre-line' }}>
|
<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>
|
</span>
|
||||||
}
|
}
|
||||||
icon={<FaBug style={{ display: 'block' }} />}
|
icon={<FaChrome style={{ display: 'block' }} />}
|
||||||
>
|
>
|
||||||
<Toggle
|
<Toggle
|
||||||
value={allowRemoteDebugging || false}
|
value={allowRemoteDebugging || false}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const StoreSelect: FunctionComponent<{}> = () => {
|
|||||||
// 0 being Default, 1 being Testing and 2 being Custom
|
// 0 being Default, 1 being Testing and 2 being Custom
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field label="Store Channel">
|
<Field label="Plugin Store Channel" childrenContainerWidth={'fixed'}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
rgOptions={Object.values(Store)
|
rgOptions={Object.values(Store)
|
||||||
.filter((store) => typeof store == 'string')
|
.filter((store) => typeof store == 'string')
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Suspense, lazy } from 'react';
|
import { Suspense, lazy } from 'react';
|
||||||
import { useEffect, useState } 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 { VerInfo, callUpdaterMethod, finishUpdate } from '../../../../updater';
|
||||||
import { findSP } from '../../../../utils/windows';
|
import { findSP } from '../../../../utils/windows';
|
||||||
@@ -95,21 +95,21 @@ export default function UpdaterSettings() {
|
|||||||
<Field
|
<Field
|
||||||
onOptionsActionDescription={versionInfo?.all ? 'Patch Notes' : undefined}
|
onOptionsActionDescription={versionInfo?.all ? 'Patch Notes' : undefined}
|
||||||
onOptionsButton={versionInfo?.all ? showPatchNotes : undefined}
|
onOptionsButton={versionInfo?.all ? showPatchNotes : undefined}
|
||||||
label="Updates"
|
label="Decky Updates"
|
||||||
description={
|
description={
|
||||||
versionInfo && (
|
checkingForUpdates || versionInfo?.remote?.tag_name != versionInfo?.current || !versionInfo?.remote ? (
|
||||||
<span style={{ whiteSpace: 'pre-line' }}>{`Current version: ${versionInfo.current}\n${
|
''
|
||||||
versionInfo.updatable ? `Latest version: ${versionInfo.remote?.tag_name}` : ''
|
) : (
|
||||||
}`}</span>
|
<span>Up to date: running {versionInfo?.current}</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
icon={
|
icon={
|
||||||
!versionInfo ? (
|
versionInfo?.remote &&
|
||||||
<Spinner style={{ width: '1em', height: 20, display: 'block' }} />
|
versionInfo?.remote?.tag_name != versionInfo?.current && (
|
||||||
) : (
|
<FaExclamation color="var(--gpColor-Yellow)" style={{ display: 'block' }} />
|
||||||
<FaArrowDown style={{ display: 'block' }} />
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
childrenContainerWidth={'fixed'}
|
||||||
>
|
>
|
||||||
{updateProgress == -1 && !isLoaderUpdating ? (
|
{updateProgress == -1 && !isLoaderUpdating ? (
|
||||||
<DialogButton
|
<DialogButton
|
||||||
@@ -144,7 +144,7 @@ export default function UpdaterSettings() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
{versionInfo?.remote && (
|
{versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current && (
|
||||||
<InlinePatchNotes
|
<InlinePatchNotes
|
||||||
title={versionInfo?.remote.name}
|
title={versionInfo?.remote.name}
|
||||||
date={new Intl.RelativeTimeFormat('en-US', {
|
date={new Intl.RelativeTimeFormat('en-US', {
|
||||||
|
|||||||
@@ -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 { useState } from 'react';
|
||||||
import { FaShapes, FaTools } from 'react-icons/fa';
|
|
||||||
|
|
||||||
import { installFromURL } from '../../../../store';
|
import { installFromURL } from '../../../../store';
|
||||||
|
import { useDeckyState } from '../../../DeckyState';
|
||||||
import BranchSelect from './BranchSelect';
|
import BranchSelect from './BranchSelect';
|
||||||
import RemoteDebuggingSettings from './RemoteDebugging';
|
|
||||||
import StoreSelect from './StoreSelect';
|
import StoreSelect from './StoreSelect';
|
||||||
import UpdaterSettings from './Updater';
|
import UpdaterSettings from './Updater';
|
||||||
|
|
||||||
@@ -16,34 +23,44 @@ export default function GeneralSettings({
|
|||||||
setIsDeveloper: (val: boolean) => void;
|
setIsDeveloper: (val: boolean) => void;
|
||||||
}) {
|
}) {
|
||||||
const [pluginURL, setPluginURL] = useState('');
|
const [pluginURL, setPluginURL] = useState('');
|
||||||
|
const { versionInfo } = useDeckyState();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<DialogBody>
|
||||||
<UpdaterSettings />
|
<DialogControlsSection>
|
||||||
<BranchSelect />
|
<DialogControlsSectionHeader>Updates</DialogControlsSectionHeader>
|
||||||
<StoreSelect />
|
<UpdaterSettings />
|
||||||
<RemoteDebuggingSettings />
|
</DialogControlsSection>
|
||||||
<Field
|
<DialogControlsSection>
|
||||||
label="Developer mode"
|
<DialogControlsSectionHeader>Beta Participation</DialogControlsSectionHeader>
|
||||||
description={<span style={{ whiteSpace: 'pre-line' }}>Enables Decky's developer settings.</span>}
|
<BranchSelect />
|
||||||
icon={<FaTools style={{ display: 'block' }} />}
|
<StoreSelect />
|
||||||
>
|
</DialogControlsSection>
|
||||||
<Toggle
|
<DialogControlsSection>
|
||||||
value={isDeveloper}
|
<DialogControlsSectionHeader>Other</DialogControlsSectionHeader>
|
||||||
onChange={(toggleValue) => {
|
<Field label="Enable Developer Mode">
|
||||||
setIsDeveloper(toggleValue);
|
<Toggle
|
||||||
}}
|
value={isDeveloper}
|
||||||
/>
|
onChange={(toggleValue) => {
|
||||||
</Field>
|
setIsDeveloper(toggleValue);
|
||||||
<Field
|
}}
|
||||||
label="Manual plugin install"
|
/>
|
||||||
description={<TextField label={'URL'} value={pluginURL} onChange={(e) => setPluginURL(e?.target.value)} />}
|
</Field>
|
||||||
icon={<FaShapes style={{ display: 'block' }} />}
|
<Field
|
||||||
>
|
label="Install plugin from URL"
|
||||||
<DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}>
|
description={<TextField label={'URL'} value={pluginURL} onChange={(e) => setPluginURL(e?.target.value)} />}
|
||||||
Install
|
>
|
||||||
</DialogButton>
|
<DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}>
|
||||||
</Field>
|
Install
|
||||||
</div>
|
</DialogButton>
|
||||||
|
</Field>
|
||||||
|
</DialogControlsSection>
|
||||||
|
<DialogControlsSection>
|
||||||
|
<DialogControlsSectionHeader>About</DialogControlsSectionHeader>
|
||||||
|
<Field label="Decky Version" focusable={true}>
|
||||||
|
<div style={{ color: 'var(--gpSystemLighterGrey)' }}>{versionInfo?.current}</div>
|
||||||
|
</Field>
|
||||||
|
</DialogControlsSection>
|
||||||
|
</DialogBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { useEffect } from 'react';
|
||||||
import { FaDownload, FaEllipsisH } from 'react-icons/fa';
|
import { FaDownload, FaEllipsisH } from 'react-icons/fa';
|
||||||
|
|
||||||
@@ -21,46 +29,52 @@ export default function PluginList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul style={{ listStyleType: 'none' }}>
|
<DialogBody>
|
||||||
{plugins.map(({ name, version }) => {
|
<DialogControlsSection>
|
||||||
const update = updates?.get(name);
|
<ul style={{ listStyleType: 'none', padding: '0' }}>
|
||||||
return (
|
{plugins.map(({ name, version }) => {
|
||||||
<li style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', paddingBottom: '10px' }}>
|
const update = updates?.get(name);
|
||||||
<span>
|
return (
|
||||||
{name} {version}
|
<li style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', paddingBottom: '10px' }}>
|
||||||
</span>
|
<span>
|
||||||
<Focusable style={{ marginLeft: 'auto', boxShadow: 'none', display: 'flex', justifyContent: 'right' }}>
|
{name} <span style={{ opacity: '50%' }}>{'(' + version + ')'}</span>
|
||||||
{update && (
|
</span>
|
||||||
<DialogButton
|
<Focusable style={{ marginLeft: 'auto', boxShadow: 'none', display: 'flex', justifyContent: 'right' }}>
|
||||||
style={{ height: '40px', minWidth: '60px', marginRight: '10px' }}
|
{update && (
|
||||||
onClick={() => requestPluginInstall(name, update)}
|
<DialogButton
|
||||||
>
|
style={{ height: '40px', minWidth: '60px', marginRight: '10px' }}
|
||||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
onClick={() => requestPluginInstall(name, update)}
|
||||||
Update to {update.name}
|
>
|
||||||
<FaDownload style={{ paddingLeft: '2rem' }} />
|
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||||
</div>
|
Update to {update.name}
|
||||||
</DialogButton>
|
<FaDownload style={{ paddingLeft: '2rem' }} />
|
||||||
)}
|
</div>
|
||||||
<DialogButton
|
</DialogButton>
|
||||||
style={{ height: '40px', width: '40px', padding: '10px 12px', minWidth: '40px' }}
|
)}
|
||||||
onClick={(e: MouseEvent) =>
|
<DialogButton
|
||||||
showContextMenu(
|
style={{ height: '40px', width: '40px', padding: '10px 12px', minWidth: '40px' }}
|
||||||
<Menu label="Plugin Actions">
|
onClick={(e: MouseEvent) =>
|
||||||
<MenuItem onSelected={() => window.DeckyPluginLoader.importPlugin(name, version)}>
|
showContextMenu(
|
||||||
Reload
|
<Menu label="Plugin Actions">
|
||||||
</MenuItem>
|
<MenuItem onSelected={() => window.DeckyPluginLoader.importPlugin(name, version)}>
|
||||||
<MenuItem onSelected={() => window.DeckyPluginLoader.uninstallPlugin(name)}>Uninstall</MenuItem>
|
Reload
|
||||||
</Menu>,
|
</MenuItem>
|
||||||
e.currentTarget ?? window,
|
<MenuItem onSelected={() => window.DeckyPluginLoader.uninstallPlugin(name)}>
|
||||||
)
|
Uninstall
|
||||||
}
|
</MenuItem>
|
||||||
>
|
</Menu>,
|
||||||
<FaEllipsisH />
|
e.currentTarget ?? window,
|
||||||
</DialogButton>
|
)
|
||||||
</Focusable>
|
}
|
||||||
</li>
|
>
|
||||||
);
|
<FaEllipsisH />
|
||||||
})}
|
</DialogButton>
|
||||||
</ul>
|
</Focusable>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</DialogControlsSection>
|
||||||
|
</DialogBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user