Skip to content

Commit

Permalink
Merge pull request #25 from DagsHub/feature/grouped-display-filters
Browse files Browse the repository at this point in the history
Feature | grouped display filters
  • Loading branch information
elad-n authored Sep 14, 2023
2 parents e8eeeca + 9cb4123 commit a79da1b
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 19 deletions.
47 changes: 47 additions & 0 deletions src/components/elements/controlledDisplayFiltersGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useState } from 'react';
import { Box } from '@mui/material';
import { DisplayFilter, DisplayFilterProps } from '../displayFilter';
import React from 'react';
import { LabeledSwitch } from '../../forms';

export interface ControlledDisplayFiltersGroupProps {
filters: DisplayFilterProps[];
label?: string;
toggleShowAll: (show: boolean) => void;
onFilterChange: (name: string, show: boolean) => void;
}

export function ControlledDisplayFiltersGroup({
filters,
onFilterChange,
toggleShowAll,
label
}: ControlledDisplayFiltersGroupProps) {
const [showAll, setShowAll] = useState<boolean>(false);

const toggleAll = () => {
setShowAll(!showAll);
toggleShowAll(!showAll);
};

const updateFilter = (name: string, show: boolean) => {
onFilterChange(name, show);
};

return (
<Box>
<Box>
<LabeledSwitch label={label} onChange={toggleAll} />
</Box>
{filters.map((item) => {
return (
<DisplayFilter
value={showAll}
label={item.label}
onChange={(show) => updateFilter(item.label, show)}
/>
);
})}
</Box>
);
}
51 changes: 51 additions & 0 deletions src/components/elements/displayFilter/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Stack, Typography } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { Icon } from '../../icons';

export interface DisplayFilterProps {
label: string;
onChange: (show: boolean) => void;
value: boolean;
}
export function DisplayFilter({ label, onChange, value }: DisplayFilterProps) {
const [show, setShow] = useState<boolean>(false);

const filterClicked = () => {
const currentShow = show;
setShow(!currentShow);
onChange(!currentShow);
};

useEffect(() => {
setShow(value);
}, [value]);

return (
<Stack
gap={1}
direction={'row'}
sx={{ cursor: 'pointer', width: 'fit-content' }}
display={'flex'}
justifyContent={'space-between'}
alignItems={'center'}
onClick={filterClicked}
role={'button'}
>
<Typography
sx={{
padding: 1,
lineHeight: '20px',
color: '#172D32',
fontFamily: 'Inter',
fontSize: '14px',
fontWeight: 500,
width: '144px'
}}
>
{label}
</Typography>

<Icon icon={show ? 'eye' : 'eye-off'} height={16} width={16} fill={'#94A3B8'} />
</Stack>
);
}
3 changes: 2 additions & 1 deletion src/components/elements/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './dropdownV2';
export * from './code-block';
export * from './tooltip';
export * from './genericError';

export * from './displayFilter';
export * from './controlledDisplayFiltersGroup';
1 change: 1 addition & 0 deletions src/components/forms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './input';
export * from './textarea';
export * from './radio-button/radio-button-item';
export * from './radio-button/radio-button-list';
export * from './labeledSwitch';
65 changes: 65 additions & 0 deletions src/components/forms/labeledSwitch/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch, { SwitchProps } from '@mui/material/Switch';

const StyledSwitch = styled((props: SwitchProps) => (
<Switch focusVisibleClassName=".Mui-focusVisible" disableRipple {...props} />
))(({ theme }) => ({
width: 48,
height: 24,
padding: 0,
'& .MuiSwitch-switchBase': {
padding: 0,
margin: '2px',
transitionDuration: '300ms',
'&.Mui-checked': {
transform: 'translateX(24px)',
color: '#fff',
'& + .MuiSwitch-track': {
backgroundColor: theme.palette.mode === 'dark' ? '#2ECA45' : '#65C466',
opacity: 1,
border: 0
},
'&.Mui-disabled + .MuiSwitch-track': {
opacity: 0.5
}
},
'&.Mui-focusVisible .MuiSwitch-thumb': {
color: '#33cf4d',
border: '6px solid #fff'
},
'&.Mui-disabled .MuiSwitch-thumb': {
color: theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[600]
},
'&.Mui-disabled + .MuiSwitch-track': {
opacity: theme.palette.mode === 'light' ? 0.7 : 0.3
}
},
'& .MuiSwitch-thumb': {
boxSizing: 'border-box',
width: 20,
height: 20
},
'& .MuiSwitch-track': {
borderRadius: 23 / 2,
backgroundColor: theme.palette.mode === 'light' ? '#E9E9EA' : '#39393D',
opacity: 1,
transition: theme.transitions.create(['background-color'], {
duration: 500
})
}
}));

