refactor: move filters code to a new component and use it on routes

This commit is contained in:
Tim 2022-02-16 23:09:38 +01:00
parent 74b84c1123
commit 6703b9771b
10 changed files with 180 additions and 127 deletions

View file

@ -0,0 +1,32 @@
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const Button = require('stremio/common/Button');
const styles = require('./styles');
const Icon = require('@stremio/stremio-icons/dom');
const Filters = ({ className, children }) => {
const [filtersMenuOpen, setFiltersMenuOpen] = React.useState(false);
return (
<div className={classnames(className, styles['filters-container'])}>
<Button className={styles['filters-button-container']} title={'Filter items'} onClick={() => setFiltersMenuOpen(!filtersMenuOpen)}>
<Icon className={styles['icon']} icon={'ic_filter'} />
</Button>
{
filtersMenuOpen ?
<div className={styles['filters-menu-container']}>
{ children }
</div>
:
null
}
</div>
);
};
Filters.propTypes = {
className: PropTypes.string,
children: PropTypes.node
};
module.exports = Filters;

View file

@ -0,0 +1,2 @@
const Filters = require('./Filters');
module.exports = Filters;

View file

@ -0,0 +1,45 @@
@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less';
.filters-container {
flex: 0 0 auto;
.filters-button-container {
display: flex;
flex: none;
flex-direction: row;
align-items: center;
justify-content: center;
height: 3.5rem;
padding: 0 1rem;
background-color: @color-background;
.icon {
flex: none;
width: 1.2rem;
height: 1.2rem;
fill: @color-secondaryvariant1-90;
}
}
.filters-menu-container {
z-index: 99;
flex: auto;
display: flex;
position: absolute;
top: 5em;
left: 0;
right: 0;
flex-direction: column;
gap: 1em;
padding: 1.5em;
background-color: @color-background-dark2;
box-shadow: 0 1.35rem 2.7rem @color-background-dark5-40,
0 1.1rem 0.85rem @color-background-dark5-20;
overflow: visible;
.select-input-container {
flex-basis: 3.5em;
margin-right: 0;
}
}
}

View file

