Store and plugin installation visual improvements (#343)

* Redesign store, add comments for filtering

* Improve installation/uninstallation modals

* Fix store comment to be easier to fix

* Add source code info to about page
This commit is contained in:
EMERALD
2023-01-19 20:00:42 -06:00
committed by GitHub
parent cbbd564860
commit 3ebaac6752
10 changed files with 408 additions and 202 deletions
+206 -18
View File
@@ -1,6 +1,16 @@
import { SteamSpinner } from 'decky-frontend-lib';
import { FC, useEffect, useState } from 'react';
import {
Dropdown,
DropdownOption,
Focusable,
PanelSectionRow,
SteamSpinner,
Tabs,
TextField,
findModule,
} from 'decky-frontend-lib';
import { FC, useEffect, useMemo, useState } from 'react';
import logo from '../../../assets/plugin_store.png';
import Logger from '../../logger';
import { StorePlugin, getPluginList } from '../../store';
import PluginCard from './PluginCard';
@@ -8,7 +18,12 @@ import PluginCard from './PluginCard';
const logger = new Logger('FilePicker');
const StorePage: FC<{}> = () => {
const [currentTabRoute, setCurrentTabRoute] = useState<string>('browse');
const [data, setData] = useState<StorePlugin[] | null>(null);
const { TabCount } = findModule((m) => {
if (m?.TabCount && m?.TabTitle) return true;
return false;
});
useEffect(() => {
(async () => {
@@ -19,19 +34,12 @@ const StorePage: FC<{}> = () => {
}, []);
return (
<div
style={{
marginTop: '40px',
height: 'calc( 100% - 40px )',
overflowY: 'scroll',
}}
>
<>
<div
style={{
display: 'flex',
flexWrap: 'nowrap',
flexDirection: 'column',
height: '100%',
marginTop: '40px',
height: 'calc( 100% - 40px )',
background: '#0005',
}}
>
{!data ? (
@@ -39,13 +47,193 @@ const StorePage: FC<{}> = () => {
<SteamSpinner />
</div>
) : (
<div>
{data.map((plugin: StorePlugin) => (
<PluginCard plugin={plugin} />
))}
</div>
<Tabs
activeTab={currentTabRoute}
onShowTab={(tabId: string) => {
setCurrentTabRoute(tabId);
}}
tabs={[
{
title: 'Browse',
content: <BrowseTab children={{ data: data }} />,
id: 'browse',
renderTabAddon: () => <span className={TabCount}>{data.length}</span>,
},
{
title: 'About',
content: <AboutTab />,
id: 'about',
},
]}
/>
)}
</div>
</>
);
};
const BrowseTab: FC<{ children: { data: StorePlugin[] } }> = (data) => {
const sortOptions = useMemo(
(): DropdownOption[] => [
{ data: 1, label: 'Alphabetical (A to Z)' },
{ data: 2, label: 'Alphabetical (Z to A)' },
],
[],
);
// const filterOptions = useMemo((): DropdownOption[] => [{ data: 1, label: 'All' }], []);
const [selectedSort, setSort] = useState<number>(sortOptions[0].data);
// const [selectedFilter, setFilter] = useState<number>(filterOptions[0].data);
const [searchFieldValue, setSearchValue] = useState<string>('');
return (
<>
<style>{`
.deckyStoreCardInstallContainer > .Panel {
padding: 0;
}
`}</style>
{/* This should be used once filtering is added
<PanelSectionRow>
<Focusable style={{ display: 'flex', maxWidth: '100%' }}>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '47.5%',
}}
>
<span className="DialogLabel">Sort</span>
<Dropdown
menuLabel="Sort"
rgOptions={sortOptions}
strDefaultLabel="Last Updated (Newest)"
selectedOption={selectedSort}
onChange={(e) => setSort(e.data)}
/>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '47.5%',
marginLeft: 'auto',
}}
>
<span className="DialogLabel">Filter</span>
<Dropdown
menuLabel="Filter"
rgOptions={filterOptions}
strDefaultLabel="All"
selectedOption={selectedFilter}
onChange={(e) => setFilter(e.data)}
/>
</div>
</Focusable>
</PanelSectionRow>
<div style={{ justifyContent: 'center', display: 'flex' }}>
<Focusable style={{ display: 'flex', alignItems: 'center', width: '96%' }}>
<div style={{ width: '100%' }}>
<TextField label="Search" value={searchFieldValue} onChange={(e) => setSearchValue(e.target.value)} />
</div>
</Focusable>
</div>
*/}
<PanelSectionRow>
<Focusable style={{ display: 'flex', maxWidth: '100%' }}>
<div
style={{
display: 'flex',
flexDirection: 'column',
minWidth: '100%',
maxWidth: '100%',
}}
>
<span className="DialogLabel">Sort</span>
<Dropdown
menuLabel="Sort"
rgOptions={sortOptions}
strDefaultLabel="Last Updated (Newest)"
selectedOption={selectedSort}
onChange={(e) => setSort(e.data)}
/>
</div>
</Focusable>
</PanelSectionRow>
<div style={{ justifyContent: 'center', display: 'flex' }}>
<Focusable style={{ display: 'flex', alignItems: 'center', width: '96%' }}>
<div style={{ width: '100%' }}>
<TextField label="Search" value={searchFieldValue} onChange={(e) => setSearchValue(e.target.value)} />
</div>
</Focusable>
</div>
<div>
{data.children.data
.filter((plugin: StorePlugin) => {
return (
plugin.name.toLowerCase().includes(searchFieldValue.toLowerCase()) ||
plugin.description.toLowerCase().includes(searchFieldValue.toLowerCase()) ||
plugin.author.toLowerCase().includes(searchFieldValue.toLowerCase()) ||
plugin.tags.some((tag: string) => tag.toLowerCase().includes(searchFieldValue.toLowerCase()))
);
})
.sort((a, b) => {
if (selectedSort % 2 === 1) return a.name.localeCompare(b.name);
else return b.name.localeCompare(a.name);
})
.map((plugin: StorePlugin) => (
<PluginCard plugin={plugin} />
))}
</div>
</>
);
};
const AboutTab: FC<{}> = () => {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
}}
>
<style>{`
.deckyStoreAboutHeader {
font-size: 24px;
font-weight: 600;
margin-top: 20px;
}
`}</style>
<img
src={logo}
style={{
width: '256px',
height: 'auto',
alignSelf: 'center',
}}
/>
<span className="deckyStoreAboutHeader">Testing</span>
<span>
Please consider testing new plugins to help the Decky Loader team!{' '}
<a
href="https://deckbrew.xyz/testing"
target="_blank"
style={{
textDecoration: 'none',
}}
>
deckbrew.xyz/testing
</a>
</span>
<span className="deckyStoreAboutHeader">Contributing</span>
<span>
If you would like to contribute to the Decky Plugin Store, check the SteamDeckHomebrew/decky-plugin-template
repository on GitHub. Information on development and distribution is available in the README.
</span>
<span className="deckyStoreAboutHeader">Source Code</span>
<span>All plugin source code is available on SteamDeckHomebrew/decky-plugin-database repository on GitHub.</span>
</div>
);
};