summaryrefslogtreecommitdiff
path: root/frontend/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components')
-rw-r--r--frontend/src/components/DeckyErrorBoundary.tsx82
-rw-r--r--frontend/src/components/Markdown.tsx9
-rw-r--r--frontend/src/components/modals/filepicker/patches/library.ts2
-rw-r--r--frontend/src/components/settings/pages/developer/index.tsx11
-rw-r--r--frontend/src/components/settings/pages/general/Updater.tsx48
5 files changed, 131 insertions, 21 deletions
diff --git a/frontend/src/components/DeckyErrorBoundary.tsx b/frontend/src/components/DeckyErrorBoundary.tsx
index 654db8a0..7a8d2b31 100644
--- a/frontend/src/components/DeckyErrorBoundary.tsx
+++ b/frontend/src/components/DeckyErrorBoundary.tsx
@@ -4,6 +4,8 @@ import { FunctionComponent, useEffect, useReducer, useState } from 'react';
import { uninstallPlugin } from '../plugin';
import { VerInfo, doRestart, doShutdown } from '../updater';
import { ValveReactErrorInfo, getLikelyErrorSourceFromValveReactError } from '../utils/errors';
+import { useSetting } from '../utils/hooks/useSetting';
+import { UpdateBranch } from './settings/pages/general/BranchSelect';
interface DeckyErrorBoundaryProps {
error: ValveReactErrorInfo;
@@ -37,6 +39,27 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
if (!shouldReportToValve) DeckyPluginLoader.errorBoundaryHook.temporarilyDisableReporting();
DeckyPluginLoader.updateVersion().then(setVersionInfo);
}, []);
+
+ const [selectedBranch, setSelectedBranch] = useSetting<UpdateBranch>('branch', UpdateBranch.Stable);
+ const [isChecking, setIsChecking] = useState<boolean>(false);
+ const [updateProgress, setUpdateProgress] = useState<number>(-1);
+ const [versionToUpdateTo, setSetVersionToUpdateTo] = useState<string>('');
+
+ useEffect(() => {
+ const a = DeckyBackend.addEventListener('updater/update_download_percentage', (percentage) => {
+ setUpdateProgress(percentage);
+ });
+
+ const b = DeckyBackend.addEventListener('updater/finish_download', () => {
+ setUpdateProgress(-2);
+ });
+
+ return () => {
+ DeckyBackend.removeEventListener('updater/update_download_percentage', a);
+ DeckyBackend.removeEventListener('updater/finish_download', b);
+ };
+ }, []);
+
return (
<>
<style>
@@ -149,6 +172,65 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
</button>
</div>
)}
+ {
+ <div style={{ display: 'block', marginBottom: '5px' }}>
+ {updateProgress > -1
+ ? 'Update in progress... ' + updateProgress + '%'
+ : updateProgress == -2
+ ? 'Update complete. Restarting...'
+ : 'Changing your Decky Loader branch and/or \n checking for updates might help!\n'}
+ {updateProgress == -1 && (
+ <div style={{ height: '30px' }}>
+ <select
+ style={{ height: '100%' }}
+ onChange={async (e) => {
+ const branch = parseInt(e.target.value);
+ setSelectedBranch(branch);
+ setSetVersionToUpdateTo('');
+ }}
+ >
+ <option value="0" selected={selectedBranch == UpdateBranch.Stable}>
+ Stable
+ </option>
+ <option value="1" selected={selectedBranch == UpdateBranch.Prerelease}>
+ Pre-Release
+ </option>
+ <option value="2" selected={selectedBranch == UpdateBranch.Testing}>
+ Testing
+ </option>
+ </select>
+ <button
+ style={{ height: '100%' }}
+ disabled={updateProgress != -1 || isChecking}
+ onClick={async () => {
+ if (versionToUpdateTo == '') {
+ setIsChecking(true);
+ const versionInfo = (await DeckyBackend.callable(
+ 'updater/check_for_updates',
+ )()) as unknown as VerInfo;
+ setIsChecking(false);
+ if (versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current) {
+ setSetVersionToUpdateTo(versionInfo.remote.tag_name);
+ } else {
+ setSetVersionToUpdateTo('');
+ }
+ } else {
+ DeckyBackend.callable('updater/do_update')();
+ setUpdateProgress(0);
+ }
+ }}
+ >
+ {' '}
+ {isChecking
+ ? 'Checking for updates...'
+ : versionToUpdateTo != ''
+ ? 'Update to ' + versionToUpdateTo
+ : 'Check for updates'}
+ </button>
+ </div>
+ )}
+ </div>
+ }
{wasCausedByPlugin && (
<div style={{ display: 'block', marginBottom: '5px' }}>
{'\n'}
diff --git a/frontend/src/components/Markdown.tsx b/frontend/src/components/Markdown.tsx
index cf6657aa..9842750d 100644
--- a/frontend/src/components/Markdown.tsx
+++ b/frontend/src/components/Markdown.tsx
@@ -1,4 +1,4 @@
-import { Focusable, Navigation } from '@decky/ui';
+import { Focusable, Navigation, findClass, findClassByName } from '@decky/ui';
import { FunctionComponent, useRef } from 'react';
import ReactMarkdown, { Options as ReactMarkdownOptions } from 'react-markdown';
import remarkGfm from 'remark-gfm';
@@ -8,6 +8,9 @@ interface MarkdownProps extends ReactMarkdownOptions {
}
const Markdown: FunctionComponent<MarkdownProps> = (props) => {
+ const eventDetailsBodyClassName = findClassByName('EventDetailsBody') || undefined;
+ const eventLinkClassName = findClass('43088', 'Link');
+
return (
<Focusable>
<ReactMarkdown
@@ -25,8 +28,10 @@ const Markdown: FunctionComponent<MarkdownProps> = (props) => {
Navigation.NavigateToExternalWeb(aRef.current!.href);
}}
style={{ display: 'inline' }}
+ focusClassName="steam-focus"
+ className={eventDetailsBodyClassName}
>
- <a ref={aRef} {...nodeProps.node.properties}>
+ <a ref={aRef} {...nodeProps.node.properties} className={eventLinkClassName}>
{nodeProps.children}
</a>
</Focusable>
diff --git a/frontend/src/components/modals/filepicker/patches/library.ts b/frontend/src/components/modals/filepicker/patches/library.ts
index 3b7fa679..b0930a5e 100644
--- a/frontend/src/components/modals/filepicker/patches/library.ts
+++ b/frontend/src/components/modals/filepicker/patches/library.ts
@@ -47,7 +47,7 @@ export default async function libraryPatch() {
}
const unlisten = History.listen(() => {
- if (window.SteamClient.Apps.PromptToChangeShortcut !== patch.patchedFunction) {
+ if ((window.SteamClient.Apps as any).PromptToChangeShortcut !== patch.patchedFunction) {
rePatch();
}
});
diff --git a/frontend/src/components/settings/pages/developer/index.tsx b/frontend/src/components/settings/pages/developer/index.tsx
index 099f2610..05989806 100644
--- a/frontend/src/components/settings/pages/developer/index.tsx
+++ b/frontend/src/components/settings/pages/developer/index.tsx
@@ -72,7 +72,16 @@ export default function DeveloperSettings() {
}
icon={<FaLink style={{ display: 'block' }} />}
>
- <DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}>
+ <DialogButton
+ disabled={pluginURL.length == 0}
+ onClick={() => {
+ if (/^https?:\/\//.test(pluginURL)) {
+ installFromURL(pluginURL);
+ } else {
+ installFromURL('https://' + pluginURL);
+ }
+ }}
+ >
{t('SettingsDeveloperIndex.third_party_plugins.button_install')}
</DialogButton>
</Field>
diff --git a/frontend/src/components/settings/pages/general/Updater.tsx b/frontend/src/components/settings/pages/general/Updater.tsx
index 59756a57..3cd58ab6 100644
--- a/frontend/src/components/settings/pages/general/Updater.tsx
+++ b/frontend/src/components/settings/pages/general/Updater.tsx
@@ -1,14 +1,4 @@
-import {
- Carousel,
- DialogButton,
- Field,
- FocusRing,
- Focusable,
- ProgressBarWithInfo,
- Spinner,
- findSP,
- showModal,
-} from '@decky/ui';
+import { Carousel, DialogButton, Field, Focusable, ProgressBarWithInfo, Spinner, findSP, showModal } from '@decky/ui';
import { Suspense, lazy, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FaExclamation } from 'react-icons/fa';
@@ -23,9 +13,31 @@ const MarkdownRenderer = lazy(() => import('../../../Markdown'));
function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | null; closeModal?: () => {} }) {
const SP = findSP();
const { t } = useTranslation();
+
return (
- <Focusable onCancelButton={closeModal}>
- <FocusRing>
+ <>
+ <style>
+ {`
+.steam-focus {
+ outline-offset: 3px;
+ outline: 2px solid rgba(255, 255, 255, 0.6);
+ animation: pulseOutline 1.2s infinite ease-in-out;
+}
+
+@keyframes pulseOutline {
+ 0% {
+ outline: 2px solid rgba(255, 255, 255, 0.6);
+ }
+ 50% {
+ outline: 2px solid rgba(255, 255, 255, 1);
+ }
+ 100% {
+ outline: 2px solid rgba(255, 255, 255, 0.6);
+ }
+}`}
+ </style>
+
+ <Focusable onCancelButton={closeModal}>
<Carousel
fnItemRenderer={(id: number) => (
<Focusable
@@ -35,7 +47,9 @@ function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | n
overflowY: 'scroll',
display: 'flex',
justifyContent: 'center',
- margin: '40px',
+ margin: '30px',
+ padding: '0 15px',
+ backgroundColor: 'rgba(37, 40, 46, 0.5)',
}}
>
<div>
@@ -57,11 +71,11 @@ function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | n
nItemMarginX={0}
initialColumn={0}
autoFocus={true}
- fnGetColumnWidth={() => SP.innerWidth}
+ fnGetColumnWidth={() => SP.innerWidth - SP.innerWidth * (10 / 100)}
name={t('Updater.decky_updates') as string}
/>
- </FocusRing>
- </Focusable>
+ </Focusable>
+ </>
);
}