@ -4,6 +4,7 @@ const AddonDetailsModal = require('./AddonDetailsModal');
const Button = require('./Button');
const Checkbox = require('./Checkbox');
const ColorInput = require('./ColorInput');
const Filters = require('./Filters');
const Image = require('./Image');
const LibItem = require('./LibItem');
const MainNavBars = require('./MainNavBars');
@ -43,6 +44,7 @@ module.exports = {
Button,
Checkbox,
ColorInput,
Filters,
Image,
LibItem,
MainNavBars,

View file

@ -10,6 +10,7 @@ const useRemoteAddons = require('./useRemoteAddons');
const useAddonDetailsTransportUrl = require('./useAddonDetailsTransportUrl');
const useSelectableInputs = require('./useSelectableInputs');
const styles = require('./styles');
const { Filters } = require('stremio/common');
const Addons = ({ urlParams, queryParams }) => {
const installedAddons = useInstalledAddons(urlParams);
@ -40,7 +41,6 @@ const Addons = ({ urlParams, queryParams }) => {
}
];
}, [addAddonOnSubmit]);
const [filtersMenuOpen, setFiltersMenuOpen] = React.useState(false);
const [search, setSearch] = React.useState('');
const searchInputOnChange = React.useCallback((event) => {
setSearch(event.currentTarget.value);
@ -100,17 +100,9 @@ const Addons = ({ urlParams, queryParams }) => {
value={search}
onChange={searchInputOnChange}
/>
<Button className={styles['filter-button-container']} title={'Filter addons'} onClick={() => setFiltersMenuOpen(!filtersMenuOpen)}>
<Icon className={styles['icon']} icon={'ic_filter'} />
</Button>
{
filtersMenuOpen ?
<div className={styles['filters-menu-container']}>
{ renderMultiselectsInputs() }
</div>
:
null
}
<Filters className={styles['filters']}>
{ renderMultiselectsInputs() }
</Filters>
</div>
{
installedAddons.selected !== null ?

View file

@ -71,45 +71,6 @@
}
}
.filter-button-container {
display: none;
flex: none;
flex-direction: row;
align-items: center;
justify-content: center;
height: 3.5rem;
padding: 0 1rem;
background-color: @color-background;
.icon {
flex: none;
width: 1.2rem;
height: 1.2rem;
fill: @color-secondaryvariant1-90;
}
}
.filters-menu-container {
flex: auto;
display: flex;
position: absolute;
top: 5em;
left: 0;
right: 0;
flex-direction: column;
gap: 1em;
padding: 1.5em;
background-color: @color-background-dark2;
box-shadow: 0 1.35rem 2.7rem @color-background-dark5-40,
0 1.1rem 0.85rem @color-background-dark5-20;
overflow: visible;
.select-input-container {
flex-basis: 3.5em;
margin-right: 0;
}
}
.multiselect-inputs-container {
flex: auto;
display: flex;
@ -139,6 +100,10 @@
flex-shrink: 1;
flex-basis: 18rem;
}
.filters {
display: none;
}
}
.message-container {
@ -270,8 +235,6 @@
.addons-container {
.addons-content {
.selectable-inputs-container {
position: relative;
flex-direction: row;
gap: 1em;
.add-button-container {
@ -281,9 +244,9 @@
box-shadow: 0 1.35rem 2.7rem @color-background-dark5-40,
0 1.1rem 0.85rem @color-background-dark5-20;
}
.filter-button-container {
display: flex;
.select-input-container {
flex: 0 1 3.5em;
}
.multiselect-inputs-container {
@ -297,6 +260,10 @@
.search-bar {
flex-basis: 100%;
}
.filters {
display: block;
}
}
}
}

View file

@ -9,12 +9,12 @@ const { AddonDetailsModal, Button, MainNavBars, MetaItem, Image, MetaPreview, Mu
const useDiscover = require('./useDiscover');
const useSelectableInputs = require('./useSelectableInputs');
const styles = require('./styles');
const { Filters } = require('stremio/common');
const Discover = ({ urlParams, queryParams }) => {
const { core } = useServices();
const discover = useDiscover(urlParams, queryParams);
const [selectInputs, paginationInput] = useSelectableInputs(discover);
const [filtersMenuOpen, setFiltersMenuOpen] = React.useState(false);
const [inputsModalOpen, openInputsModal, closeInputsModal] = useBinaryState(false);
const [addonModalOpen, openAddonModal, closeAddonModal] = useBinaryState(false);
const [selectedMetaItemIndex, setSelectedMetaItemIndex] = React.useState(0);
@ -107,17 +107,9 @@ const Discover = ({ urlParams, queryParams }) => {
:
<PaginationInput label={'1'} className={classnames(styles['pagination-input'], styles['pagination-input-placeholder'])} />
}
<Button className={styles['filter-button-container']} title={'Filter items'} onClick={() => setFiltersMenuOpen(!filtersMenuOpen)}>
<Icon className={styles['icon']} icon={'ic_filter'} />
</Button>
{
filtersMenuOpen ?
<div className={styles['filters-menu-container']}>
{ renderMultiselectsInputs() }
</div>
:
null
}
<Filters className={styles['filters']}>
{ renderMultiselectsInputs() }
</Filters>
</div>
:
null

View file

@ -43,46 +43,6 @@
padding: 1.5rem;
overflow: visible;
.filter-button-container {
display: none;
flex: none;
flex-direction: row;
align-items: center;
justify-content: center;
height: 3.5rem;
padding: 0 1rem;
background-color: @color-background;
.icon {
flex: none;
width: 1.2rem;
height: 1.2rem;
fill: @color-secondaryvariant1-90;
}
}
.filters-menu-container {
z-index: 99;
flex: auto;
display: flex;
position: absolute;
top: 5em;
left: 0;
right: 0;
flex-direction: column;
gap: 1em;
padding: 1.5em;
background-color: @color-background-dark2;
box-shadow: 0 1.35rem 2.7rem @color-background-dark5-40,
0 1.1rem 0.85rem @color-background-dark5-20;
overflow: visible;
.select-input-container {
flex-basis: 3.5em;
margin-right: 0;
}
}
.multiselect-inputs-container {
flex: auto;
display: flex;
@ -167,6 +127,10 @@
width: 3rem;
}
}
.filters {
display: none;
}
}
.missing-addon-warning-container {
@ -491,8 +455,6 @@
.discover-content {
.catalog-container {
.selectable-inputs-container {
position: relative;
flex-direction: row;
justify-content: space-between;
gap: 1em;
@ -504,10 +466,6 @@
}
}
.filter-button-container {
display: flex;
}
.multiselect-inputs-container {
display: none;
}
@ -519,6 +477,10 @@
.pagination-input {
margin-left: 0;
}
.filters {
display: block;
}
}
.meta-items-container {

View file

@ -8,6 +8,7 @@ const { Button, Multiselect, MainNavBars, LibItem, Image, PaginationInput, usePr
const useLibrary = require('./useLibrary');
const useSelectableInputs = require('./useSelectableInputs');
const styles = require('./styles');
const { Filters } = require('stremio/common');
function withModel(Library) {
const withModel = ({ urlParams, queryParams }) => {
@ -46,14 +47,19 @@ const Library = ({ model, urlParams, queryParams }) => {
const profile = useProfile();
const library = useLibrary(model, urlParams, queryParams);
const [typeSelect, sortSelect, paginationInput] = useSelectableInputs(library);
const multiselectInputs = <>
<Multiselect {...typeSelect} className={styles['select-input-container']} />
<Multiselect {...sortSelect} className={styles['select-input-container']} />
</>;
return (
<MainNavBars className={styles['library-container']} route={model}>
<div className={styles['library-content']}>
{
model === 'continue_watching' || profile.auth !== null ?
<div className={styles['selectable-inputs-container']}>
<Multiselect {...typeSelect} className={styles['select-input-container']} />
<Multiselect {...sortSelect} className={styles['select-input-container']} />
<div className={styles['multiselect-inputs-container']}>
{ multiselectInputs }
</div>
<div className={styles['spacing']} />
{
paginationInput !== null ?
@ -61,6 +67,9 @@ const Library = ({ model, urlParams, queryParams }) => {
:
<PaginationInput label={'1'} className={classnames(styles['pagination-input'], styles['pagination-input-placeholder'])} />
}
<Filters className={styles['filters']}>
{ multiselectInputs }
</Filters>
</div>
:
null

View file

@ -33,19 +33,26 @@
padding: 1.5rem;
overflow: visible;
.select-input-container {
flex-grow: 0;
flex-shrink: 1;
flex-basis: 15rem;
height: 3.5rem;
.multiselect-inputs-container {
flex: auto;
display: flex;
flex-direction: row;
overflow: visible;
&:not(:last-child) {
margin-right: 1.5rem;
}
.select-input-container {
flex-grow: 0;
flex-shrink: 1;
flex-basis: 15rem;
height: 3.5rem;
.multiselect-menu-container {
max-height: calc(3.2rem * 7);
overflow: auto;
&:not(:last-child) {
margin-right: 1.5rem;
}
.multiselect-menu-container {
max-height: calc(3.2rem * 7);
overflow: auto;
}
}
}
@ -86,6 +93,10 @@
width: 3rem;
}
}
.filters {
display: none;
}
}
.message-container {
@ -230,4 +241,43 @@
}
}
}
}
@media only screen and (max-width: @minimum) {
.library-container {
.library-content {
.selectable-inputs-container {
justify-content: space-between;
gap: 1em;
.select-input-container {
flex-basis: 3.5em;
&:not(:last-child) {
margin-right: 0;
}
}
.multiselect-inputs-container {
display: none;
}
.spacing {
display: none;
}
.pagination-input {
margin-left: 0;
}
.filters {
display: block;
}
}
.meta-items-container {
grid-template-columns: repeat(3, 1fr);
}
}
}
}