diff --git a/src/locales/en.json b/src/locales/en.json
index 9313a0b1b..b28d14216 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -417,7 +417,16 @@
"leap_out_tip": "This RGB++ transaction is marked as \"L2 → L1\", indicating that the number of cells with RGB++ lock in the input exceeds the number of cells with RGB++ lock in the output.",
"view_in_btc_explorer": "View in Bitcoin Explorer",
"view-as-asset-items": "View Asset Distribution",
- "view-as-merged-assets": "View Asset Amounts(CKB excluded)"
+ "view-as-merged-assets": "View Asset Amounts(CKB excluded)",
+ "block-height": "Block Height",
+ "out-point": "OutPoint",
+ "capacity": "Capacity(CKB)",
+ "type": "Type",
+ "amount": "Amount",
+ "detail": "Detail",
+ "asset": "Asset",
+ "view-asset": "View Asset",
+ "cell-info": "Cell Info"
},
"rgbpp": {
"transaction": {
@@ -895,7 +904,9 @@
},
"sort": {
"time": "Sort by time",
- "capacity": "Sort by capacity"
+ "capacity": "Sort by capacity",
+ "card": "Show as card view",
+ "list": "Show as list view"
},
"decoder": {
"view-data-as": "View data as",
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 5464d7c65..2bfd6d163 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -417,7 +417,16 @@
"leap_out_tip": "本笔 RGB++ 交易被标记为\"L2 → L1\",即存在 RGB++ 资产转化为一般 CKB 资产。",
"view_in_btc_explorer": "在 Bitcoin 浏览器查看",
"view-as-asset-items": "查看资产分布",
- "view-as-merged-assets": "查看资产合计(不含 CKB)"
+ "view-as-merged-assets": "查看资产合计(不含 CKB)",
+ "block-height": "区块高度",
+ "out-point": "OutPoint",
+ "capacity": "Capacity",
+ "type": "类型",
+ "amount": "数量",
+ "detail": "详情",
+ "asset": "资产",
+ "view-asset": "查看资产",
+ "cell-info": "Cell详情"
},
"rgbpp": {
"transaction": {
@@ -896,7 +905,9 @@
},
"sort": {
"time": "按时间排序",
- "capacity": "按 Capacity 排序"
+ "capacity": "按 Capacity 排序",
+ "card": "按卡片样式展示",
+ "list": "按列表样式展示"
},
"decoder": {
"view-data-as": "选择解码格式",
diff --git a/src/pages/Address/AddressComp.tsx b/src/pages/Address/AddressComp.tsx
index 11d5953f2..f9df1f4a5 100644
--- a/src/pages/Address/AddressComp.tsx
+++ b/src/pages/Address/AddressComp.tsx
@@ -47,15 +47,8 @@ import { Address, UDTAccount } from '../../models/Address'
import { Card, CardCellInfo, CardCellsLayout } from '../../components/Card'
import { CardHeader } from '../../components/Card/CardHeader'
import Cells from './Cells'
-import {
- AddressCoTAComp,
- AddressOmigaInscriptionComp,
- AddressMNFTComp,
- AddressSporeComp,
- AddressSudtComp,
- AddressXudtComp,
- AddressNRC721Comp,
-} from './AddressAssetComp'
+import DefinedTokens from './DefinedTokens'
+import { AddressOmigaInscriptionComp } from './AddressAssetComp'
enum AssetInfo {
UDT = 1,
@@ -255,41 +248,7 @@ export const AddressOverviewCard: FC<{ address: Address }> = ({ address }) => {
key={AssetInfo.UDT}
>
- {udts.map(udt => {
- switch (udt.udtType) {
- case 'xudt':
- return
-
- case 'sudt':
- return
-
- case 'spore_cell':
- return
-
- case 'm_nft_token':
- return
-
- case 'nrc_721_token':
- return
-
- default:
- return null
- }
- })}
- {cotaList?.map(cota => (
-
- )) ?? null}
+
)}
diff --git a/src/pages/Address/Cells.tsx b/src/pages/Address/Cells.tsx
index 872c56ddd..fe355e9a6 100644
--- a/src/pages/Address/Cells.tsx
+++ b/src/pages/Address/Cells.tsx
@@ -1,12 +1,11 @@
import { type FC, useState, useRef, useEffect } from 'react'
-import { useTranslation } from 'react-i18next'
+import { TFunction, useTranslation } from 'react-i18next'
import BigNumber from 'bignumber.js'
import { useInfiniteQuery } from '@tanstack/react-query'
import { Tooltip } from 'antd'
import { explorerService, LiveCell } from '../../services/ExplorerService'
import SUDTTokenIcon from '../../assets/sudt_token.png'
import CKBTokenIcon from './ckb_token_icon.png'
-import { ReactComponent as CopyIcon } from './copy.svg'
import { ReactComponent as TypeHashIcon } from './type_script.svg'
import { ReactComponent as DataIcon } from './data.svg'
import { ReactComponent as SporeCluterIcon } from './spore_cluster.svg'
@@ -18,10 +17,11 @@ import { ReactComponent as ListIcon } from './list.svg'
import { ReactComponent as GridIcon } from './grid.svg'
import { parseUDTAmount } from '../../utils/number'
import { shannonToCkb } from '../../utils/util'
-import { useSetToast } from '../../components/Toast'
-import { PAGE_SIZE } from '../../constants/common'
+import { parseSimpleDateNoSecond } from '../../utils/date'
import styles from './cells.module.scss'
import SmallLoading from '../../components/Loading/SmallLoading'
+import { TransactionCellInfo } from '../Transaction/TransactionCell'
+import { CellBasicInfo } from '../../utils/transformer'
import { sliceNftName } from '../../utils/string'
enum Sort {
@@ -53,31 +53,13 @@ const initialPageParams = { size: 10, sort: 'capacity.desc' }
const ATTRIBUTE_LENGTH = 18
-const Cell: FC<{ cell: LiveCell }> = ({ cell }) => {
- const setToast = useSetToast()
- const { t } = useTranslation()
-
- const handleCopy = (e: React.MouseEvent) => {
- e.stopPropagation()
- e.preventDefault()
- const { detail } = e.currentTarget.dataset
- if (!detail) return
- navigator.clipboard.writeText(detail).then(() => {
- setToast({ message: t('common.copied') })
- })
- }
-
+const getCellDetails = (cell: LiveCell, t: TFunction) => {
const ckb = new BigNumber(shannonToCkb(+cell.capacity)).toFormat()
- const title = `${cell.txHash.slice(0, 8)}...${cell.txHash.slice(-8)}#${cell.cellIndex}`
- const link = `/transaction/${cell.txHash}?${new URLSearchParams({
- page_of_outputs: Math.ceil((+cell.cellIndex + 1) / PAGE_SIZE).toString(),
- })}`
const assetType: string = cell.extraInfo?.type ?? cell.cellType
let icon: string | React.ReactElement | null = null
let assetName = null
let attribute = null
let detailInfo = null
-
switch (assetType) {
case 'ckb': {
if (cell.typeHash) {
@@ -183,44 +165,105 @@ const Cell: FC<{ cell: LiveCell }> = ({ cell }) => {
attribute = '-'
}
}
- const outPoint = {
- tx_hash: cell.txHash,
- index: `0x${cell.cellIndex.toString(16)}`,
+
+ const outPointStr = `${cell.txHash.slice(0, 8)}...${cell.txHash.slice(-8)}#${cell.cellIndex}`
+ const parsedBlockCreateAt = parseSimpleDateNoSecond(cell.blockTimestamp)
+ const title = `${cell.cellId}: ${ckb} `
+ const cellInfo = {
+ ...cell,
+ id: Number(cell.cellId),
+ isGenesisOutput: Number(cell.blockNumber) === 0,
+ } as CellBasicInfo
+
+ return {
+ ckb,
+ outPointStr,
+ icon,
+ assetName,
+ attribute,
+ detailInfo,
+ title,
+ parsedBlockCreateAt,
+ cellInfo,
}
+}
+
+const Cell: FC<{ cell: LiveCell }> = ({ cell }) => {
+ const { t } = useTranslation()
+
+ const { title, parsedBlockCreateAt, icon, assetName, attribute, detailInfo, cellInfo } = getCellDetails(cell, t)
return (
-
- {title}
+
+
+
+ {title}
+ CKB ({parsedBlockCreateAt})
+
+
-
- {`${ckb} CKB`}
-
-
- {typeof icon === 'string' ?
![{assetName]({icon})
: null}
- {icon && typeof icon !== 'string' ? icon : null}
-
-
{assetName}
-
-
{attribute}
- {detailInfo ? (
-
- ) : null}
+
+ {typeof icon === 'string' ?
![{assetName]({icon})
: null}
+ {icon && typeof icon !== 'string' ? icon : null}
+
+
{assetName}
+
+ {attribute}
+
-
+
)
}
+const CellTable: FC<{ cells: LiveCell[] }> = ({ cells }) => {
+ const { t } = useTranslation()
+ const headers = getTableHeaders(t)
+
+ return (
+
+
+
+
+ {headers.map(header => (
+ {header.title} |
+ ))}
+
+
+
+ {cells.map((cell, index) => {
+ const { ckb, outPointStr, assetName, attribute, cellInfo } = getCellDetails(cell, t)
+
+ return (
+
+ {index + 1} |
+ {cell.blockNumber} |
+ {outPointStr} |
+ {ckb} |
+ {cell.extraInfo?.type} |
+
+ {attribute} {attribute === 'Unknown amount' ? '' : assetName}
+ |
+
+
+ {t('address.detail')}
+
+ |
+
+ )
+ })}
+
+
+
+ )
+}
+
const Cells: FC<{ address: string; count: number }> = ({ address, count }) => {
const { t } = useTranslation()
const [params, setParams] = useState(initialPageParams)
- const [isDisplayedAsList, setIsDisplayedAsList] = useState(true)
+ const [isDisplayedAsList, setIsDisplayedAsList] = useState(false)
const loadMoreRef = useRef
(null)
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery(
@@ -279,9 +322,6 @@ const Cells: FC<{ address: string; count: number }> = ({ address, count }) => {
data-sort={params.sort === Sort.TimeAsc ? Sort.TimeDesc : Sort.TimeAsc}
onClick={handleSortChange}
data-is-active={params.sort === Sort.TimeAsc || params.sort === Sort.TimeDesc}
- style={{
- display: 'none', // FIXME: wait for api fix
- }}
>
{params.sort === Sort.TimeAsc ? : }
@@ -296,35 +336,56 @@ const Cells: FC<{ address: string; count: number }> = ({ address, count }) => {
-
+
+
+
-
- {cells.map(cell => (
- |
- ))}
-
- {isFetchingNextPage ? (
-
-
-
- ) : null}
- {!hasNextPage || isFetchingNextPage ? null : (
-
-
-
- )}
+
+
+ {isDisplayedAsList ? (
+
+ ) : (
+
+ {cells.map(cell => (
+ |
+ ))}
+
+ )}
+
+ {isFetchingNextPage ? (
+
+
+
+ ) : null}
+ {!hasNextPage || isFetchingNextPage ? null : (
+
+
+
+ )}
+
)
}
export default Cells
+
+const getTableHeaders = (t: TFunction): TableHeader[] => {
+ return [
+ { title: '#', key: 'index' },
+ { title: t('address.block-height'), key: 'block-number' },
+ { title: t('address.out-point'), key: 'out-point' },
+ { title: t('address.capacity'), key: 'capacity' },
+ { title: t('address.type'), key: 'type' },
+ { title: t('address.amount'), key: 'amount' },
+ { title: '', key: 'action' },
+ ]
+}
+
+interface TableHeader {
+ title: string
+ key: string
+}
diff --git a/src/pages/Address/DefinedTokens.tsx b/src/pages/Address/DefinedTokens.tsx
new file mode 100644
index 000000000..51e2f3d82
--- /dev/null
+++ b/src/pages/Address/DefinedTokens.tsx
@@ -0,0 +1,195 @@
+import { type FC, useState, useMemo } from 'react'
+import { TFunction, useTranslation } from 'react-i18next'
+import { Tooltip } from 'antd'
+import { ReactComponent as ListIcon } from './list.svg'
+import { ReactComponent as GridIcon } from './grid.svg'
+import { parseUDTAmount } from '../../utils/number'
+import { formatNftDisplayId } from '../../utils/util'
+import styles from './definedTokens.module.scss'
+import { sliceNftName } from '../../utils/string'
+import { NFTItem } from '../../services/ExplorerService/fetcher'
+import { UDTAccount } from '../../models/Address'
+import {
+ AddressCoTAComp,
+ AddressMNFTComp,
+ AddressSporeComp,
+ AddressSudtComp,
+ AddressXudtComp,
+ AddressNRC721Comp,
+} from './AddressAssetComp'
+
+const TokenTable: FC<{ udts: UDTAccount[]; cotaList: NFTItem[] }> = ({ udts, cotaList }) => {
+ const { t } = useTranslation()
+ const headers = getTableHeaders(t)
+
+ return (
+
+
+
+
+ {headers.map(header => (
+ {header.title} |
+ ))}
+
+
+
+ {udts.map((udt, index) => {
+ let type = ''
+ let key = udt.symbol + udt.udtType
+ let href = ''
+ let asset = ''
+ let amount = ''
+ switch (udt.udtType) {
+ case 'xudt':
+ type = 'xUDT'
+ key += udt.amount
+ href = `/xudt/${udt.typeHash}`
+ asset = udt.uan || udt.symbol
+ amount = `${parseUDTAmount(udt.amount, udt.decimal)} ${asset}`
+ break
+ case 'sudt':
+ type = 'sUDT'
+ key += udt.amount
+ href = `/sudt/${udt.typeHash}`
+ asset = udt.uan || udt.symbol
+ amount = `${parseUDTAmount(udt.amount, udt.decimal)} ${asset}`
+ break
+ case 'spore_cell':
+ type = 'DOB'
+ key += udt.amount
+ href = `/nft-collections/${udt.collection?.typeHash}`
+ asset = sliceNftName(udt.symbol) || ''
+ // eslint-disable-next-line no-case-declarations
+ const id = formatNftDisplayId(udt.amount, 'spore')
+ amount = `id: ${id.slice(0, 8)}...${id.slice(-8)}`
+ break
+ case 'm_nft_token':
+ type = 'm-NFT'
+ key += udt.amount
+ href = `/nft-collections/${udt.collection?.typeHash}`
+ asset = sliceNftName(udt.symbol) || ''
+ amount = `#${udt.amount}`
+ break
+ case 'nrc_721_token':
+ type = 'NRC 721'
+ key += udt.amount
+ href = `/nft-collections/${udt.collection?.typeHash}`
+ asset = !udt.symbol ? '?' : sliceNftName(`${udt.symbol} #${udt.collection.typeHash.slice(2, 5)}`) || ''
+ amount = `id: ${udt.amount.slice(0, 5)}...${udt.amount.slice(-4)}`
+ break
+ default:
+ break
+ }
+
+ return (
+
+ {index + 1} |
+ {type} |
+ {asset || '/'} |
+ {amount} |
+
+ {t('address.view-asset')}
+ |
+
+ )
+ })}
+ {cotaList.map((cota, index) => {
+ return (
+
+ {udts.length + index + 1} |
+ CoTA |
+ {sliceNftName(cota.collection.name)} |
+ {`#${Number(cota.token_id)}`} |
+
+ {t('address.view-asset')}
+ |
+
+ )
+ })}
+
+
+
+ )
+}
+
+const DefinedTokens: FC<{ udts: UDTAccount[]; cotaList?: NFTItem[] }> = ({ udts, cotaList = [] }) => {
+ const { t } = useTranslation()
+ const [isDisplayedAsList, setIsDisplayedAsList] = useState(false)
+
+ const count = useMemo(() => udts.length + cotaList.length, [udts, cotaList])
+
+ return (
+
+
+
Count: {count.toLocaleString('en')}
+
+
+
+
+
+
+
+
+ {isDisplayedAsList ? (
+
+ ) : (
+
+ {udts.map(udt => {
+ switch (udt.udtType) {
+ case 'xudt':
+ return
+
+ case 'sudt':
+ return
+
+ case 'spore_cell':
+ return
+
+ case 'm_nft_token':
+ return
+
+ case 'nrc_721_token':
+ return
+
+ default:
+ return null
+ }
+ })}
+ {cotaList?.map(cota => (
+
+ )) ?? null}
+
+ )}
+
+
+ )
+}
+export default DefinedTokens
+
+const getTableHeaders = (t: TFunction): TableHeader[] => {
+ return [
+ { title: '#', key: 'index' },
+ { title: t('address.type'), key: 'type' },
+ { title: t('address.asset'), key: 'asset' },
+ { title: t('address.amount'), key: 'amount' },
+ { title: '', key: 'action' },
+ ]
+}
+
+interface TableHeader {
+ title: string
+ key: string
+}
diff --git a/src/pages/Address/RgbppAssets.tsx b/src/pages/Address/RgbppAssets.tsx
index 213d6f25e..6add7a4c3 100644
--- a/src/pages/Address/RgbppAssets.tsx
+++ b/src/pages/Address/RgbppAssets.tsx
@@ -1,8 +1,10 @@
import { type FC, useState, useRef, useEffect } from 'react'
-import { useTranslation } from 'react-i18next'
+import { TFunction, useTranslation } from 'react-i18next'
import BigNumber from 'bignumber.js'
import { useInfiniteQuery } from '@tanstack/react-query'
import { Tooltip } from 'antd'
+import { ReactComponent as ListIcon } from './list.svg'
+import { ReactComponent as GridIcon } from './grid.svg'
import { explorerService, LiveCell } from '../../services/ExplorerService'
import SUDTTokenIcon from '../../assets/sudt_token.png'
import CKBTokenIcon from './ckb_token_icon.png'
@@ -14,6 +16,7 @@ import { ReactComponent as SporeCellIcon } from './spore_cell.svg'
import { ReactComponent as MergedAssetIcon } from './merged_assets.svg'
import { ReactComponent as AssetItemsIcon } from './asset_items.svg'
import SmallLoading from '../../components/Loading/SmallLoading'
+import { TransactionCellInfo } from '../Transaction/TransactionCell'
import { parseUDTAmount } from '../../utils/number'
import { getContractHashTag, shannonToCkb } from '../../utils/util'
import { useSetToast } from '../../components/Toast'
@@ -21,6 +24,7 @@ import { PAGE_SIZE } from '../../constants/common'
import styles from './rgbppAssets.module.scss'
import MergedAssetList from './MergedAssetList'
import { UDTAccount } from '../../models/Address'
+import { CellBasicInfo } from '../../utils/transformer'
const fetchCells = async ({
address,
@@ -44,20 +48,7 @@ const initialPageParams = { size: 10, sort: 'capacity.desc' }
const ATTRIBUTE_LENGTH = 18
-const AssetItem: FC<{ cell: LiveCell }> = ({ cell }) => {
- const setToast = useSetToast()
- const { t } = useTranslation()
-
- const handleCopy = (e: React.MouseEvent) => {
- e.stopPropagation()
- e.preventDefault()
- const { detail } = e.currentTarget.dataset
- if (!detail) return
- navigator.clipboard.writeText(detail).then(() => {
- setToast({ message: t('common.copied') })
- })
- }
-
+const getCellDetails = (cell: LiveCell, t: TFunction) => {
const ckb = new BigNumber(shannonToCkb(+cell.capacity)).toFormat()
const link = `/transaction/${cell.txHash}?${new URLSearchParams({
page_of_outputs: Math.ceil((+cell.cellIndex + 1) / PAGE_SIZE).toString(),
@@ -68,6 +59,8 @@ const AssetItem: FC<{ cell: LiveCell }> = ({ cell }) => {
let attribute = null
let detailInfo = null
+ const utxo = `${cell.txHash.slice(0, 4)}...${cell.txHash.slice(-3)}:${cell.cellIndex}`
+
switch (assetType) {
case 'ckb': {
if (cell.typeHash) {
@@ -172,6 +165,41 @@ const AssetItem: FC<{ cell: LiveCell }> = ({ cell }) => {
}
}
+ const cellInfo = {
+ ...cell,
+ id: Number(cell.cellId),
+ isGenesisOutput: false,
+ } as CellBasicInfo
+
+ return {
+ link,
+ assetType,
+ ckb,
+ detailInfo,
+ icon,
+ assetName,
+ attribute,
+ cellInfo,
+ utxo,
+ }
+}
+
+const AssetItem: FC<{ cell: LiveCell }> = ({ cell }) => {
+ const setToast = useSetToast()
+ const { t } = useTranslation()
+
+ const handleCopy = (e: React.MouseEvent) => {
+ e.stopPropagation()
+ e.preventDefault()
+ const { detail } = e.currentTarget.dataset
+ if (!detail) return
+ navigator.clipboard.writeText(detail).then(() => {
+ setToast({ message: t('common.copied') })
+ })
+ }
+
+ const { link, assetType, ckb, detailInfo, icon, assetName, attribute } = getCellDetails(cell, t)
+
return (
= ({ cell }) => {
{`${ckb} CKB`}
-
+
{typeof icon === 'string' ?
![{assetName]({icon})
: null}
{icon && typeof icon !== 'string' ? icon : null}
@@ -203,7 +231,54 @@ const AssetItem: FC<{ cell: LiveCell }> = ({ cell }) => {
)
}
-const RgbAssetItems: FC<{ address: string; count: number }> = ({ address, count }) => {
+const CellTable: FC<{ cells: LiveCell[] }> = ({ cells }) => {
+ const { t } = useTranslation()
+ const headers = getTableHeaders(t)
+
+ return (
+
+
+
+
+ {headers.map(header => (
+ {header.title} |
+ ))}
+
+
+
+ {cells.map((cell, index) => {
+ const { utxo, link, assetType, ckb, assetName, attribute, cellInfo } = getCellDetails(cell, t)
+ return (
+
+ {index + 1} |
+
+ {utxo}
+ |
+ {assetType} |
+ {assetName} |
+
+ {attribute} {assetName}
+ |
+ {ckb} |
+
+
+ {t('address.cell-info')}
+
+ |
+
+ )
+ })}
+
+
+
+ )
+}
+
+const RgbAssetItems: FC<{ address: string; count: number; isDisplayedAsList: boolean }> = ({
+ address,
+ count,
+ isDisplayedAsList,
+}) => {
const [params] = useState(initialPageParams)
const loadMoreRef = useRef
(null)
@@ -260,11 +335,15 @@ const RgbAssetItems: FC<{ address: string; count: number }> = ({ address, count
return (
<>
-
- {cells.map(cell => (
-
- ))}
-
+ {isDisplayedAsList ? (
+
+ ) : (
+
+ {cells.map(cell => (
+
+ ))}
+
+ )}
{isFetchingNextPage ? (
@@ -289,6 +368,7 @@ const RgbAssets: FC<{ address: string; count: number; udts: UDTAccount[]; inscri
}) => {
const [isMerged, setIsMerged] = useState(true)
const { t } = useTranslation()
+ const [isDisplayedAsList, setIsDisplayedAsList] = useState(false)
return (
@@ -296,19 +376,62 @@ const RgbAssets: FC<{ address: string; count: number; udts: UDTAccount[]; inscri
{t(`address.${isMerged ? 'view-as-merged-assets' : 'view-as-asset-items'}`)}
-
+
+ {
+ setIsDisplayedAsList(i => !i)
+ setIsMerged(false)
+ }}
+ >
+ {isDisplayedAsList ? : }
+
+
- {isMerged ? (
-
- ) : (
-
- )}
+
+
+ {isDisplayedAsList ? (
+
+ ) : (
+ <>
+ {isMerged ? (
+
+ ) : (
+
+ )}
+ >
+ )}
+
)
}
export default RgbAssets
+
+const getTableHeaders = (t: TFunction): TableHeader[] => {
+ return [
+ { title: '#', key: 'index' },
+ { title: 'UTXO', key: 'utxo' },
+ { title: t('address.type'), key: 'type' },
+ { title: t('address.asset'), key: 'asset' },
+ { title: t('address.amount'), key: 'amount' },
+ { title: t('address.capacity'), key: 'capacity' },
+ { title: '', key: 'action' },
+ ]
+}
+
+interface TableHeader {
+ title: string
+ key: string
+}
diff --git a/src/pages/Address/cells.module.scss b/src/pages/Address/cells.module.scss
index fac4d70ce..72b115119 100644
--- a/src/pages/Address/cells.module.scss
+++ b/src/pages/Address/cells.module.scss
@@ -1,3 +1,5 @@
+@import '../../styles/variables.module';
+
.container {
width: 100%;
overflow: scroll;
@@ -49,6 +51,18 @@
}
}
+ .content {
+ overflow-x: scroll;
+
+ @media (width >= $extraLargeBreakPoint) {
+ max-height: 220px;
+ }
+
+ @media (width <= $extraLargeBreakPoint) {
+ max-height: 310px;
+ }
+ }
+
ul {
list-style: none;
padding: 0;
@@ -66,50 +80,26 @@
h5 {
display: flex;
- justify-content: space-between;
align-items: center;
background: var(--primary-color);
color: #fff;
height: 1.875rem;
padding: 8px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- a {
- &:hover {
- font-weight: bold;
- color: #fff;
- text-decoration: underline;
+ span {
+ &:first-child {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
- }
-
- .copy {
- appearance: none;
- border: none;
- background: none;
- width: 14px;
- cursor: pointer;
- margin-right: 8px;
- height: 14px;
- svg {
- pointer-events: none;
- height: 14px;
+ &:last-child {
+ flex-shrink: 0;
}
}
-
- span {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- cursor: default;
- flex: 1;
- text-align: right;
- }
}
- .content {
+ .cellContent {
padding: 8px;
display: flex;
line-height: 1;
@@ -160,6 +150,47 @@
}
}
+.tableContainer {
+ table {
+ width: 100%;
+ background: #fff;
+ border: 1px solid #e5e5e5;
+
+ thead tr th {
+ background: #fff;
+ position: sticky;
+ top: -1px;
+ }
+
+ th,
+ td {
+ border: 1px solid #e5e5e5;
+ text-align: center;
+ padding: 0 24px;
+ font-size: 14px;
+ color: #333;
+ }
+
+ th {
+ height: 40px;
+ }
+
+ td {
+ height: 48px;
+ }
+ }
+}
+
+.detail {
+ text-decoration: underline;
+ cursor: pointer;
+ color: #666;
+
+ &:hover {
+ color: var(--primary-color);
+ }
+}
+
.loading {
display: flex;
justify-content: center;
diff --git a/src/pages/Address/definedTokens.module.scss b/src/pages/Address/definedTokens.module.scss
new file mode 100644
index 000000000..1c5a31c58
--- /dev/null
+++ b/src/pages/Address/definedTokens.module.scss
@@ -0,0 +1,108 @@
+@import '../../styles/variables.module';
+
+.container {
+ width: 100%;
+ overflow: scroll;
+
+ .toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+
+ .filters {
+ display: flex;
+ align-items: center;
+ gap: 24px;
+
+ button {
+ width: 20px;
+ height: 20px;
+ appearance: none;
+ border: none;
+ cursor: pointer;
+ color: #999;
+
+ &:hover {
+ color: var(--primary-color);
+ }
+
+ svg {
+ pointer-events: none;
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .capacitySortIcon {
+ &[data-current-sort='capacity.asc'] {
+ path:last-of-type {
+ fill: var(--primary-color);
+ }
+ }
+
+ &[data-current-sort='capacity.desc'] {
+ path:first-of-type {
+ fill: var(--primary-color);
+ }
+ }
+ }
+ }
+ }
+
+ .content {
+ overflow-x: scroll;
+
+ @media (width >= $extraLargeBreakPoint) {
+ max-height: 220px;
+ }
+
+ @media (width <= $extraLargeBreakPoint) {
+ max-height: 310px;
+ }
+ }
+
+ ul {
+ list-style: none;
+ padding: 0;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
+ gap: 1rem;
+ }
+}
+
+.tableContainer {
+ table {
+ width: 100%;
+ background: #fff;
+ border: 1px solid #e5e5e5;
+
+ thead tr th {
+ background: #fff;
+ position: sticky;
+ top: -1px;
+ }
+
+ th,
+ td {
+ border: 1px solid #e5e5e5;
+ text-align: center;
+ padding: 0 24px;
+ font-size: 14px;
+ color: #333;
+ }
+
+ th {
+ height: 40px;
+ }
+
+ td {
+ height: 48px;
+ }
+ }
+
+ a {
+ text-decoration: underline;
+ }
+}
diff --git a/src/pages/Address/rgbppAssets.module.scss b/src/pages/Address/rgbppAssets.module.scss
index 961d1c3d6..a1d3ecd57 100644
--- a/src/pages/Address/rgbppAssets.module.scss
+++ b/src/pages/Address/rgbppAssets.module.scss
@@ -1,3 +1,5 @@
+@import '../../styles/variables.module';
+
.container {
width: 100%;
overflow: scroll;
@@ -49,6 +51,18 @@
}
}
+ .content {
+ overflow-x: scroll;
+
+ @media (width >= $extraLargeBreakPoint) {
+ max-height: 220px;
+ }
+
+ @media (width <= $extraLargeBreakPoint) {
+ max-height: 310px;
+ }
+ }
+
ul {
list-style: none;
padding: 0;
@@ -110,7 +124,7 @@
}
}
- .content {
+ .itemContent {
padding: 8px;
display: flex;
line-height: 1;
@@ -155,6 +169,46 @@
}
}
+.tableContainer {
+ table {
+ width: 100%;
+ background: #fff;
+ border: 1px solid #e5e5e5;
+
+ thead tr th {
+ background: #fff;
+ position: sticky;
+ top: -1px;
+ }
+
+ th,
+ td {
+ border: 1px solid #e5e5e5;
+ text-align: center;
+ padding: 0 24px;
+ font-size: 14px;
+ color: #333;
+ }
+
+ th {
+ height: 40px;
+ }
+
+ td {
+ height: 48px;
+ }
+ }
+
+ .cellInfo {
+ text-decoration: underline;
+ cursor: pointer;
+
+ &:hover {
+ color: var(--primary-color);
+ }
+ }
+}
+
.loading {
display: flex;
justify-content: center;
diff --git a/src/pages/Address/styles.module.scss b/src/pages/Address/styles.module.scss
index 59317476a..b43d82631 100644
--- a/src/pages/Address/styles.module.scss
+++ b/src/pages/Address/styles.module.scss
@@ -285,17 +285,9 @@
margin-top: 10px;
background-color: #f1f1f1;
padding: 6px 25px;
+ border-radius: 4px;
width: 100%;
display: flex;
flex-flow: row wrap;
- overflow-y: scroll;
gap: 1rem;
-
- @media (width >= $extraLargeBreakPoint) {
- max-height: 220px;
- }
-
- @media (width <= $extraLargeBreakPoint) {
- max-height: 310px;
- }
}
diff --git a/src/pages/Transaction/TransactionCell/index.tsx b/src/pages/Transaction/TransactionCell/index.tsx
index 1d6e9f4d7..28fe1226e 100644
--- a/src/pages/Transaction/TransactionCell/index.tsx
+++ b/src/pages/Transaction/TransactionCell/index.tsx
@@ -43,6 +43,7 @@ import { useDASAccount } from '../../../hooks/useDASAccount'
import styles from './styles.module.scss'
import AddressText from '../../../components/AddressText'
import { Cell } from '../../../models/Cell'
+import { CellBasicInfo } from '../../../utils/transformer'
export const Addr: FC<{ address: string; isCellBase: boolean }> = ({ address, isCellBase }) => {
const alias = useDASAccount(address)
@@ -171,7 +172,7 @@ const useParseNftInfo = (cell: Cell) => {
}
}
-const TransactionCellDetail = ({ cell }: { cell: Cell }) => {
+export const TransactionCellDetail = ({ cell }: { cell: Cell }) => {
const { t } = useTranslation()
let detailTitle = t('transaction.ckb_capacity')
let detailIcon
@@ -266,12 +267,20 @@ const TransactionCellDetail = ({ cell }: { cell: Cell }) => {
)
}
-const TransactionCellInfo = ({ cell, children }: { cell: Cell; children: string | ReactNode }) => {
+export const TransactionCellInfo = ({
+ cell,
+ children,
+ isDefaultStyle = true,
+}: {
+ cell: CellBasicInfo
+ children: string | ReactNode
+ isDefaultStyle?: boolean
+}) => {
const [showModal, setShowModal] = useState(false)
return (
{
setShowModal(true)
}}
@@ -279,6 +288,7 @@ const TransactionCellInfo = ({ cell, children }: { cell: Cell; children: string
{children}
+
setShowModal(false)} />
diff --git a/src/services/ExplorerService/fetcher.ts b/src/services/ExplorerService/fetcher.ts
index 46b853505..2ebc1171c 100644
--- a/src/services/ExplorerService/fetcher.ts
+++ b/src/services/ExplorerService/fetcher.ts
@@ -49,7 +49,7 @@ const v1GetUnwrappedPagedList = (...args: Parameters) =>
v1Get[]>(...args).then(res => {
assert(res.meta, 'Unexpected paged list response')
return {
- data: res.data.map(wrapper => wrapper.attributes),
+ data: res.data.map(wrapper => ({ ...wrapper.attributes, cellId: wrapper.id })),
...res.meta,
}
})
diff --git a/src/services/ExplorerService/types.ts b/src/services/ExplorerService/types.ts
index 403a2f54f..1a9e2c68b 100644
--- a/src/services/ExplorerService/types.ts
+++ b/src/services/ExplorerService/types.ts
@@ -349,6 +349,7 @@ export interface Script {
}
export interface LiveCell {
+ cellId: string
cellType: string
txHash: string
cellIndex: number