diff options
Diffstat (limited to 'frontend/src/components/store/PluginCard.tsx')
| -rw-r--r-- | frontend/src/components/store/PluginCard.tsx | 277 |
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> ); }; |