export function LabeledSwitch({ onChange, label }: { onChange: () => void; label?: string }) {
return (
<FormGroup>
<FormControlLabel
onChange={onChange}
control={<StyledSwitch sx={{ m: 1 }} defaultChecked />}
label={label}
/>
</FormGroup>
);
}
57 changes: 40 additions & 17 deletions src/components/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,7 @@ export const icons = {
</defs>
</svg>
),
'redirect': ({ fill, width, height, onClick = () => {} }: IconProp) => (
redirect: ({ fill, width, height, onClick = () => {} }: IconProp) => (
<svg
width={width}
height={height}
Expand Down Expand Up @@ -1660,7 +1660,7 @@ export const icons = {
/>
</svg>
),
'beaker': ({ fill, width, height, onClick = () => {} }: IconProp) => (
beaker: ({ fill, width, height, onClick = () => {} }: IconProp) => (
<svg
width={width}
height={height}
Expand Down Expand Up @@ -1729,7 +1729,7 @@ export const icons = {
/>
</svg>
),
'annotations': ({ fill, width, height, onClick = () => {} }: IconProp) => (
annotations: ({ fill, width, height, onClick = () => {} }: IconProp) => (
<svg
width={width}
height={height}
Expand All @@ -1747,23 +1747,46 @@ export const icons = {
</svg>
),
'code-tags': ({ fill, width, height, onClick = () => {} }: IconProp) => (
<svg width={width} height={height} viewBox="0 0 16 16" fill={fill} xmlns="http://www.w3.org/2000/svg">
<g id="Icon/Solid/code">
<path id="Icon" fill-rule="evenodd" clip-rule="evenodd" d="M9.85297 2.44105C10.2721 2.58077 10.4987 3.03382 10.3589 3.45298L7.15893 13.053C7.01922 13.4721 6.56616 13.6987 6.14701 13.5589C5.72785 13.4192 5.50132 12.9662 5.64104 12.547L8.84104 2.94702C8.98076 2.52786 9.43381 2.30133 9.85297 2.44105ZM4.56567 5.03431C4.87809 5.34673 4.87809 5.85326 4.56567 6.16568L2.73136 8L4.56567 9.83431C4.87809 10.1467 4.87809 10.6533 4.56567 10.9657C4.25325 11.2781 3.74672 11.2781 3.4343 10.9657L1.0343 8.56568C0.721883 8.25326 0.721883 7.74673 1.0343 7.43431L3.4343 5.03431C3.74672 4.72189 4.25325 4.72189 4.56567 5.03431ZM11.4343 5.03431C11.7467 4.72189 12.2533 4.72189 12.5657 5.03431L14.9657 7.43431C15.2781 7.74673 15.2781 8.25326 14.9657 8.56568L12.5657 10.9657C12.2533 11.2781 11.7467 11.2781 11.4343 10.9657C11.1219 10.6533 11.1219 10.1467 11.4343 9.83431L13.2686 8L11.4343 6.16568C11.1219 5.85326 11.1219 5.34673 11.4343 5.03431Z" fill="#172D32"/>
</g>
</svg>

<svg
width={width}
height={height}
viewBox="0 0 16 16"
fill={fill}
xmlns="http://www.w3.org/2000/svg"
>
<g id="Icon/Solid/code">
<path
id="Icon"
fill-rule="evenodd"
clip-rule="evenodd"
d="M9.85297 2.44105C10.2721 2.58077 10.4987 3.03382 10.3589 3.45298L7.15893 13.053C7.01922 13.4721 6.56616 13.6987 6.14701 13.5589C5.72785 13.4192 5.50132 12.9662 5.64104 12.547L8.84104 2.94702C8.98076 2.52786 9.43381 2.30133 9.85297 2.44105ZM4.56567 5.03431C4.87809 5.34673 4.87809 5.85326 4.56567 6.16568L2.73136 8L4.56567 9.83431C4.87809 10.1467 4.87809 10.6533 4.56567 10.9657C4.25325 11.2781 3.74672 11.2781 3.4343 10.9657L1.0343 8.56568C0.721883 8.25326 0.721883 7.74673 1.0343 7.43431L3.4343 5.03431C3.74672 4.72189 4.25325 4.72189 4.56567 5.03431ZM11.4343 5.03431C11.7467 4.72189 12.2533 4.72189 12.5657 5.03431L14.9657 7.43431C15.2781 7.74673 15.2781 8.25326 14.9657 8.56568L12.5657 10.9657C12.2533 11.2781 11.7467 11.2781 11.4343 10.9657C11.1219 10.6533 11.1219 10.1467 11.4343 9.83431L13.2686 8L11.4343 6.16568C11.1219 5.85326 11.1219 5.34673 11.4343 5.03431Z"
fill="#172D32"
/>
</g>
</svg>
),
'sidebar-collapse': ({ fill, width, height, onClick = () => {} }: IconProp) => (
<svg width={width || 20} height={height || 20} viewBox="0 0 20 20" fill={fill} xmlns="http://www.w3.org/2000/svg">
<g id="Icon/Solid/Sidebar-Collapse">
<g id="Vector">
<path d="M6.177 9.823L8.573 7.427C8.60796 7.39195 8.65255 7.36806 8.7011 7.35838C8.74966 7.3487 8.79999 7.35365 8.84573 7.37261C8.89147 7.39157 8.93055 7.42368 8.95801 7.46487C8.98547 7.50607 9.00009 7.55449 9 7.604V12.396C9.00009 12.4455 8.98547 12.4939 8.95801 12.5351C8.93055 12.5763 8.89147 12.6084 8.84573 12.6274C8.79999 12.6464 8.74966 12.6513 8.7011 12.6416C8.65255 12.6319 8.60796 12.6081 8.573 12.573L6.177 10.177C6.15372 10.1538 6.13525 10.1262 6.12264 10.0958C6.11004 10.0654 6.10355 10.0329 6.10355 10C6.10355 9.96712 6.11004 9.93456 6.12264 9.90418C6.13525 9.87381 6.15372 9.84622 6.177 9.823Z" fill="#172D32"/>
<path d="M2 3.75C2 2.784 2.784 2 3.75 2H16.25C17.216 2 18 2.784 18 3.75V16.25C18 16.7141 17.8156 17.1592 17.4874 17.4874C17.1592 17.8156 16.7141 18 16.25 18H3.75C3.28587 18 2.84075 17.8156 2.51256 17.4874C2.18437 17.1592 2 16.7141 2 16.25V3.75ZM3.75 3.5C3.6837 3.5 3.62011 3.52634 3.57322 3.57322C3.52634 3.62011 3.5 3.6837 3.5 3.75V16.25C3.5 16.388 3.612 16.5 3.75 16.5H11.5V3.5H3.75ZM16.25 16.5C16.3163 16.5 16.3799 16.4737 16.4268 16.4268C16.4737 16.3799 16.5 16.3163 16.5 16.25V3.75C16.5 3.6837 16.4737 3.62011 16.4268 3.57322C16.3799 3.52634 16.3163 3.5 16.25 3.5H13V16.5H16.25Z" fill="#172D32"/>
</g>
<svg
width={width || 20}
height={height || 20}
viewBox="0 0 20 20"
fill={fill}
xmlns="http://www.w3.org/2000/svg"
>
<g id="Icon/Solid/Sidebar-Collapse">
<g id="Vector">
<path
d="M6.177 9.823L8.573 7.427C8.60796 7.39195 8.65255 7.36806 8.7011 7.35838C8.74966 7.3487 8.79999 7.35365 8.84573 7.37261C8.89147 7.39157 8.93055 7.42368 8.95801 7.46487C8.98547 7.50607 9.00009 7.55449 9 7.604V12.396C9.00009 12.4455 8.98547 12.4939 8.95801 12.5351C8.93055 12.5763 8.89147 12.6084 8.84573 12.6274C8.79999 12.6464 8.74966 12.6513 8.7011 12.6416C8.65255 12.6319 8.60796 12.6081 8.573 12.573L6.177 10.177C6.15372 10.1538 6.13525 10.1262 6.12264 10.0958C6.11004 10.0654 6.10355 10.0329 6.10355 10C6.10355 9.96712 6.11004 9.93456 6.12264 9.90418C6.13525 9.87381 6.15372 9.84622 6.177 9.823Z"
fill="#172D32"
/>
<path
d="M2 3.75C2 2.784 2.784 2 3.75 2H16.25C17.216 2 18 2.784 18 3.75V16.25C18 16.7141 17.8156 17.1592 17.4874 17.4874C17.1592 17.8156 16.7141 18 16.25 18H3.75C3.28587 18 2.84075 17.8156 2.51256 17.4874C2.18437 17.1592 2 16.7141 2 16.25V3.75ZM3.75 3.5C3.6837 3.5 3.62011 3.52634 3.57322 3.57322C3.52634 3.62011 3.5 3.6837 3.5 3.75V16.25C3.5 16.388 3.612 16.5 3.75 16.5H11.5V3.5H3.75ZM16.25 16.5C16.3163 16.5 16.3799 16.4737 16.4268 16.4268C16.4737 16.3799 16.5 16.3163 16.5 16.25V3.75C16.5 3.6837 16.4737 3.62011 16.4268 3.57322C16.3799 3.52634 16.3163 3.5 16.25 3.5H13V16.5H16.25Z"
fill="#172D32"
/>
</g>
</svg>
),
</g>
</svg>
)
};

export type IconType = keyof typeof icons;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Meta, StoryFn } from '@storybook/react';
import React from 'react';
import {
ControlledDisplayFiltersGroup,
ControlledDisplayFiltersGroupProps
} from '../../../components';

const meta: Meta<ControlledDisplayFiltersGroupProps> = {
title: 'Elements/Display filter group',
component: ControlledDisplayFiltersGroup
};

export default meta;

const Template: StoryFn<typeof ControlledDisplayFiltersGroup> = (args) => (
<ControlledDisplayFiltersGroup {...args} />
);

export const ControlledDisplayFilterBasic: StoryFn<typeof ControlledDisplayFiltersGroup> =
Template.bind({});
ControlledDisplayFilterBasic.args = {
filters: [
{
label: 'test label1',
onChange: (value) => console.log('changed', value),
value: false
},
{
label: 'test label2',
onChange: (value) => console.log('changed', value),
value: false
},
{
label: 'test label3 ',
onChange: (value) => console.log('changed', value),
value: false
}
],
onFilterChange: (value) => console.log('show all', value),
toggleShowAll: (value) => console.log('toggle show all', value),
label: 'Grouped display filters example',
};
18 changes: 18 additions & 0 deletions src/stories/elements/displayFilter/DisplayFilter.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DisplayFilter, DisplayFilterProps } from '../../../components';
import { Meta, StoryFn } from '@storybook/react';
import React from 'react';

const meta: Meta<DisplayFilterProps> = {
title: 'Elements/Display filter',
component: DisplayFilter
};

export default meta;

const Template: StoryFn<typeof DisplayFilter> = (args) => <DisplayFilter {...args} />;

export const DisplayFilterBasic: StoryFn<typeof DisplayFilter> = Template.bind({});
DisplayFilterBasic.args = {
label: 'test label',
onChange: () => console.log('changed')
};
2 changes: 1 addition & 1 deletion src/stories/elements/dropdownV2/dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Meta, StoryFn } from '@storybook/react';
import {DropdownV2} from '../../../components';
import { DropdownV2 } from '../../../components';
import { RadioButtonItemProps } from '../../../components';

const meta: Meta<typeof DropdownV2> = {
Expand Down

0 comments on commit a79da1b

Please sign in to comment.