mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 17:15:48 +00:00
refactor: move filters code to a new component and use it on routes
This commit is contained in:
parent
74b84c1123
commit
6703b9771b
10 changed files with 180 additions and 127 deletions
32
src/common/Filters/Filters.js
Normal file
32
src/common/Filters/Filters.js
Normal 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;
|
||||
2
src/common/Filters/index.js
Normal file
2
src/common/Filters/index.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
const Filters = require('./Filters');
|
||||
module.exports = Filters;
|
||||
45
src/common/Filters/styles.less
Normal file
45
src/common/Filters/styles.less
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 ?
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue