feat: multiple label filter

- add search functionality in menu items
This commit is contained in:
Aien Saidi 2021-03-24 00:37:04 +01:00 committed by Sascha
parent 7a7e93c913
commit 92ce861fab
2 changed files with 71 additions and 23 deletions

View File

@ -1,14 +1,26 @@
import clsx from 'clsx';
import { LocationDescriptor } from 'history';
import React, { useState, useRef } from 'react';
import React, { useRef, useState } from 'react';
import { Link } from 'react-router-dom';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import { SvgIconProps } from '@material-ui/core/SvgIcon';
import { makeStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import { makeStyles, withStyles } from '@material-ui/core/styles';
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
const CustomTextField = withStyles({
root: {
margin: '0 8px 12px 8px',
'& label.Mui-focused': {
margin: '0 2px',
},
},
})(TextField);
const ITEM_HEIGHT = 48;
export type Query = { [key: string]: string[] };
function parse(query: string): Query {
@ -90,6 +102,7 @@ type FilterDropdownProps = {
itemActive: (key: string) => boolean;
icon?: React.ComponentType<SvgIconProps>;
to: (key: string) => LocationDescriptor;
hasFilter?: boolean;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
function FilterDropdown({
@ -98,9 +111,11 @@ function FilterDropdown({
itemActive,
icon: Icon,
to,
hasFilter,
...props
}: FilterDropdownProps) {
const [open, setOpen] = useState(false);
const [filter, setFilter] = useState<string>('');
const buttonRef = useRef<HTMLButtonElement>(null);
const classes = useStyles({ active: false });
@ -135,18 +150,36 @@ function FilterDropdown({
open={open}
onClose={() => setOpen(false)}
anchorEl={buttonRef.current}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5,
width: '20ch',
},
}}
>
{dropdown.map(([key, value]) => (
<MenuItem
component={Link}
to={to(key)}
className={itemActive(key) ? classes.itemActive : undefined}
onClick={() => setOpen(false)}
key={key}
>
{value}
</MenuItem>
))}
{hasFilter && (
<CustomTextField
onChange={(e) => {
const { value } = e.target;
setFilter(value);
}}
value={filter}
label={`Filter ${children}`}
/>
)}
{dropdown
.filter((d) => d[1].toLowerCase().includes(filter.toLowerCase()))
.map(([key, value]) => (
<MenuItem
component={Link}
to={to(key)}
className={itemActive(key) ? classes.itemActive : undefined}
onClick={() => setOpen(false)}
key={key}
>
{value}
</MenuItem>
))}
</Menu>
</>
);
@ -158,6 +191,7 @@ export type FilterProps = {
icon?: React.ComponentType<SvgIconProps>;
children: React.ReactNode;
};
function Filter({ active, to, children, icon: Icon }: FilterProps) {
const classes = useStyles();

View File

@ -109,6 +109,20 @@ function FilterToolbar({ query, queryLocation }: Props) {
...params,
[key]: params[key] && params[key].includes(value) ? [] : [value],
});
const toggleOrAddParam = (key: string, value: string) => (
params: Query
): Query => {
const values = params[key];
return {
...params,
[key]:
params[key] && params[key].includes(value)
? values.filter((v) => v !== value)
: values
? [...values, value]
: [value],
};
};
const clearParam = (key: string) => (params: Query): Query => ({
...params,
[key]: [],
@ -150,18 +164,18 @@ function FilterToolbar({ query, queryLocation }: Props) {
dropdown={identities}
itemActive={(key) => hasValue('author', key)}
to={(key) => pipe(replaceParam('author', key), loc)(params)}
hasFilter
>
Author
</FilterDropdown>
{labels.length ? (
<FilterDropdown
dropdown={labels}
itemActive={(key) => hasValue('label', key)}
to={(key) => pipe(replaceParam('label', key), loc)(params)}
>
Label
</FilterDropdown>
) : null}
<FilterDropdown
dropdown={labels}
itemActive={(key) => hasValue('label', key)}
to={(key) => pipe(toggleOrAddParam('label', key), loc)(params)}
hasFilter
>
Label
</FilterDropdown>
<FilterDropdown
dropdown={[
['id', 'ID'],
@ -171,7 +185,7 @@ function FilterToolbar({ query, queryLocation }: Props) {
['edit-asc', 'Least recently updated'],
]}
itemActive={(key) => hasValue('sort', key)}
to={(key) => pipe(replaceParam('sort', key), loc)(params)}
to={(key) => pipe(toggleParam('sort', key), loc)(params)}
>
Sort
</FilterDropdown>