mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
token page
This commit is contained in:
+17
-11
@@ -10,37 +10,41 @@ NEXT_PUBLIC_APP_ENV=development
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
|
||||
|
||||
# Instance ENVs
|
||||
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "728301", "width": "728", "height": "90" }
|
||||
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "728302", "width": "320", "height": "100" }
|
||||
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER=adbutler
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_HOST=base.blockscout.com
|
||||
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
|
||||
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
|
||||
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'aerodrome'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
|
||||
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'rubic'},{'text':'Disperse','icon':'txn_batches_slim','dappId':'smol'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
|
||||
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
|
||||
NEXT_PUBLIC_FAULT_PROOF_ENABLED=true
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/base-mainnet.json
|
||||
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/base-mainnet.json
|
||||
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
|
||||
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&disableBridges=true', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xfd5c5dae7b69fe29e61d19b9943e688aa0f1be1e983c4fba8fe985f90ff69d5f
|
||||
NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS=true
|
||||
NEXT_PUBLIC_HAS_USER_OPS=true
|
||||
NEXT_PUBLIC_HIDE_INDEXING_ALERT_INT_TXS=true
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
|
||||
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
|
||||
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)']}
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
NEXT_PUBLIC_LOGOUT_URL=https://basechain.us.auth0.com/v2/logout
|
||||
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maxaleks/0d18fc309ff499075127b364cc69306d/raw/2a51f961a8c1b9f884f2ab7eed79d4b69330e1ae/peanut_protocol_banner.html
|
||||
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://base.blockscout.com/apps/peanut-protocol
|
||||
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Joined recent campaigns? Mint your Merit Badge <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=base">here</a></p>
|
||||
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html
|
||||
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=base
|
||||
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
|
||||
NEXT_PUBLIC_MARKETPLACE_ENABLED=true
|
||||
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
|
||||
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
|
||||
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
|
||||
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
|
||||
NEXT_PUBLIC_METASUITES_ENABLED=true
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}]
|
||||
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
|
||||
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
|
||||
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/pools']
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
|
||||
@@ -59,8 +63,10 @@ NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://bridge.base.org/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-base.safe.global
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-base-mainnet.k8s-prod-1.blockscout.com
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-base-mainnet.k8s-prod-2.blockscout.com
|
||||
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
|
||||
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar
|
||||
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
|
||||
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'OpenSea','collection_url':'https://opensea.io/assets/base/{hash}','instance_url':'https://opensea.io/assets/base/{hash}/{id}','logo_url':'https://opensea.io/static/images/logos/opensea-logo.svg'}]
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
|
||||
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
|
||||
@@ -10,14 +10,14 @@ import fetchApi from 'nextjs/utils/fetchApi';
|
||||
|
||||
import config from 'configs/app';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
// import Token from 'ui/pages/Token';
|
||||
import Token from 'ui/pages/Token';
|
||||
|
||||
const pathname: Route['pathname'] = '/token/[hash]';
|
||||
|
||||
const Page: NextPage<Props<typeof pathname>> = (props: Props<typeof pathname>) => {
|
||||
return (
|
||||
<PageNextJs pathname={ pathname } query={ props.query } apiData={ props.apiData }>
|
||||
{ /* <Token/> */ }
|
||||
<Token/>
|
||||
</PageNextJs>
|
||||
);
|
||||
};
|
||||
|
||||
+5
-6
@@ -4,9 +4,9 @@ import { useRouter } from 'next/router';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import type { SocketMessage } from 'lib/socket/types';
|
||||
import type { TabItemRegular } from 'toolkit/components/AdaptiveTabs/types';
|
||||
import type { TokenInfo } from 'types/api/token';
|
||||
import type { PaginationParams } from 'ui/shared/pagination/types';
|
||||
import type { RoutedTab } from 'ui/shared/Tabs/types';
|
||||
|
||||
import config from 'configs/app';
|
||||
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
|
||||
@@ -20,6 +20,7 @@ import * as addressStubs from 'stubs/address';
|
||||
import * as tokenStubs from 'stubs/token';
|
||||
import { getTokenHoldersStub } from 'stubs/token';
|
||||
import { generateListStub } from 'stubs/utils';
|
||||
import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs';
|
||||
import AddressContract from 'ui/address/AddressContract';
|
||||
import AddressCsvExportLink from 'ui/address/AddressCsvExportLink';
|
||||
import useContractTabs from 'ui/address/contract/useContractTabs';
|
||||
@@ -28,7 +29,6 @@ import TextAd from 'ui/shared/ad/TextAd';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
import Pagination from 'ui/shared/pagination/Pagination';
|
||||
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
|
||||
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
|
||||
import TokenDetails from 'ui/token/TokenDetails';
|
||||
import TokenHolders from 'ui/token/TokenHolders/TokenHolders';
|
||||
import TokenInventory from 'ui/token/TokenInventory';
|
||||
@@ -161,7 +161,7 @@ const TokenPageContent = () => {
|
||||
const isLoading = tokenQuery.isPlaceholderData || addressQuery.isPlaceholderData;
|
||||
const contractTabs = useContractTabs(addressQuery.data, addressQuery.isPlaceholderData);
|
||||
|
||||
const tabs: Array<RoutedTab> = [
|
||||
const tabs: Array<TabItemRegular> = [
|
||||
hasInventoryTab ? {
|
||||
id: 'inventory',
|
||||
title: 'Inventory',
|
||||
@@ -212,7 +212,7 @@ const TokenPageContent = () => {
|
||||
pagination = inventoryQuery.pagination;
|
||||
}
|
||||
|
||||
const tabListProps = React.useCallback(({ isSticky, activeTabIndex }: { isSticky: boolean; activeTabIndex: number }) => {
|
||||
const tabListProps = React.useCallback(() => {
|
||||
if (isMobile) {
|
||||
return { mt: 8 };
|
||||
}
|
||||
@@ -221,7 +221,6 @@ const TokenPageContent = () => {
|
||||
pt: 6,
|
||||
pb: 6,
|
||||
marginBottom: 0,
|
||||
boxShadow: activeTabIndex === 2 && isSticky ? 'action_bar' : 'none',
|
||||
};
|
||||
}, [ isMobile ]);
|
||||
|
||||
@@ -257,7 +256,7 @@ const TokenPageContent = () => {
|
||||
|
||||
<RoutedTabs
|
||||
tabs={ tabs }
|
||||
tabListProps={ tabListProps }
|
||||
listProps={ tabListProps }
|
||||
rightSlot={ tabsRightSlot }
|
||||
rightSlotProps={ TABS_RIGHT_SLOT_PROPS }
|
||||
stickyEnabled={ !isMobile }
|
||||
|
||||
@@ -82,6 +82,7 @@ const EntityTag = ({ data, isLoading, noLink, ...rest }: Props) => {
|
||||
onClick={ handleLinkClick }
|
||||
noIcon
|
||||
cursor={ hasLink ? 'pointer' : 'default' }
|
||||
{ ...rest }
|
||||
>
|
||||
<Tag
|
||||
bg={ data.meta?.bgColor }
|
||||
@@ -92,7 +93,6 @@ const EntityTag = ({ data, isLoading, noLink, ...rest }: Props) => {
|
||||
endElementProps={ linkParams?.type === 'external' ? { ml: -1 } : undefined }
|
||||
_hover={ hasLink ? { opacity: 0.76 } : undefined }
|
||||
variant={ hasLink ? 'clickable' : 'subtle' }
|
||||
{ ...rest }
|
||||
>
|
||||
{ prefix }{ name }
|
||||
</Tag>
|
||||
|
||||
@@ -45,7 +45,7 @@ const EntityTags = ({ tags, className, isLoading }: Props) => {
|
||||
+{ tags.length - visibleNum }
|
||||
</Badge>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent maxW="300px">
|
||||
<PopoverContent maxW="300px" w="fit-content">
|
||||
<PopoverBody>
|
||||
<Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap">
|
||||
{ tags.slice(visibleNum).map((tag) => <EntityTag key={ tag.slug } data={ tag }/>) }
|
||||
|
||||
+18
-28
@@ -1,15 +1,10 @@
|
||||
import {
|
||||
PopoverTrigger, PopoverContent, PopoverBody,
|
||||
Modal, ModalContent, ModalCloseButton,
|
||||
useDisclosure,
|
||||
Button,
|
||||
} from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import Popover from 'ui/shared/chakra/Popover';
|
||||
|
||||
import IconSvg from './IconSvg';
|
||||
import { Button } from 'toolkit/chakra/button';
|
||||
import { DialogRoot, DialogContent, DialogTrigger, DialogHeader } from 'toolkit/chakra/dialog';
|
||||
import { PopoverBody, PopoverContent, PopoverRoot, PopoverTrigger } from 'toolkit/chakra/popover';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@@ -17,21 +12,16 @@ interface Props {
|
||||
|
||||
const InfoButton = ({ children }: Props) => {
|
||||
const isMobile = useIsMobile();
|
||||
const { isOpen, onToggle, onClose } = useDisclosure();
|
||||
|
||||
const triggerButton = (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
onClick={ onToggle }
|
||||
isActive={ isOpen }
|
||||
variant="dropdown"
|
||||
gap={ 0 }
|
||||
aria-label="Show info"
|
||||
fontWeight={ 500 }
|
||||
lineHeight={ 6 }
|
||||
pl={ 1 }
|
||||
pr={ isMobile ? 1 : 2 }
|
||||
h="32px"
|
||||
>
|
||||
<IconSvg name="info" boxSize={ 6 } mr={ isMobile ? 0 : 1 }/>
|
||||
{ !isMobile && <span>Info</span> }
|
||||
@@ -40,29 +30,29 @@ const InfoButton = ({ children }: Props) => {
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<>
|
||||
{ triggerButton }
|
||||
<Modal isOpen={ isOpen } onClose={ onClose } size="full">
|
||||
<ModalContent>
|
||||
<ModalCloseButton/>
|
||||
{ children }
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
<DialogRoot size="full">
|
||||
<DialogTrigger>
|
||||
{ triggerButton }
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader/>
|
||||
{ children }
|
||||
</DialogContent>
|
||||
</DialogRoot>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
|
||||
<PopoverRoot>
|
||||
<PopoverTrigger>
|
||||
{ triggerButton }
|
||||
</PopoverTrigger>
|
||||
<PopoverContent w="500px">
|
||||
<PopoverBody px={ 6 } py={ 5 }>
|
||||
<PopoverBody>
|
||||
{ children }
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</PopoverRoot>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Tooltip, Flex, useColorModeValue } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import { IconButton } from 'toolkit/chakra/icon-button';
|
||||
import { Tooltip } from 'toolkit/chakra/tooltip';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
|
||||
type Props = {
|
||||
@@ -8,22 +9,14 @@ type Props = {
|
||||
};
|
||||
|
||||
const ResetIconButton = ({ onClick }: Props) => {
|
||||
const resetTokenIconColor = useColorModeValue('blue.600', 'blue.300');
|
||||
const resetTokenIconHoverColor = useColorModeValue('blue.400', 'blue.200');
|
||||
|
||||
return (
|
||||
<Tooltip label="Reset filter">
|
||||
<Flex>
|
||||
<Tooltip content="Reset filter">
|
||||
<IconButton ml={ 1 } variant="link" onClick={ onClick }>
|
||||
<IconSvg
|
||||
name="cross"
|
||||
boxSize={ 5 }
|
||||
ml={ 1 }
|
||||
color={ resetTokenIconColor }
|
||||
cursor="pointer"
|
||||
_hover={{ color: resetTokenIconHoverColor }}
|
||||
onClick={ onClick }
|
||||
/>
|
||||
</Flex>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
+12
-13
@@ -1,4 +1,4 @@
|
||||
import { Box, Grid, Link } from '@chakra-ui/react';
|
||||
import { Box, Grid } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -14,10 +14,11 @@ import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
|
||||
import getCurrencyValue from 'lib/getCurrencyValue';
|
||||
import useIsMounted from 'lib/hooks/useIsMounted';
|
||||
import { TOKEN_COUNTERS } from 'stubs/token';
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import type { TokenTabs } from 'ui/pages/Token';
|
||||
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
|
||||
import useAppActionData from 'ui/shared/AppActionButton/useAppActionData';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
|
||||
import DetailedInfoSponsoredItem from 'ui/shared/DetailedInfo/DetailedInfoSponsoredItem';
|
||||
import TruncatedValue from 'ui/shared/TruncatedValue';
|
||||
@@ -65,11 +66,9 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
const tab: TokenTabs = item === 'token_holders_count' ? 'holders' : 'token_transfers';
|
||||
|
||||
return (
|
||||
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
|
||||
<Link onClick={ changeUrlAndScroll(tab) }>
|
||||
{ Number(itemValue).toLocaleString() }
|
||||
</Link>
|
||||
</Skeleton>
|
||||
<Link onClick={ changeUrlAndScroll(tab) } loading={ tokenCountersQuery.isPlaceholderData }>
|
||||
{ Number(itemValue).toLocaleString() }
|
||||
</Link>
|
||||
);
|
||||
}, [ tokenCountersQuery.data, tokenCountersQuery.isPlaceholderData, changeUrlAndScroll ]);
|
||||
|
||||
@@ -112,7 +111,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
Price
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block">
|
||||
<Skeleton loading={ tokenQuery.isPlaceholderData } display="inline-block">
|
||||
<span>{ `$${ Number(exchangeRate).toLocaleString(undefined, { minimumSignificantDigits: 4 }) }` }</span>
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -128,7 +127,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
Fully diluted market cap
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block">
|
||||
<Skeleton loading={ tokenQuery.isPlaceholderData } display="inline-block">
|
||||
<span>{ `$${ BigNumber(marketCap).toFormat() }` }</span>
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -146,7 +145,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
wordBreak="break-word"
|
||||
whiteSpace="pre-wrap"
|
||||
>
|
||||
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } w="100%" display="flex">
|
||||
<Skeleton loading={ tokenQuery.isPlaceholderData } w="100%" display="flex">
|
||||
<TruncatedValue value={ totalSupplyValue || '0' } maxW="80%" flexShrink={ 0 }/>
|
||||
<Box flexShrink={ 0 }> </Box>
|
||||
<TruncatedValue value={ symbol || '' }/>
|
||||
@@ -160,7 +159,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
Holders
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
|
||||
<Skeleton loading={ tokenCountersQuery.isPlaceholderData }>
|
||||
{ countersItem('token_holders_count') }
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -172,7 +171,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
Transfers
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
|
||||
<Skeleton loading={ tokenCountersQuery.isPlaceholderData }>
|
||||
{ countersItem('transfers_count') }
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
@@ -186,7 +185,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
|
||||
Decimals
|
||||
</DetailedInfo.ItemLabel>
|
||||
<DetailedInfo.ItemValue>
|
||||
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } minW={ 6 }>
|
||||
<Skeleton loading={ tokenQuery.isPlaceholderData } minW={ 6 }>
|
||||
{ decimals }
|
||||
</Skeleton>
|
||||
</DetailedInfo.ItemValue>
|
||||
|
||||
@@ -37,11 +37,13 @@ const TokenHoldersContent = ({ holdersQuery, token, shouldRender = true }: Props
|
||||
|
||||
const actionBar = isMobile && holdersQuery.pagination.isVisible && (
|
||||
<ActionBar mt={ -6 }>
|
||||
<AddressCsvExportLink
|
||||
address={ token?.address }
|
||||
params={{ type: 'holders' }}
|
||||
isLoading={ holdersQuery.pagination.isLoading }
|
||||
/>
|
||||
{ token && (
|
||||
<AddressCsvExportLink
|
||||
address={ token.address }
|
||||
params={{ type: 'holders' }}
|
||||
isLoading={ holdersQuery.pagination.isLoading }
|
||||
/>
|
||||
) }
|
||||
<Pagination ml="auto" { ...holdersQuery.pagination }/>
|
||||
</ActionBar>
|
||||
);
|
||||
@@ -54,7 +56,7 @@ const TokenHoldersContent = ({ holdersQuery, token, shouldRender = true }: Props
|
||||
<TokenHoldersTable
|
||||
data={ items }
|
||||
token={ token }
|
||||
top={ holdersQuery.pagination.isVisible ? TABS_HEIGHT : 0 }
|
||||
top={ TABS_HEIGHT }
|
||||
isLoading={ holdersQuery.isPlaceholderData }
|
||||
/>
|
||||
</Box>
|
||||
@@ -71,11 +73,12 @@ const TokenHoldersContent = ({ holdersQuery, token, shouldRender = true }: Props
|
||||
return (
|
||||
<DataListDisplay
|
||||
isError={ holdersQuery.isError }
|
||||
items={ holdersQuery.data?.items }
|
||||
itemsNum={ holdersQuery.data?.items.length }
|
||||
emptyText="There are no holders for this token."
|
||||
content={ content }
|
||||
actionBar={ actionBar }
|
||||
/>
|
||||
>
|
||||
{ content }
|
||||
</DataListDisplay>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
|
||||
import type { TokenHolder, TokenInfo } from 'types/api/token';
|
||||
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
|
||||
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
|
||||
import Utilization from 'ui/shared/Utilization/Utilization';
|
||||
@@ -33,7 +33,7 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
|
||||
<>
|
||||
<ListItemMobileGrid.Label isLoading={ isLoading }>ID#</ListItemMobileGrid.Label>
|
||||
<ListItemMobileGrid.Value>
|
||||
<Skeleton isLoaded={ !isLoading } display="inline-block">
|
||||
<Skeleton loading={ isLoading } display="inline-block">
|
||||
{ holder.token_id }
|
||||
</Skeleton>
|
||||
</ListItemMobileGrid.Value>
|
||||
@@ -42,7 +42,7 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
|
||||
|
||||
<ListItemMobileGrid.Label isLoading={ isLoading }>Quantity</ListItemMobileGrid.Label>
|
||||
<ListItemMobileGrid.Value>
|
||||
<Skeleton isLoaded={ !isLoading } display="inline-block">
|
||||
<Skeleton loading={ isLoading } display="inline-block">
|
||||
{ quantity }
|
||||
</Skeleton>
|
||||
</ListItemMobileGrid.Value>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Table, Tbody, Tr, Th } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TokenHolder, TokenInfo } from 'types/api/token';
|
||||
|
||||
import { default as Thead } from 'ui/shared/TheadSticky';
|
||||
import { TableBody, TableColumnHeader, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table';
|
||||
import TokenHoldersTableItem from 'ui/token/TokenHolders/TokenHoldersTableItem';
|
||||
|
||||
interface Props {
|
||||
@@ -15,21 +14,21 @@ interface Props {
|
||||
|
||||
const TokenHoldersTable = ({ data, token, top, isLoading }: Props) => {
|
||||
return (
|
||||
<Table layout="auto">
|
||||
<Thead top={ top }>
|
||||
<Tr>
|
||||
<Th>Holder</Th>
|
||||
{ (token.type === 'ERC-1155' || token.type === 'ERC-404') && <Th>ID#</Th> }
|
||||
<Th isNumeric>Quantity</Th>
|
||||
{ token.total_supply && token.type !== 'ERC-404' && <Th isNumeric width="175px">Percentage</Th> }
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<TableRoot tableLayout="auto">
|
||||
<TableHeaderSticky top={ top }>
|
||||
<TableRow>
|
||||
<TableColumnHeader>Holder</TableColumnHeader>
|
||||
{ (token.type === 'ERC-1155' || token.type === 'ERC-404') && <TableColumnHeader>ID#</TableColumnHeader> }
|
||||
<TableColumnHeader isNumeric>Quantity</TableColumnHeader>
|
||||
{ token.total_supply && token.type !== 'ERC-404' && <TableColumnHeader isNumeric width="175px">Percentage</TableColumnHeader> }
|
||||
</TableRow>
|
||||
</TableHeaderSticky>
|
||||
<TableBody>
|
||||
{ data.map((item, index) => (
|
||||
<TokenHoldersTableItem key={ item.address.hash + (isLoading ? index : '') } holder={ item } token={ token } isLoading={ isLoading }/>
|
||||
)) }
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableBody>
|
||||
</TableRoot>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Tr, Td } from '@chakra-ui/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import React from 'react';
|
||||
|
||||
import type { TokenHolder, TokenInfo } from 'types/api/token';
|
||||
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import { TableCell, TableRow } from 'toolkit/chakra/table';
|
||||
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
|
||||
import Utilization from 'ui/shared/Utilization/Utilization';
|
||||
|
||||
@@ -18,38 +18,38 @@ const TokenTransferTableItem = ({ holder, token, isLoading }: Props) => {
|
||||
const quantity = BigNumber(holder.value).div(BigNumber(10 ** Number(token.decimals))).toFormat();
|
||||
|
||||
return (
|
||||
<Tr>
|
||||
<Td verticalAlign="middle">
|
||||
<TableRow>
|
||||
<TableCell verticalAlign="middle">
|
||||
<AddressEntity
|
||||
address={ holder.address }
|
||||
isLoading={ isLoading }
|
||||
flexGrow={ 1 }
|
||||
fontWeight="700"
|
||||
/>
|
||||
</Td>
|
||||
</TableCell>
|
||||
{ (token.type === 'ERC-1155' || token.type === 'ERC-404') && 'token_id' in holder && (
|
||||
<Td verticalAlign="middle">
|
||||
<Skeleton isLoaded={ !isLoading } display="inline-block">
|
||||
<TableCell verticalAlign="middle">
|
||||
<Skeleton loading={ isLoading } display="inline-block">
|
||||
{ 'token_id' in holder && holder.token_id }
|
||||
</Skeleton>
|
||||
</Td>
|
||||
</TableCell>
|
||||
) }
|
||||
<Td verticalAlign="middle" isNumeric>
|
||||
<Skeleton isLoaded={ !isLoading } display="inline-block" wordBreak="break-word">
|
||||
<TableCell verticalAlign="middle" isNumeric>
|
||||
<Skeleton loading={ isLoading } display="inline-block" wordBreak="break-word">
|
||||
{ quantity }
|
||||
</Skeleton>
|
||||
</Td>
|
||||
</TableCell>
|
||||
{ token.total_supply && token.type !== 'ERC-404' && (
|
||||
<Td verticalAlign="middle" isNumeric>
|
||||
<TableCell verticalAlign="middle" isNumeric>
|
||||
<Utilization
|
||||
value={ BigNumber(holder.value).div(BigNumber(token.total_supply)).dp(4).toNumber() }
|
||||
colorScheme="green"
|
||||
display="inline-flex"
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
</Td>
|
||||
</TableCell>
|
||||
) }
|
||||
</Tr>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -88,15 +88,16 @@ const TokenInventory = ({ inventoryQuery, tokenQuery, ownerFilter, shouldRender
|
||||
return (
|
||||
<DataListDisplay
|
||||
isError={ inventoryQuery.isError }
|
||||
items={ items }
|
||||
itemsNum={ items?.length }
|
||||
emptyText="There are no tokens."
|
||||
filterProps={{
|
||||
hasActiveFilters: Boolean(ownerFilter),
|
||||
emptyFilteredText: 'No tokens found for the selected owner.',
|
||||
}}
|
||||
content={ content }
|
||||
actionBar={ actionBar }
|
||||
/>
|
||||
>
|
||||
{ content }
|
||||
</DataListDisplay>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Flex, Text, Link, useColorModeValue } from '@chakra-ui/react';
|
||||
import { Box, Flex, Text } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TokenInfo, TokenInstance } from 'types/api/token';
|
||||
@@ -6,9 +6,9 @@ import type { TokenInfo, TokenInstance } from 'types/api/token';
|
||||
import { route } from 'nextjs-routes';
|
||||
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
|
||||
import LinkInternal from 'ui/shared/links/LinkInternal';
|
||||
import NftMedia from 'ui/shared/nft/NftMedia';
|
||||
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
|
||||
|
||||
@@ -33,38 +33,37 @@ const TokenInventoryItem = ({ item, token, isLoading }: Props) => {
|
||||
<Box
|
||||
w={{ base: '100%', lg: '210px' }}
|
||||
border="1px solid"
|
||||
borderColor={ useColorModeValue('blackAlpha.100', 'whiteAlpha.200') }
|
||||
borderColor={{ _light: 'blackAlpha.100', _dark: 'whiteAlpha.200' }}
|
||||
borderRadius="12px"
|
||||
p="10px"
|
||||
fontSize="sm"
|
||||
textStyle="sm"
|
||||
fontWeight={ 500 }
|
||||
lineHeight="20px"
|
||||
>
|
||||
<Link href={ isLoading ? undefined : url }>
|
||||
<Link href={ isLoading ? undefined : url } display="inline">
|
||||
{ mediaElement }
|
||||
</Link>
|
||||
{ item.id && (
|
||||
<Flex mb={ 2 } ml={ 1 }>
|
||||
<Text whiteSpace="pre" variant="secondary">ID# </Text>
|
||||
<Text whiteSpace="pre" color="text.secondary">ID# </Text>
|
||||
<TruncatedTextTooltip label={ item.id }>
|
||||
<Skeleton isLoaded={ !isLoading } overflow="hidden">
|
||||
<LinkInternal
|
||||
<Skeleton loading={ isLoading } overflow="hidden">
|
||||
<Link
|
||||
overflow="hidden"
|
||||
textOverflow="ellipsis"
|
||||
whiteSpace="nowrap"
|
||||
display="block"
|
||||
isLoading={ isLoading }
|
||||
loading={ isLoading }
|
||||
href={ url }
|
||||
>
|
||||
{ item.id }
|
||||
</LinkInternal>
|
||||
</Link>
|
||||
</Skeleton>
|
||||
</TruncatedTextTooltip>
|
||||
</Flex>
|
||||
) }
|
||||
{ item.owner && (
|
||||
<Flex mb={ 2 } ml={ 1 }>
|
||||
<Text whiteSpace="pre" variant="secondary" mr={ 2 } lineHeight="24px">Owner</Text>
|
||||
<Text whiteSpace="pre" color="text.secondary" mr={ 2 } lineHeight="24px">Owner</Text>
|
||||
<AddressEntity
|
||||
address={ item.owner }
|
||||
isLoading={ isLoading }
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Image, Link, Tooltip } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { AddressMetadataTagFormatted } from 'types/client/addressMetadata';
|
||||
|
||||
import config from 'configs/app';
|
||||
import { Image } from 'toolkit/chakra/image';
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import { Tooltip } from 'toolkit/chakra/tooltip';
|
||||
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
|
||||
import TextSeparator from 'ui/shared/TextSeparator';
|
||||
|
||||
@@ -33,14 +35,14 @@ const TokenNftMarketplaces = ({ hash, id, isLoading, appActionData, source }: Pr
|
||||
<DetailedInfo.ItemValue
|
||||
py={ appActionData ? '1px' : '6px' }
|
||||
>
|
||||
<Skeleton isLoaded={ !isLoading } display="flex" columnGap={ 3 } flexWrap="wrap" alignItems="center">
|
||||
<Skeleton loading={ isLoading } display="flex" columnGap={ 3 } flexWrap="wrap" alignItems="center">
|
||||
{ config.UI.views.nft.marketplaces.map((item) => {
|
||||
|
||||
const hrefTemplate = id ? item.instance_url : item.collection_url;
|
||||
const href = hrefTemplate.replace('{id}', id || '').replace('{hash}', hash || '');
|
||||
|
||||
return (
|
||||
<Tooltip label={ `View on ${ item.name }` } key={ item.name }>
|
||||
<Tooltip content={ `View on ${ item.name }` } key={ item.name }>
|
||||
<Link href={ href } target="_blank">
|
||||
<Image
|
||||
src={ item.logo_url }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Flex, Tooltip, useToken } from '@chakra-ui/react';
|
||||
import { Flex, useToken } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { ResourceError } from 'lib/api/resources';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { useAppContext } from 'lib/contexts/app';
|
||||
import { getTokenTypeName } from 'lib/token/tokenTypes';
|
||||
import { Tooltip } from 'toolkit/chakra/tooltip';
|
||||
import AddressMetadataAlert from 'ui/address/details/AddressMetadataAlert';
|
||||
import AddressQrCode from 'ui/address/details/AddressQrCode';
|
||||
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
|
||||
@@ -66,8 +67,8 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
|
||||
};
|
||||
}, [ appProps.referrer ]);
|
||||
|
||||
const bridgedTokenTagBgColor = useToken('colors', 'blue.500');
|
||||
const bridgedTokenTagTextColor = useToken('colors', 'white');
|
||||
const [ bridgedTokenTagBgColor ] = useToken('colors', 'blue.500');
|
||||
const [ bridgedTokenTagTextColor ] = useToken('colors', 'white');
|
||||
|
||||
const tags: Array<EntityTag> = React.useMemo(() => {
|
||||
return [
|
||||
@@ -105,10 +106,8 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
|
||||
const contentAfter = (
|
||||
<>
|
||||
{ verifiedInfoQuery.data?.tokenAddress && (
|
||||
<Tooltip label={ `Information on this token has been verified by ${ config.chain.name }` }>
|
||||
<Box boxSize={ 6 }>
|
||||
<IconSvg name="certified" color="green.500" boxSize={ 6 } cursor="pointer"/>
|
||||
</Box>
|
||||
<Tooltip content={ `Information on this token has been verified by ${ config.chain.name }` }>
|
||||
<IconSvg name="certified" color="green.500" boxSize={ 6 } cursor="pointer"/>
|
||||
</Tooltip>
|
||||
) }
|
||||
<EntityTags
|
||||
@@ -131,7 +130,7 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
|
||||
/>
|
||||
) }
|
||||
{ !isLoading && tokenQuery.data && <AddressAddToWallet token={ tokenQuery.data } variant="button"/> }
|
||||
<AddressQrCode address={ addressQuery.data } isLoading={ isLoading }/>
|
||||
{ addressQuery.data && <AddressQrCode hash={ addressQuery.data.hash } isLoading={ isLoading }/> }
|
||||
<AccountActionsMenu isLoading={ isLoading }/>
|
||||
<Flex ml={{ base: 0, lg: 'auto' }} columnGap={ 2 } flexGrow={{ base: 1, lg: 0 }}>
|
||||
<TokenVerifiedInfo verifiedInfoQuery={ verifiedInfoQuery }/>
|
||||
|
||||
@@ -59,7 +59,7 @@ const Content = ({ data }: Props) => {
|
||||
<Flex fontSize="sm" flexDir="column" rowGap={ 5 }>
|
||||
{ (description || docs || support) && (
|
||||
<div>
|
||||
<Text variant="secondary" fontSize="xs">Description and support info</Text>
|
||||
<Text color="text.secondary" fontSize="xs">Description and support info</Text>
|
||||
{ description }
|
||||
{ (docs || support) && (
|
||||
<Flex alignItems="center" flexWrap="wrap" columnGap={ 6 } mt={ 3 }>
|
||||
@@ -71,7 +71,7 @@ const Content = ({ data }: Props) => {
|
||||
) }
|
||||
{ socialLinks.length > 0 && (
|
||||
<div>
|
||||
<Text variant="secondary" fontSize="xs">Links</Text>
|
||||
<Text color="text.secondary" fontSize="xs">Links</Text>
|
||||
<Grid templateColumns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} columnGap={ 4 } rowGap={ 3 } mt={ 3 }>
|
||||
{ socialLinks.map((link) => <ServiceLink key={ link.field } { ...link }/>) }
|
||||
</Grid>
|
||||
@@ -79,7 +79,7 @@ const Content = ({ data }: Props) => {
|
||||
) }
|
||||
{ priceTickersLinks.length > 0 && (
|
||||
<div>
|
||||
<Text variant="secondary" fontSize="xs">Crypto markets</Text>
|
||||
<Text color="text.secondary" fontSize="xs">Crypto markets</Text>
|
||||
<Grid templateColumns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} columnGap={ 4 } rowGap={ 3 } mt={ 3 }>
|
||||
{ priceTickersLinks.map((link) => <ServiceLink key={ link.field } { ...link }/>) }
|
||||
</Grid>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Link } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
|
||||
interface Props {
|
||||
@@ -16,7 +16,7 @@ const DocsLink = ({ href }: Props) => {
|
||||
alignItems="center"
|
||||
columnGap={ 1 }
|
||||
>
|
||||
<IconSvg name="docs" boxSize={ 6 } color="text_secondary"/>
|
||||
<IconSvg name="docs" boxSize={ 6 } color="text.secondary"/>
|
||||
<span>Documentation</span>
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Link } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TokenVerifiedInfo } from 'types/api/token';
|
||||
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import type { IconName } from 'ui/shared/IconSvg';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
|
||||
@@ -23,7 +23,7 @@ const ServiceLink = ({ href, title, icon }: Props) => {
|
||||
display="inline-flex"
|
||||
alignItems="center"
|
||||
>
|
||||
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text_secondary"/>
|
||||
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text.secondary"/>
|
||||
<span>{ title }</span>
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Link } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
|
||||
interface Props {
|
||||
@@ -19,7 +19,7 @@ const SupportLink = ({ url }: Props) => {
|
||||
alignItems="center"
|
||||
columnGap={ 1 }
|
||||
>
|
||||
<IconSvg name={ isEmail ? 'email' : 'link' } boxSize={ 6 } color="text_secondary"/>
|
||||
<IconSvg name={ isEmail ? 'email' : 'link' } boxSize={ 6 } color="text.secondary"/>
|
||||
<span>{ url }</span>
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -74,7 +74,7 @@ const TokenTransfer = ({ transfersQuery, tokenId, tokenQuery, shouldRender = tru
|
||||
<Box display={{ base: 'none', lg: 'block' }}>
|
||||
<TokenTransferTable
|
||||
data={ data?.items }
|
||||
top={ pagination.isVisible ? TABS_HEIGHT : 0 }
|
||||
top={ TABS_HEIGHT }
|
||||
showSocketInfo={ pagination.page === 1 }
|
||||
socketInfoAlert={ socketAlert }
|
||||
socketInfoNum={ newItemsCount }
|
||||
@@ -107,11 +107,12 @@ const TokenTransfer = ({ transfersQuery, tokenId, tokenQuery, shouldRender = tru
|
||||
return (
|
||||
<DataListDisplay
|
||||
isError={ isError || isTokenError }
|
||||
items={ data?.items }
|
||||
itemsNum={ data?.items.length }
|
||||
emptyText="There are no token transfers."
|
||||
content={ content }
|
||||
actionBar={ actionBar }
|
||||
/>
|
||||
>
|
||||
{ content }
|
||||
</DataListDisplay>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
|
||||
|
||||
import getCurrencyValue from 'lib/getCurrencyValue';
|
||||
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
|
||||
import { Badge } from 'toolkit/chakra/badge';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import AddressFromTo from 'ui/shared/address/AddressFromTo';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import Tag from 'ui/shared/chakra/Tag';
|
||||
import NftEntity from 'ui/shared/entities/nft/NftEntity';
|
||||
import TxEntity from 'ui/shared/entities/tx/TxEntity';
|
||||
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
|
||||
@@ -36,7 +36,7 @@ const TokenTransferListItem = ({
|
||||
}) : { usd: null, valueStr: null };
|
||||
|
||||
return (
|
||||
<ListItemMobile rowGap={ 3 } isAnimated>
|
||||
<ListItemMobile rowGap={ 3 }>
|
||||
<Flex justifyContent="space-between" alignItems="center" lineHeight="24px" width="100%">
|
||||
<TxEntity
|
||||
isLoading={ isLoading }
|
||||
@@ -48,13 +48,13 @@ const TokenTransferListItem = ({
|
||||
timestamp={ timestamp }
|
||||
enableIncrement
|
||||
isLoading={ isLoading }
|
||||
color="text_secondary"
|
||||
color="text.secondary"
|
||||
fontWeight="400"
|
||||
fontSize="sm"
|
||||
display="inline-block"
|
||||
/>
|
||||
</Flex>
|
||||
{ method && <Tag isLoading={ isLoading }>{ method }</Tag> }
|
||||
{ method && <Badge loading={ isLoading }>{ method }</Badge> }
|
||||
<AddressFromTo
|
||||
from={ from }
|
||||
to={ to }
|
||||
@@ -65,12 +65,12 @@ const TokenTransferListItem = ({
|
||||
/>
|
||||
{ valueStr && token && (token.type === 'ERC-20' || token.type === 'ERC-1155') && (
|
||||
<Grid gap={ 2 } templateColumns={ `1fr auto auto${ usd ? ' auto' : '' }` }>
|
||||
<Skeleton isLoaded={ !isLoading } flexShrink={ 0 } fontWeight={ 500 }>
|
||||
<Skeleton loading={ isLoading } flexShrink={ 0 } fontWeight={ 500 }>
|
||||
Value
|
||||
</Skeleton>
|
||||
<Skeleton
|
||||
isLoaded={ !isLoading }
|
||||
color="text_secondary"
|
||||
loading={ isLoading }
|
||||
color="text.secondary"
|
||||
wordBreak="break-all"
|
||||
overflow="hidden"
|
||||
flexGrow={ 1 }
|
||||
@@ -80,8 +80,8 @@ const TokenTransferListItem = ({
|
||||
{ token.symbol && <TruncatedValue isLoading={ isLoading } value={ token.symbol }/> }
|
||||
{ usd && (
|
||||
<Skeleton
|
||||
isLoaded={ !isLoading }
|
||||
color="text_secondary"
|
||||
loading={ isLoading }
|
||||
color="text.secondary"
|
||||
wordBreak="break-all"
|
||||
overflow="hidden"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Table, Tbody, Tr, Th } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TokenInfo } from 'types/api/token';
|
||||
@@ -6,8 +5,8 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
|
||||
|
||||
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
|
||||
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
|
||||
import { TableBody, TableColumnHeader, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table';
|
||||
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
|
||||
import { default as Thead } from 'ui/shared/TheadSticky';
|
||||
import TruncatedValue from 'ui/shared/TruncatedValue';
|
||||
import TokenTransferTableItem from 'ui/token/TokenTransfer/TokenTransferTableItem';
|
||||
|
||||
@@ -28,23 +27,23 @@ const TokenTransferTable = ({ data, top, showSocketInfo, socketInfoAlert, socket
|
||||
|
||||
return (
|
||||
<AddressHighlightProvider>
|
||||
<Table minW="950px">
|
||||
<Thead top={ top }>
|
||||
<Tr>
|
||||
<Th width="280px">Txn hash</Th>
|
||||
<Th width="200px">Method</Th>
|
||||
<Th width={{ lg: '224px', xl: '380px' }}>From/To</Th>
|
||||
<TableRoot minW="950px">
|
||||
<TableHeaderSticky top={ top }>
|
||||
<TableRow>
|
||||
<TableColumnHeader width="280px">Txn hash</TableColumnHeader>
|
||||
<TableColumnHeader width="200px">Method</TableColumnHeader>
|
||||
<TableColumnHeader width={{ lg: '224px', xl: '380px' }}>From/To</TableColumnHeader>
|
||||
{ (NFT_TOKEN_TYPE_IDS.includes(tokenType)) &&
|
||||
<Th width={ tokenType === 'ERC-1155' || tokenType === 'ERC-404' ? '50%' : '100%' }>Token ID</Th>
|
||||
<TableColumnHeader width={ tokenType === 'ERC-1155' || tokenType === 'ERC-404' ? '50%' : '100%' }>Token ID</TableColumnHeader>
|
||||
}
|
||||
{ (tokenType === 'ERC-20' || tokenType === 'ERC-1155' || tokenType === 'ERC-404') && (
|
||||
<Th width={ tokenType === 'ERC-20' ? '100%' : '50%' } isNumeric>
|
||||
<TableColumnHeader width={ tokenType === 'ERC-20' ? '100%' : '50%' } isNumeric>
|
||||
<TruncatedValue value={ `Value ${ token?.symbol || '' }` } w="100%" verticalAlign="middle"/>
|
||||
</Th>
|
||||
</TableColumnHeader>
|
||||
) }
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
</TableRow>
|
||||
</TableHeaderSticky>
|
||||
<TableBody>
|
||||
{ showSocketInfo && (
|
||||
<SocketNewItemsNotice.Desktop
|
||||
url={ window.location.href }
|
||||
@@ -62,8 +61,8 @@ const TokenTransferTable = ({ data, top, showSocketInfo, socketInfoAlert, socket
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
)) }
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableBody>
|
||||
</TableRoot>
|
||||
</AddressHighlightProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { Tr, Td, Flex, Box } from '@chakra-ui/react';
|
||||
import { Flex, Box } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TokenTransfer } from 'types/api/tokenTransfer';
|
||||
|
||||
import getCurrencyValue from 'lib/getCurrencyValue';
|
||||
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
|
||||
import { Badge } from 'toolkit/chakra/badge';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
import { TableCell, TableRow } from 'toolkit/chakra/table';
|
||||
import AddressFromTo from 'ui/shared/address/AddressFromTo';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import Tag from 'ui/shared/chakra/Tag';
|
||||
import NftEntity from 'ui/shared/entities/nft/NftEntity';
|
||||
import TxEntity from 'ui/shared/entities/tx/TxEntity';
|
||||
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
|
||||
@@ -34,8 +35,8 @@ const TokenTransferTableItem = ({
|
||||
}) : { usd: null, valueStr: null };
|
||||
|
||||
return (
|
||||
<Tr alignItems="top">
|
||||
<Td>
|
||||
<TableRow alignItems="top">
|
||||
<TableCell>
|
||||
<Flex alignItems="center" py="7px">
|
||||
<TxEntity
|
||||
hash={ txHash }
|
||||
@@ -54,15 +55,15 @@ const TokenTransferTableItem = ({
|
||||
ml="10px"
|
||||
/>
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{ method ? (
|
||||
<Box my="3px">
|
||||
<Tag isLoading={ isLoading } isTruncated>{ method }</Tag>
|
||||
<Badge loading={ isLoading } truncated>{ method }</Badge>
|
||||
</Box>
|
||||
) : null }
|
||||
</Td>
|
||||
<Td>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<AddressFromTo
|
||||
from={ from }
|
||||
to={ to }
|
||||
@@ -71,9 +72,9 @@ const TokenTransferTableItem = ({
|
||||
mode={{ lg: 'compact', xl: 'long' }}
|
||||
tokenHash={ token?.address }
|
||||
/>
|
||||
</Td>
|
||||
</TableCell>
|
||||
{ (token && NFT_TOKEN_TYPE_IDS.includes(token.type)) && (
|
||||
<Td>
|
||||
<TableCell>
|
||||
{ total && 'token_id' in total && token && total.token_id !== null ? (
|
||||
<NftEntity
|
||||
hash={ token.address }
|
||||
@@ -83,23 +84,23 @@ const TokenTransferTableItem = ({
|
||||
/>
|
||||
) : ''
|
||||
}
|
||||
</Td>
|
||||
</TableCell>
|
||||
) }
|
||||
{ token && (token.type === 'ERC-20' || token.type === 'ERC-1155' || token.type === 'ERC-404') && (
|
||||
<Td isNumeric verticalAlign="top">
|
||||
<TableCell isNumeric verticalAlign="top">
|
||||
{ valueStr && (
|
||||
<Skeleton isLoaded={ !isLoading } display="inline-block" mt="7px" wordBreak="break-all">
|
||||
<Skeleton loading={ isLoading } display="inline-block" mt="7px" wordBreak="break-all">
|
||||
{ valueStr }
|
||||
</Skeleton>
|
||||
) }
|
||||
{ usd && (
|
||||
<Skeleton isLoaded={ !isLoading } color="text_secondary" mt="10px" wordBreak="break-all">
|
||||
<Skeleton loading={ isLoading } color="text.secondary" mt="10px" wordBreak="break-all">
|
||||
<span>${ usd }</span>
|
||||
</Skeleton>
|
||||
) }
|
||||
</Td>
|
||||
</TableCell>
|
||||
) }
|
||||
</Tr>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import type { TokenVerifiedInfo as TTokenVerifiedInfo } from 'types/api/token';
|
||||
|
||||
import config from 'configs/app';
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import Skeleton from 'ui/shared/chakra/Skeleton';
|
||||
import LinkExternal from 'ui/shared/links/LinkExternal';
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import { Skeleton } from 'toolkit/chakra/skeleton';
|
||||
|
||||
import TokenProjectInfo from './TokenProjectInfo';
|
||||
|
||||
@@ -26,9 +26,9 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
|
||||
if (isPending) {
|
||||
return (
|
||||
<>
|
||||
<Skeleton w="100px" h="30px" borderRadius="base"/>
|
||||
<Skeleton w="100px" h="30px" borderRadius="base"/>
|
||||
<Skeleton w="70px" h="30px" borderRadius="base"/>
|
||||
<Skeleton loading w="100px" h="30px" borderRadius="base"/>
|
||||
<Skeleton loading w="100px" h="30px" borderRadius="base"/>
|
||||
<Skeleton loading w="70px" h="30px" borderRadius="base"/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -41,9 +41,9 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
|
||||
try {
|
||||
const url = new URL(data.projectWebsite);
|
||||
return (
|
||||
<LinkExternal href={ data.projectWebsite } variant="subtle" flexShrink={ 0 } fontSize="sm" lineHeight={ 5 }>
|
||||
<Link external href={ data.projectWebsite } variant="underlaid" flexShrink={ 0 } textStyle="sm">
|
||||
{ url.host }
|
||||
</LinkExternal>
|
||||
</Link>
|
||||
);
|
||||
} catch (error) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user