mirror of
https://github.com/Prowlarr/Prowlarr
synced 2025-12-06 08:34:28 +01:00
Fixed: Mobile add indexer modal layout (#2464)
* New: Add Indexer Filters are Collapsible fixes #2431 * Fixed: Rename onToggleFilters to handleToggleFilters * fix css lint
This commit is contained in:
parent
04a6bba76b
commit
4350b6ce70
3 changed files with 80 additions and 11 deletions
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
.scroller {
|
.scroller {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterRow {
|
.filterRow {
|
||||||
|
|
@ -57,29 +58,68 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filtersToggle {
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid var(--borderColor);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--textColor);
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filtersToggle:hover {
|
||||||
|
background-color: var(--hoverBackgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterRowCollapsed {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointSmall) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.filterInput {
|
.filterInput {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert {
|
.notice {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filtersToggle {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.filterRow {
|
.filterRow {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid var(--borderColor);
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: var(--cardBackgroundColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterContainer {
|
.filterContainer {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterContainer:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroller {
|
.scroller {
|
||||||
margin-right: -30px;
|
margin-right: -15px;
|
||||||
margin-bottom: -30px;
|
margin-bottom: -15px;
|
||||||
margin-left: -30px;
|
margin-left: -15px;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalBody {
|
||||||
|
padding: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ interface CssExports {
|
||||||
'filterInput': string;
|
'filterInput': string;
|
||||||
'filterLabel': string;
|
'filterLabel': string;
|
||||||
'filterRow': string;
|
'filterRow': string;
|
||||||
|
'filterRowCollapsed': string;
|
||||||
|
'filtersToggle': string;
|
||||||
'indexers': string;
|
'indexers': string;
|
||||||
'modalBody': string;
|
'modalBody': string;
|
||||||
'modalFooter': string;
|
'modalFooter': string;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
import { some } from 'lodash';
|
import { some } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
@ -7,6 +8,7 @@ import Alert from 'Components/Alert';
|
||||||
import EnhancedSelectInput from 'Components/Form/EnhancedSelectInput';
|
import EnhancedSelectInput from 'Components/Form/EnhancedSelectInput';
|
||||||
import NewznabCategorySelectInputConnector from 'Components/Form/NewznabCategorySelectInputConnector';
|
import NewznabCategorySelectInputConnector from 'Components/Form/NewznabCategorySelectInputConnector';
|
||||||
import TextInput from 'Components/Form/TextInput';
|
import TextInput from 'Components/Form/TextInput';
|
||||||
|
import Icon from 'Components/Icon';
|
||||||
import Button from 'Components/Link/Button';
|
import Button from 'Components/Link/Button';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
|
|
@ -16,7 +18,7 @@ import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import Scroller from 'Components/Scroller/Scroller';
|
import Scroller from 'Components/Scroller/Scroller';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import { kinds, scrollDirections } from 'Helpers/Props';
|
import { icons, kinds, scrollDirections } from 'Helpers/Props';
|
||||||
import Indexer, { IndexerCategory } from 'Indexer/Indexer';
|
import Indexer, { IndexerCategory } from 'Indexer/Indexer';
|
||||||
import {
|
import {
|
||||||
fetchIndexerSchema,
|
fetchIndexerSchema,
|
||||||
|
|
@ -25,6 +27,7 @@ import {
|
||||||
} from 'Store/Actions/indexerActions';
|
} from 'Store/Actions/indexerActions';
|
||||||
import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector';
|
import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector';
|
||||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
import { SortCallback } from 'typings/callbacks';
|
import { SortCallback } from 'typings/callbacks';
|
||||||
import sortByProp from 'Utilities/Array/sortByProp';
|
import sortByProp from 'Utilities/Array/sortByProp';
|
||||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
|
|
@ -111,7 +114,8 @@ function createAddIndexersSelector() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createClientSideCollectionSelector('indexers.schema'),
|
createClientSideCollectionSelector('indexers.schema'),
|
||||||
createAllIndexersSelector(),
|
createAllIndexersSelector(),
|
||||||
(indexers: IndexerAppState, allIndexers) => {
|
createDimensionsSelector(),
|
||||||
|
(indexers: IndexerAppState, allIndexers, dimensions) => {
|
||||||
const { isFetching, isPopulated, error, items, sortDirection, sortKey } =
|
const { isFetching, isPopulated, error, items, sortDirection, sortKey } =
|
||||||
indexers;
|
indexers;
|
||||||
|
|
||||||
|
|
@ -130,6 +134,7 @@ function createAddIndexersSelector() {
|
||||||
indexers: indexerList,
|
indexers: indexerList,
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
sortDirection,
|
||||||
|
isSmallScreen: dimensions.isSmallScreen,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -143,8 +148,15 @@ interface AddIndexerModalContentProps {
|
||||||
function AddIndexerModalContent(props: AddIndexerModalContentProps) {
|
function AddIndexerModalContent(props: AddIndexerModalContentProps) {
|
||||||
const { onSelectIndexer, onModalClose } = props;
|
const { onSelectIndexer, onModalClose } = props;
|
||||||
|
|
||||||
const { isFetching, isPopulated, error, indexers, sortKey, sortDirection } =
|
const {
|
||||||
useSelector(createAddIndexersSelector());
|
isFetching,
|
||||||
|
isPopulated,
|
||||||
|
error,
|
||||||
|
indexers,
|
||||||
|
sortKey,
|
||||||
|
sortDirection,
|
||||||
|
isSmallScreen,
|
||||||
|
} = useSelector(createAddIndexersSelector());
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [filter, setFilter] = useState('');
|
const [filter, setFilter] = useState('');
|
||||||
|
|
@ -152,6 +164,7 @@ function AddIndexerModalContent(props: AddIndexerModalContentProps) {
|
||||||
const [filterLanguages, setFilterLanguages] = useState<string[]>([]);
|
const [filterLanguages, setFilterLanguages] = useState<string[]>([]);
|
||||||
const [filterPrivacyLevels, setFilterPrivacyLevels] = useState<string[]>([]);
|
const [filterPrivacyLevels, setFilterPrivacyLevels] = useState<string[]>([]);
|
||||||
const [filterCategories, setFilterCategories] = useState<number[]>([]);
|
const [filterCategories, setFilterCategories] = useState<number[]>([]);
|
||||||
|
const [isFiltersCollapsed, setIsFiltersCollapsed] = useState(isSmallScreen);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -196,6 +209,10 @@ function AddIndexerModalContent(props: AddIndexerModalContentProps) {
|
||||||
[setFilterCategories]
|
[setFilterCategories]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleToggleFilters = useCallback(() => {
|
||||||
|
setIsFiltersCollapsed(!isFiltersCollapsed);
|
||||||
|
}, [isFiltersCollapsed]);
|
||||||
|
|
||||||
const onIndexerSelect = useCallback(
|
const onIndexerSelect = useCallback(
|
||||||
({
|
({
|
||||||
implementation,
|
implementation,
|
||||||
|
|
@ -322,7 +339,17 @@ function AddIndexerModalContent(props: AddIndexerModalContentProps) {
|
||||||
onChange={onFilterChange}
|
onChange={onFilterChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={styles.filterRow}>
|
<Button className={styles.filtersToggle} onPress={handleToggleFilters}>
|
||||||
|
<Icon name={isFiltersCollapsed ? icons.EXPAND : icons.COLLAPSE} />
|
||||||
|
{translate('Filters')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
styles.filterRow,
|
||||||
|
isFiltersCollapsed && styles.filterRowCollapsed
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div className={styles.filterContainer}>
|
<div className={styles.filterContainer}>
|
||||||
<label className={styles.filterLabel}>
|
<label className={styles.filterLabel}>
|
||||||
{translate('Protocol')}
|
{translate('Protocol')}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue