From c33e859dd53f117aa420e26d09490b5fe5bd9c91 Mon Sep 17 00:00:00 2001 From: daryl Date: Mon, 24 Jun 2024 22:11:54 +0800 Subject: [PATCH] feat(xudt): add filter to filter tags --- src/assets/not-selected-icon.svg | 3 + src/assets/partial-selected-icon.svg | 11 +++ src/assets/selected-icon.svg | 5 ++ src/components/MultiFilterButton/index.tsx | 66 +++++++++++++++ .../MultiFilterButton/styles.module.scss | 71 ++++++++++++++++ src/components/XUDTTag/index.tsx | 2 +- src/locales/en.json | 27 ++++--- src/locales/zh.json | 27 ++++--- src/pages/Xudts/index.tsx | 81 ++++++++++++++++++- 9 files changed, 267 insertions(+), 26 deletions(-) create mode 100644 src/assets/not-selected-icon.svg create mode 100644 src/assets/partial-selected-icon.svg create mode 100644 src/assets/selected-icon.svg create mode 100644 src/components/MultiFilterButton/index.tsx create mode 100644 src/components/MultiFilterButton/styles.module.scss diff --git a/src/assets/not-selected-icon.svg b/src/assets/not-selected-icon.svg new file mode 100644 index 000000000..e53ea5dbb --- /dev/null +++ b/src/assets/not-selected-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/partial-selected-icon.svg b/src/assets/partial-selected-icon.svg new file mode 100644 index 000000000..0dcf2c1b2 --- /dev/null +++ b/src/assets/partial-selected-icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/selected-icon.svg b/src/assets/selected-icon.svg new file mode 100644 index 000000000..8e402f4c3 --- /dev/null +++ b/src/assets/selected-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/MultiFilterButton/index.tsx b/src/components/MultiFilterButton/index.tsx new file mode 100644 index 000000000..b6ed0c47e --- /dev/null +++ b/src/components/MultiFilterButton/index.tsx @@ -0,0 +1,66 @@ +import { Link } from 'react-router-dom' +import { Popover } from 'antd' +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' +import { ReactComponent as PartialSelectedIcon } from '../../assets/partial-selected-icon.svg' +import { useSearchParams } from '../../hooks' +import styles from './styles.module.scss' + +export function MultiFilterButton({ + filteredList, + isMobile, + filterName, +}: { + filterName: string + filteredList: { key: string; value: string; to: string; title: string | JSX.Element }[] + isMobile?: boolean +}) { + const params = useSearchParams('tags') + const types = params.tags?.split(',').filter(t => t !== '') ?? [] + + return ( + +
+

Select

