summaryrefslogtreecommitdiff
path: root/frontend/src/components/store/PluginCard.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/store/PluginCard.tsx')
-rw-r--r--frontend/src/components/store/PluginCard.tsx277
1 files changed, 132 insertions, 145 deletions
diff --git a/frontend/src/components/store/PluginCard.tsx b/frontend/src/components/store/PluginCard.tsx
index aa5fd1d6..828d3ae9 100644
--- a/frontend/src/components/store/PluginCard.tsx
+++ b/frontend/src/components/store/PluginCard.tsx
@@ -1,15 +1,12 @@
import {
- DialogButton,
+ ButtonItem,
Dropdown,
Focusable,
- Navigation,
- QuickAccessTab,
+ PanelSectionRow,
SingleDropdownOption,
SuspensefulImage,
- joinClassNames,
- staticClasses,
} from 'decky-frontend-lib';
-import { FC, useRef, useState } from 'react';
+import { FC, useState } from 'react';
import { StorePlugin, StorePluginVersion, requestPluginInstall } from '../../store';
@@ -19,172 +16,162 @@ interface PluginCardProps {
const PluginCard: FC<PluginCardProps> = ({ plugin }) => {
const [selectedOption, setSelectedOption] = useState<number>(0);
- const buttonRef = useRef<HTMLDivElement>(null);
- const containerRef = useRef<HTMLDivElement>(null);
+ const root: boolean = plugin.tags.some((tag) => tag === 'root');
+
return (
<div
+ className="deckyStoreCard"
style={{
- padding: '30px',
- paddingTop: '10px',
- paddingBottom: '10px',
+ marginLeft: '20px',
+ marginRight: '20px',
+ marginBottom: '20px',
+ display: 'flex',
+ alignItems: 'center',
}}
>
- {/* TODO: abstract this messy focus hackiness into a custom component in lib */}
- <Focusable
- className="deckyStoreCard"
- ref={containerRef}
- onActivate={(_: CustomEvent) => {
- buttonRef.current!.focus();
- }}
- onCancel={(_: CustomEvent) => {
- if (containerRef.current!.querySelectorAll('* :focus').length === 0) {
- Navigation.NavigateBack();
- setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 1000);
- } else {
- containerRef.current!.focus();
- }
+ <div
+ className="deckyStoreCardImageContainer"
+ style={{
+ width: '320px',
+ height: '200px',
+ position: 'relative',
}}
+ >
+ <SuspensefulImage
+ className="deckyStoreCardImage"
+ suspenseHeight="200px"
+ suspenseWidth="320px"
+ style={{
+ width: '320px',
+ height: '200px',
+ objectFit: 'cover',
+ }}
+ src={plugin.image_url}
+ />
+ </div>
+ <div
+ className="deckyStoreCardInfo"
style={{
+ width: 'calc(100% - 320px)', // The calc is here so that the info section doesn't expand into the image
display: 'flex',
flexDirection: 'column',
- background: '#ACB2C924',
- height: 'unset',
- marginBottom: 'unset',
- // boxShadow: var(--gpShadow-Medium);
- scrollSnapAlign: 'start',
- boxSizing: 'border-box',
+ height: '100%',
+ marginLeft: '1em',
+ justifyContent: 'center',
}}
>
- <div className="deckyStoreCardHeader" style={{ display: 'flex', alignItems: 'center' }}>
- <div
- style={{ fontSize: '18pt', padding: '10px' }}
- className={joinClassNames(staticClasses.Text)}
- // onClick={() => Router.NavigateToExternalWeb('https://github.com/' + plugin.artifact)}
- >
- {plugin.name}
- </div>
- </div>
- <div
+ <span
+ className="deckyStoreCardTitle"
style={{
- display: 'flex',
- flexDirection: 'row',
- margin: '0 0 0 10px',
+ fontSize: '1.25em',
+ fontWeight: 'bold',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ width: '90%',
}}
- className="deckyStoreCardBody"
>
- <SuspensefulImage
- className="deckyStoreCardImage"
- suspenseWidth="256px"
- style={{
- width: 'auto',
- height: '160px',
- borderRadius: '5px',
- }}
- src={plugin.image_url}
- />
- <div
+ {plugin.name}
+ </span>
+ <span
+ className="deckyStoreCardAuthor"
+ style={{
+ marginRight: 'auto',
+ fontSize: '1em',
+ }}
+ >
+ {plugin.author}
+ </span>
+ <span
+ className="deckyStoreCardDescription"
+ style={{
+ fontSize: '13px',
+ color: '#969696',
+ WebkitLineClamp: root ? '2' : '3',
+ WebkitBoxOrient: 'vertical',
+ overflow: 'hidden',
+ display: '-webkit-box',
+ }}
+ >
+ {plugin.description ? (
+ plugin.description
+ ) : (
+ <span>
+ <i style={{ color: '#666' }}>No description provided.</i>
+ </span>
+ )}
+ </span>
+ {root && (
+ <span
+ className="deckyStoreCardDescription deckyStoreCardDescriptionRoot"
style={{
- display: 'flex',
- flexDirection: 'column',
+ fontSize: '13px',
+ color: '#fee75c',
}}
- className="deckyStoreCardInfo"
>
- <p
- className={joinClassNames(staticClasses.PanelSectionRow)}
- style={{ marginTop: '0px', marginLeft: '16px' }}
- >
- <span style={{ paddingLeft: '0px' }}>Author: {plugin.author}</span>
- </p>
- <p
- className={joinClassNames(staticClasses.PanelSectionRow)}
+ <i>This plugin has full access to your Steam Deck.</i>{' '}
+ <a
+ className="deckyStoreCardDescriptionRootLink"
+ href="https://deckbrew.xyz/root"
+ target="_blank"
style={{
- marginLeft: '16px',
- marginTop: '0px',
- marginBottom: '0px',
- marginRight: '16px',
+ color: '#fee75c',
+ textDecoration: 'none',
}}
>
- <span style={{ paddingLeft: '0px' }}>{plugin.description}</span>
- </p>
- <p
- className={joinClassNames('deckyStoreCardTagsContainer', staticClasses.PanelSectionRow)}
- style={{
- padding: '0 16px',
- display: 'flex',
- flexWrap: 'wrap',
- gap: '5px 10px',
- }}
- >
- <span style={{ padding: '5px 0' }}>Tags:</span>
- {plugin.tags.map((tag: string) => (
- <span
- className="deckyStoreCardTag"
- style={{
- padding: '5px',
- borderRadius: '5px',
- background: tag == 'root' ? '#842029' : '#ACB2C947',
- }}
- >
- {tag == 'root' ? 'Requires root' : tag}
- </span>
- ))}
- </p>
- </div>
- </div>
+ deckbrew.xyz/root
+ </a>
+ </span>
+ )}
<div
- className="deckyStoreCardActionsContainer"
+ className="deckyStoreCardButtonRow"
style={{
+ marginTop: '1em',
width: '100%',
- alignSelf: 'flex-end',
- display: 'flex',
- flexDirection: 'row',
+ overflow: 'hidden',
}}
>
- <Focusable
- className="deckyStoreCardActions"
- style={{
- display: 'flex',
- flexDirection: 'row',
- width: '100%',
- margin: '10px',
- }}
- >
- <div
- className="deckyStoreCardInstallButtonContainer"
- style={{
- flex: '1',
- margin: '0 10px 0 0',
- }}
- >
- <DialogButton
- className="deckyStoreCardInstallButton"
- ref={buttonRef}
- onClick={() => requestPluginInstall(plugin.name, plugin.versions[selectedOption])}
+ <PanelSectionRow>
+ <Focusable style={{ display: 'flex', maxWidth: '100%' }}>
+ <div
+ className="deckyStoreCardInstallContainer"
+ style={{
+ paddingTop: '0px',
+ paddingBottom: '0px',
+ width: '40%',
+ }}
>
- Install
- </DialogButton>
- </div>
- <div
- className="deckyStoreCardVersionDropdownContainer"
- style={{
- flex: '0.2',
- }}
- >
- <Dropdown
- rgOptions={
- plugin.versions.map((version: StorePluginVersion, index) => ({
- data: index,
- label: version.name,
- })) as SingleDropdownOption[]
- }
- strDefaultLabel={'Select a version'}
- selectedOption={selectedOption}
- onChange={({ data }) => setSelectedOption(data)}
- />
- </div>
- </Focusable>
+ <ButtonItem
+ bottomSeparator="none"
+ layout="below"
+ onClick={() => requestPluginInstall(plugin.name, plugin.versions[selectedOption])}
+ >
+ <span className="deckyStoreCardInstallText">Install</span>
+ </ButtonItem>
+ </div>
+ <div
+ className="deckyStoreCardVersionContainer"
+ style={{
+ marginLeft: '5%',
+ width: '30%',
+ }}
+ >
+ <Dropdown
+ rgOptions={
+ plugin.versions.map((version: StorePluginVersion, index) => ({
+ data: index,
+ label: version.name,
+ })) as SingleDropdownOption[]
+ }
+ menuLabel="Plugin Version"
+ selectedOption={selectedOption}
+ onChange={({ data }) => setSelectedOption(data)}
+ />
+ </div>
+ </Focusable>
+ </PanelSectionRow>
</div>
- </Focusable>
+ </div>
</div>
);
};