Skip to content

Commit

Permalink
feat(multi-select): add selected preview
Browse files Browse the repository at this point in the history
  • Loading branch information
Daryl-L committed Aug 2, 2024
1 parent 613f78e commit eac325e
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 82 deletions.
4 changes: 3 additions & 1 deletion src/components/FilterSortContainer/index.module.scss
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
.filterSortContainerOnMobile {
display: flex;
flex-wrap: wrap;
flex-wrap: nowrap;
justify-content: space-between;
gap: 20px;

ul {
max-width: 100%;
display: flex;
flex-wrap: wrap;
margin: 0;

li {
width: 50%;
list-style-type: none;
text-wrap: nowrap;

&:nth-child(odd) {
text-align: left;
Expand Down
141 changes: 81 additions & 60 deletions src/components/MultiFilterButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Link, useLocation } from 'react-router-dom'
import { Popover } from 'antd'
import { useTranslation } from 'react-i18next'
import { useEffect, useState } from 'react'
import { ReactComponent as FilterIcon } from '../../assets/filter_icon.svg'
import { ReactComponent as SelectedIcon } from '../../assets/selected-icon.svg'
import { ReactComponent as NotSelectedIcon } from '../../assets/not-selected-icon.svg'
Expand All @@ -17,81 +18,101 @@ export function MultiFilterButton({
filterList: { key: string; value: string; to: string; title: string | JSX.Element }[]
isMobile?: boolean
}) {
const [selected, setSelected] = useState<string>('')
const { t } = useTranslation()
const params = useSearchParams(filterName)
const filter = params[filterName]
const types = filter?.split(',').filter(t => !!t) ?? []

useEffect(() => {
const filterMap = new Map<string, string>(filterList.map(f => [f.key, f.value]))
setSelected(
types
.map(item => filterMap.get(item))
.filter(item => item)
.join(','),
)
}, [filter])

const isAllSelected = types.length === filterList.length
const isNoneSelected = types.length === 0
const search = new URLSearchParams(useLocation().search)
search.delete(filterName)
search.delete('page')

return (
<Popover
className={styles.container}
placement="bottomRight"
trigger={isMobile ? 'click' : 'hover'}
overlayClassName={styles.antPopover}
content={
<div className={styles.filterItems}>
<div className={styles.selectTitle}>
<h2>{t('components.multi_filter_button.select')}</h2>
<Link
key="all"
to={() => {
const newSearch = new URLSearchParams(search)
if (isNoneSelected) {
newSearch.append(filterName, filterList.map(f => f.value).join(','))
}
<div className={styles.container}>
{!!selected && (
<div className={styles.selected}>
<span className={styles.selectedItems}>{selected}</span>
<span>+{types.length}</span>
</div>
)}
<Popover
placement="bottomRight"
trigger={isMobile ? 'click' : 'hover'}
overlayClassName={styles.antPopover}
content={
<div className={styles.filterItems}>
<div className={styles.selectTitle}>
<h2>{t('components.multi_filter_button.select')}</h2>
<Link
key="all"
to={() => {
const newSearch = new URLSearchParams(search)
if (isNoneSelected) {
newSearch.append(filterName, filterList.map(f => f.key).join(','))
}

return `${filterList[0].to}?${newSearch.toString()}`
}}
>
{types.length > 0 ? (
<>{isAllSelected ? <SelectedIcon /> : <PartialSelectedIcon />}</>
) : (
<NotSelectedIcon />
)}
</Link>
</div>
{filterList.map(f => (
<Link
key={f.key}
to={() => {
const subTypes = new Set(types)
if (subTypes.has(f.value)) {
subTypes.delete(f.value)
} else {
subTypes.add(f.value)
}
return `${filterList[0].to}?${newSearch.toString()}`
}}
>
{types.length > 0 ? (
<>{isAllSelected ? <SelectedIcon /> : <PartialSelectedIcon />}</>
) : (
<NotSelectedIcon />
)}
</Link>
</div>
{filterList.map(f => (
<Link
key={f.key}
to={() => {
const subTypes = new Set(types)
if (subTypes.has(f.key)) {
subTypes.delete(f.key)
} else {
subTypes.add(f.key)
}

const newSearch = new URLSearchParams(search)
if (subTypes.size === 0) {
newSearch.delete(filterName)
} else {
newSearch.append(filterName, Array.from(subTypes).join(','))
}
return `${f.to}?${newSearch.toString()}`
}}
data-is-active={types.includes(f.value)}
>
{f.title}
{types.includes(f.value) ? <SelectedIcon /> : <NotSelectedIcon />}
</Link>
))}
const newSearch = new URLSearchParams(search)
if (subTypes.size === 0) {
newSearch.delete(filterName)
} else {
newSearch.append(filterName, Array.from(subTypes).join(','))
}
return `${f.to}?${newSearch.toString()}`
}}
data-is-active={types.includes(f.key)}
>
{f.title}
{types.includes(f.key) ? <SelectedIcon /> : <NotSelectedIcon />}
</Link>
))}
</div>
}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<FilterIcon
className={styles.filter}
// if the filter is the empty string, display highlight
// if the filter is the string list, display highlight
// if the filter is undefined, not display highlight
data-changed={filter !== undefined}
/>
</div>
}
>
<FilterIcon
className={styles.filter}
// if the filter is the empty string, display highlight
// if the filter is the string list, display highlight
// if the filter is undefined, not display highlight
data-changed={filter !== undefined}
/>
</Popover>
</Popover>
</div>
)
}

Expand Down
33 changes: 31 additions & 2 deletions src/components/MultiFilterButton/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
border: none;
outline: none;
background: none;
display: inline-flex;
vertical-align: text-top;
gap: 4px;
cursor: pointer;
width: 70%;
display: flex;
align-items: center;
}

.antPopover {
Expand All @@ -31,6 +33,33 @@
}
}

.selected {
border-radius: 48px;
border: 1px solid var(--primary-dimmed-color);
background: var(--secondary-color);
display: flex;
padding: 4px 8px;
align-items: flex-start;
align-content: flex-start;
gap: 4px;
flex-wrap: nowrap;
margin-left: 4px;
color: var(--primary-color);
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: normal;
align-self: center;
max-width: 85%;

.selectedItems {
max-width: 95%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}

.filterItems {
display: flex;
flex-direction: column;
Expand Down
16 changes: 8 additions & 8 deletions src/pages/NftCollections/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,43 +49,43 @@ function useFilterList(): Record<'title' | 'value', string>[] {
const filterList = [
{
key: 'invalid',
value: 'invalid',
value: 'Invalid',
title: <NFTTag key="invalid" tagName="invalid" />,
to: '/nft-collections',
},
{
key: 'suspicious',
value: 'suspicious',
value: 'Suspicious',
title: <NFTTag key="suspicious" tagName="suspicious" />,
to: '/nft-collections',
},
{
key: 'out-of-length-range',
value: 'out-of-length-range',
value: 'Out Of Length Range',
title: <NFTTag key="out-of-length-range" tagName="out-of-length-range" />,
to: '/nft-collections',
},
{
key: 'rgb++',
value: 'rgb++',
value: 'RGB++',
title: <NFTTag key="rgb++" tagName="rgb++" />,
to: '/nft-collections',
},
{
key: 'duplicate',
value: 'duplicate',
value: 'Duplicate',
title: <NFTTag key="duplicate" tagName="duplicate" />,
to: '/nft-collections',
},
{
key: 'layer-1-asset',
value: 'layer-1-asset',
value: 'Layer 1 Asset',
title: <NFTTag key="layer-1-asset" tagName="layer-1-asset" />,
to: '/nft-collections',
},
{
key: 'layer-2-asset',
value: 'layer-2-asset',
value: 'Layer 2 Asset',
title: <NFTTag key="layer-2-asset" tagName="layer-2-asset" />,
to: '/nft-collections',
},
Expand Down Expand Up @@ -361,7 +361,7 @@ export const ListOnMobile: React.FC<{ isLoading: boolean; list: NFTCollection[]
<SimpleSortHeader sortField="transactions" fieldI18n={t('nft.transactions')} />
<HolderMinterSort />
<SimpleSortHeader sortField="timestamp" fieldI18n={t('nft.created_time')} />
<div>
<div style={{ display: 'flex', flexWrap: 'nowrap', maxWidth: '100%' }}>
{t('xudt.title.tags')}
<MultiFilterButton filterName="tags" key="" filterList={filterList} />
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/pages/NftCollections/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@
}

.colTags {
max-width: 100%;
width: 100%;
display: flex;
flex-wrap: wrap;
flex-wrap: nowrap;
align-items: center;
}

Expand Down
20 changes: 10 additions & 10 deletions src/pages/Xudts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,19 @@ const filterList = [
// },
{
key: 'layer-1-asset',
value: 'layer-1-asset',
value: 'Layer 1 Asset',
title: <XUDTTag tagName="layer-1-asset" />,
to: '/xudts',
},
{
key: 'layer-2-asset',
value: 'layer-2-asset',
value: 'Layer 2 Asset',
title: <XUDTTag tagName="layer-2-asset" />,
to: '/xudts',
},
{
key: 'supply-limited',
value: 'supply-limited',
value: 'Supply Limited',
title: <XUDTTag tagName="supply-limited" />,
to: '/xudts',
},
Expand Down Expand Up @@ -134,20 +134,20 @@ export function TokensCard({
<Card className={styles.filterSortCard} shadow={false}>
<FilterSortContainerOnMobile key="xudts-sort">
<span className={styles.sortOption}>
{t('xudt.transactions')}
<SortButton field="transactions" sortParam={sortParam} />
{t('xudt.title.tags')}
<MultiFilterButton filterName="tags" key="" filterList={filterList} />
</span>
<span className={styles.sortOption}>
{t('xudt.unique_addresses')}
<SortButton field="addresses_count" sortParam={sortParam} />
{t('xudt.transactions')}
<SortButton field="transactions" sortParam={sortParam} />
</span>
<span className={styles.sortOption}>
{t('xudt.created_time')}
<SortButton field="created_time" sortParam={sortParam} />
</span>
<span className={styles.sortOption}>
{t('xudt.title.tags')}
<MultiFilterButton filterName="tags" key="" filterList={filterList} />
{t('xudt.unique_addresses')}
<SortButton field="addresses_count" sortParam={sortParam} />
</span>
</FilterSortContainerOnMobile>
</Card>
Expand Down Expand Up @@ -247,7 +247,7 @@ const TokenTable: FC<{
{
title: (
<>
{t('xudt.unique_addresses')}
<span>{t('xudt.unique_addresses')}</span>
<SortButton field="addresses_count" sortParam={sortParam} />
</>
),
Expand Down
9 changes: 9 additions & 0 deletions src/pages/Xudts/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ dt {
}

.colTags {
display: flex;
align-items: center;

.tags {
flex-wrap: wrap;
display: flex;
Expand Down Expand Up @@ -316,7 +319,13 @@ dt {
}

.colAddressCount {
display: flex;
min-width: 170px;
flex-wrap: nowrap;

span {
white-space: nowrap;
}
}

.colCreatedTime {
Expand Down

0 comments on commit eac325e

Please sign in to comment.