+ {types.length > 0 ? ( + <>{types.length === filteredList.length ? : } + ) : ( + + )} +
+ {filteredList.map(f => ( + { + let subTypes = types.map(t => t) + if (subTypes.includes(f.value)) { + subTypes = subTypes.filter(t => t !== f.value) + } else { + subTypes.push(f.value) + } + return `${f.to}?${filterName}=${subTypes.slice().join(',')}` + }} + data-is-active={types.includes(f.value)} + > + {f.title} + {types.includes(f.value) ? : } + + ))} + + } + > + +
+ ) +} + +MultiFilterButton.displayName = 'MultiFilterButton' + +export default MultiFilterButton diff --git a/src/components/MultiFilterButton/styles.module.scss b/src/components/MultiFilterButton/styles.module.scss new file mode 100644 index 000000000..bdb54e698 --- /dev/null +++ b/src/components/MultiFilterButton/styles.module.scss @@ -0,0 +1,71 @@ +.container { + appearance: none; + border: none; + outline: none; + background: none; + display: inline-flex; + vertical-align: text-top; + margin-left: 8px; + cursor: pointer; +} + +.antPopover { + :global { + /* stylelint-disable-next-line selector-class-pattern */ + .ant-popover-inner { + border-radius: 8px; + box-shadow: 0 2px 10px 0 #eee; + } + + /* stylelint-disable-next-line selector-class-pattern */ + .ant-popover-inner-content { + padding: 14px 24px 14px 16px; + } + } +} + +.filter { + margin-left: 8px; + color: #999; +} + +.filterItems { + display: flex; + flex-direction: column; + width: 200px; + + .selectTitle { + color: var(--primary-color); + + h2 { + color: #333; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: normal; + } + + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; + border-radius: 8px; + } + + a { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; + border-radius: 8px; + + svg { + color: var(--primary-color); + } + + &:hover { + background: var(--primary-hover-bg-color); + cursor: pointer; + } + } +} diff --git a/src/components/XUDTTag/index.tsx b/src/components/XUDTTag/index.tsx index 42adec757..1acbb7fca 100644 --- a/src/components/XUDTTag/index.tsx +++ b/src/components/XUDTTag/index.tsx @@ -8,7 +8,7 @@ const XUDTTag = ({ tagName }: { tagName: string }) => { const { push } = useHistory() let tag = tagName - let content = t(`xudt.${tag}`) + let content = t(`xudt.tags.${tag}`) if (tag.startsWith('verified-on-')) { // FIXME: should be i18n content = content.replace('Platform', tag.replace('verified-on-', '')) diff --git a/src/locales/en.json b/src/locales/en.json index 11c01a493..82362f03a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -741,6 +741,9 @@ "repeat_inscription_symbol": "This inscription is a duplicate with an earlier release of the same symbol." }, "xudt": { + "title": { + "tags": "Tags" + }, "holder_allocation": "Holder Allocation", "holder_allocation_description": "There are {{ckb}} CKB Holder addresses and {{btc}} BTC holder addresses of the current asset.", "lock_hash": "Lock Hash", @@ -762,17 +765,19 @@ "address_count": "Address Count", "created_time": "Created Time", "tokens_empty": "There are no xUDTs at this time.", - "invalid": "Invalid", - "suspicious": "Suspicious", - "out-of-length-range": "Out Of Length Range", - "duplicate": "Duplicate", - "layer-1-asset": "Layer 1 Asset", - "layer-2-asset": "Layer 2 Asset", - "verified-on": "Verified On Platform", - "supply-limited": "Supply Limited", - "supply-unlimited": "Supply Unlimited", - "rgbpp-compatible": "RGB++ Compatible", - "category": "Category" + "tags": { + "invalid": "Invalid", + "suspicious": "Suspicious", + "out-of-length-range": "Out Of Length Range", + "duplicate": "Duplicate", + "layer-1-asset": "Layer 1 Asset", + "layer-2-asset": "Layer 2 Asset", + "verified-on": "Verified On Platform", + "supply-limited": "Supply Limited", + "supply-unlimited": "Supply Unlimited", + "rgbpp-compatible": "RGB++ Compatible", + "category": "Category" + } }, "nft": { "nft_collection": "NFT Collection", diff --git a/src/locales/zh.json b/src/locales/zh.json index 79108a1b4..dc8950a32 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -742,6 +742,9 @@ "repeat_inscription_symbol": "此铭文与早期发布的铭文同名" }, "xudt": { + "title": { + "tags": "标签" + }, "holder_allocation": "地址分布", "holder_allocation_description": "当前资产有 {{ckb}} 个 CKB 用户地址及 {{btc}} 个 BTC 用户地址", "lock_hash": "Lock Hash", @@ -763,17 +766,19 @@ "address_count": "用户数", "created_time": "创建时间", "tokens_empty": "目前没有 xUDT。", - "invalid": "无效", - "suspicious": "可疑", - "out-of-length-range": "超长", - "duplicate": "重复", - "layer-1-asset": "Layer 1 资产", - "layer-2-asset": "Layer 2 资产", - "verified-on": "Platform 平台认证", - "supply-limited": "有限供应资产", - "supply-unlimited": "无限供应资产", - "rgbpp-compatible": "RGB++兼容", - "category": "类别" + "tags": { + "invalid": "无效", + "suspicious": "可疑", + "out-of-length-range": "超长", + "duplicate": "重复", + "layer-1-asset": "Layer 1 资产", + "layer-2-asset": "Layer 2 资产", + "verified-on": "Platform 平台认证", + "supply-limited": "有限供应资产", + "supply-unlimited": "无限供应资产", + "rgbpp-compatible": "RGB++兼容", + "category": "类别" + } }, "nft": { "nft_collection": "NFT 藏品", diff --git a/src/pages/Xudts/index.tsx b/src/pages/Xudts/index.tsx index 53689acb9..e5a4557ce 100644 --- a/src/pages/Xudts/index.tsx +++ b/src/pages/Xudts/index.tsx @@ -9,7 +9,7 @@ import { Link } from '../../components/Link' import Content from '../../components/Content' import Pagination from '../../components/Pagination' import SortButton from '../../components/SortButton' -import FilterButton from '../../components/FilterButton' +import MultiFilterButton from '../../components/MultiFilterButton' import { TokensPanel, TokensContentEmpty, TokensLoadingPanel } from './styled' import { localeNumberString } from '../../utils/number' import Loading from '../../components/Loading' @@ -116,6 +116,10 @@ export function TokensCard({ {t('xudt.created_time')} + + {t('xudt.title.tags')} + + @@ -140,6 +144,77 @@ export function TokensCard({ ) } +const getFilterList = (): { key: string; value: string; to: string; title: string | JSX.Element }[] => { + return [ + { + key: 'invalid', + value: 'invalid', + title: , + to: '', + }, + { + key: 'suspicious', + value: 'suspicious', + title: , + to: '', + }, + { + key: 'out-of-length-range', + value: 'out-of-length-range', + title: , + to: '', + }, + { + key: 'duplicate', + value: 'duplicate', + title: , + to: '', + }, + { + key: 'layer-1-asset', + value: 'layer-1-asset', + title: , + to: '', + }, + { + key: 'layer-2-asset', + value: 'layer-2-asset', + title: , + to: '', + }, + { + key: 'verified-on', + value: 'verified-on', + title: , + to: '', + }, + { + key: 'supply-limited', + value: 'supply-limited', + title: , + to: '', + }, + { + key: 'supply-unlimited', + value: 'supply-unlimited', + title: , + to: '', + }, + { + key: 'rgbpp-compatible', + value: 'rgbpp-compatible', + title: , + to: '', + }, + { + key: 'category', + value: 'category', + title: , + to: '', + }, + ] +} + const TokenTable: FC<{ query: UseQueryResult< { @@ -183,8 +258,8 @@ const TokenTable: FC<{ { title: ( <> - {t('xudt.tags')} - + {t('xudt.title.tags')} + ), className: styles.colTags,