feat: [info] add new tdp nav (#7531)
* feat: [info] add new tdp nav * tidy up code * pr review * nit remove unused component style * pr review * lol extraneous extra
This commit is contained in:
parent
712f82cb1a
commit
876d3a1cc3
@ -1,6 +1,7 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { CopyContractAddress, ThemedText } from 'theme/components'
|
import { CopyContractAddress, ThemedText } from 'theme/components'
|
||||||
|
import { shortenAddress } from 'utils/addresses'
|
||||||
|
|
||||||
const ContractAddressSection = styled.div`
|
const ContractAddressSection = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -29,7 +30,7 @@ export default function AddressSection({ address }: { address: string }) {
|
|||||||
<Trans>Contract address</Trans>
|
<Trans>Contract address</Trans>
|
||||||
</ThemedText.SubHeaderSmall>
|
</ThemedText.SubHeaderSmall>
|
||||||
<ContractAddress>
|
<ContractAddress>
|
||||||
<CopyContractAddress address={address} />
|
<CopyContractAddress address={address} truncatedAddress={shortenAddress(address, 2, 3)} />
|
||||||
</ContractAddress>
|
</ContractAddress>
|
||||||
</ContractAddressSection>
|
</ContractAddressSection>
|
||||||
)
|
)
|
||||||
|
@ -1,17 +1,31 @@
|
|||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
|
export const BreadcrumbNav = styled.div<{ isInfoTDPEnabled?: boolean }>`
|
||||||
|
display: flex;
|
||||||
|
color: ${({ theme }) => theme.neutral1};
|
||||||
|
${({ isInfoTDPEnabled }) =>
|
||||||
|
isInfoTDPEnabled
|
||||||
|
? css`
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
`
|
||||||
|
: css`
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
`}
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: fit-content;
|
||||||
|
`
|
||||||
|
|
||||||
export const BreadcrumbNavLink = styled(Link)`
|
export const BreadcrumbNavLink = styled(Link)`
|
||||||
display: flex;
|
display: flex;
|
||||||
color: ${({ theme }) => theme.neutral2};
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 20px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
color: ${({ theme }) => theme.neutral2};
|
||||||
text-decoration: none;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
transition-duration: ${({ theme }) => theme.transition.duration.fast};
|
transition-duration: ${({ theme }) => theme.transition.duration.fast};
|
||||||
width: fit-content;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${({ theme }) => theme.neutral3};
|
color: ${({ theme }) => theme.neutral3};
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import { Trans } from '@lingui/macro'
|
||||||
import { SwapSkeleton } from 'components/swap/SwapSkeleton'
|
import { SwapSkeleton } from 'components/swap/SwapSkeleton'
|
||||||
import { useInfoExplorePageEnabled } from 'featureFlags/flags/infoExplore'
|
import { useInfoExplorePageEnabled } from 'featureFlags/flags/infoExplore'
|
||||||
import { ArrowLeft } from 'react-feather'
|
import { useInfoTDPEnabled } from 'featureFlags/flags/infoTDP'
|
||||||
|
import { ArrowLeft, ChevronRight } from 'react-feather'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import styled, { useTheme } from 'styled-components'
|
import styled, { useTheme } from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
@ -8,7 +10,7 @@ import { textFadeIn } from 'theme/styles'
|
|||||||
|
|
||||||
import { LoadingBubble } from '../loading'
|
import { LoadingBubble } from '../loading'
|
||||||
import { AboutContainer, AboutHeader } from './About'
|
import { AboutContainer, AboutHeader } from './About'
|
||||||
import { BreadcrumbNavLink } from './BreadcrumbNavLink'
|
import { BreadcrumbNav, BreadcrumbNavLink } from './BreadcrumbNavLink'
|
||||||
import { StatPair, StatsWrapper, StatWrapper } from './StatsSection'
|
import { StatPair, StatsWrapper, StatWrapper } from './StatsSection'
|
||||||
|
|
||||||
const SWAP_COMPONENT_WIDTH = 360
|
const SWAP_COMPONENT_WIDTH = 360
|
||||||
@ -92,6 +94,9 @@ const SquaredBubble = styled(DetailBubble)`
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
`
|
`
|
||||||
|
const NavBubble = styled(DetailBubble)`
|
||||||
|
width: 169px;
|
||||||
|
`
|
||||||
const TokenLogoBubble = styled(DetailBubble)`
|
const TokenLogoBubble = styled(DetailBubble)`
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@ -222,13 +227,26 @@ function LoadingStats() {
|
|||||||
export default function TokenDetailsSkeleton() {
|
export default function TokenDetailsSkeleton() {
|
||||||
const { chainName } = useParams<{ chainName?: string }>()
|
const { chainName } = useParams<{ chainName?: string }>()
|
||||||
const isInfoExplorePageEnabled = useInfoExplorePageEnabled()
|
const isInfoExplorePageEnabled = useInfoExplorePageEnabled()
|
||||||
|
const isInfoTDPEnabled = useInfoTDPEnabled()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LeftPanel>
|
<LeftPanel>
|
||||||
|
{isInfoTDPEnabled ? (
|
||||||
|
<BreadcrumbNav isInfoTDPEnabled>
|
||||||
|
<BreadcrumbNavLink to={`${isInfoExplorePageEnabled ? '/explore' : ''}/tokens/${chainName}`}>
|
||||||
|
<Trans>Explore</Trans> <ChevronRight size={14} /> <Trans>Tokens</Trans> <ChevronRight size={14} />
|
||||||
|
</BreadcrumbNavLink>{' '}
|
||||||
|
<NavBubble />
|
||||||
|
</BreadcrumbNav>
|
||||||
|
) : (
|
||||||
|
<BreadcrumbNav>
|
||||||
<BreadcrumbNavLink
|
<BreadcrumbNavLink
|
||||||
to={(isInfoExplorePageEnabled ? '/explore' : '') + (chainName ? `/tokens/${chainName}` : `/tokens`)}
|
to={(isInfoExplorePageEnabled ? '/explore' : '') + (chainName ? `/tokens/${chainName}` : `/tokens`)}
|
||||||
>
|
>
|
||||||
<ArrowLeft size={14} /> Tokens
|
<ArrowLeft size={14} /> Tokens
|
||||||
</BreadcrumbNavLink>
|
</BreadcrumbNavLink>
|
||||||
|
</BreadcrumbNav>
|
||||||
|
)}
|
||||||
<TokenInfoContainer>
|
<TokenInfoContainer>
|
||||||
<TokenNameCell>
|
<TokenNameCell>
|
||||||
<TokenLogoBubble />
|
<TokenLogoBubble />
|
||||||
|
@ -6,7 +6,7 @@ import { PortfolioLogo } from 'components/AccountDrawer/MiniPortfolio/PortfolioL
|
|||||||
import { AboutSection } from 'components/Tokens/TokenDetails/About'
|
import { AboutSection } from 'components/Tokens/TokenDetails/About'
|
||||||
import AddressSection from 'components/Tokens/TokenDetails/AddressSection'
|
import AddressSection from 'components/Tokens/TokenDetails/AddressSection'
|
||||||
import BalanceSummary from 'components/Tokens/TokenDetails/BalanceSummary'
|
import BalanceSummary from 'components/Tokens/TokenDetails/BalanceSummary'
|
||||||
import { BreadcrumbNavLink } from 'components/Tokens/TokenDetails/BreadcrumbNavLink'
|
import { BreadcrumbNav, BreadcrumbNavLink } from 'components/Tokens/TokenDetails/BreadcrumbNavLink'
|
||||||
import ChartSection from 'components/Tokens/TokenDetails/ChartSection'
|
import ChartSection from 'components/Tokens/TokenDetails/ChartSection'
|
||||||
import MobileBalanceSummaryFooter from 'components/Tokens/TokenDetails/MobileBalanceSummaryFooter'
|
import MobileBalanceSummaryFooter from 'components/Tokens/TokenDetails/MobileBalanceSummaryFooter'
|
||||||
import ShareButton from 'components/Tokens/TokenDetails/ShareButton'
|
import ShareButton from 'components/Tokens/TokenDetails/ShareButton'
|
||||||
@ -32,12 +32,13 @@ import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch'
|
|||||||
import { UNKNOWN_TOKEN_SYMBOL, useTokenFromActiveNetwork } from 'lib/hooks/useCurrency'
|
import { UNKNOWN_TOKEN_SYMBOL, useTokenFromActiveNetwork } from 'lib/hooks/useCurrency'
|
||||||
import { Swap } from 'pages/Swap'
|
import { Swap } from 'pages/Swap'
|
||||||
import { useCallback, useMemo, useState, useTransition } from 'react'
|
import { useCallback, useMemo, useState, useTransition } from 'react'
|
||||||
import { ArrowLeft } from 'react-feather'
|
import { ArrowLeft, ChevronRight } from 'react-feather'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { Field } from 'state/swap/actions'
|
import { Field } from 'state/swap/actions'
|
||||||
import { SwapState } from 'state/swap/reducer'
|
import { SwapState } from 'state/swap/reducer'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { isAddress } from 'utils'
|
import { CopyContractAddress } from 'theme/components'
|
||||||
|
import { isAddress, shortenAddress } from 'utils'
|
||||||
import { addressesAreEquivalent } from 'utils/addressesAreEquivalent'
|
import { addressesAreEquivalent } from 'utils/addressesAreEquivalent'
|
||||||
|
|
||||||
import { OnChangeTimePeriod } from './ChartSection'
|
import { OnChangeTimePeriod } from './ChartSection'
|
||||||
@ -130,7 +131,6 @@ export default function TokenDetails({
|
|||||||
}, {} as { [key: string]: string | undefined }) ?? {},
|
}, {} as { [key: string]: string | undefined }) ?? {},
|
||||||
[tokenQueryData]
|
[tokenQueryData]
|
||||||
)
|
)
|
||||||
const isInfoTDPEnabled = useInfoTDPEnabled()
|
|
||||||
|
|
||||||
const { token: detailedToken, didFetchFromChain } = useRelevantToken(address, pageChainId, tokenQueryData)
|
const { token: detailedToken, didFetchFromChain } = useRelevantToken(address, pageChainId, tokenQueryData)
|
||||||
|
|
||||||
@ -139,6 +139,7 @@ export default function TokenDetails({
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const isInfoExplorePageEnabled = useInfoExplorePageEnabled()
|
const isInfoExplorePageEnabled = useInfoExplorePageEnabled()
|
||||||
|
const isInfoTDPEnabled = useInfoTDPEnabled()
|
||||||
|
|
||||||
// Wrapping navigate in a transition prevents Suspense from unnecessarily showing fallbacks again.
|
// Wrapping navigate in a transition prevents Suspense from unnecessarily showing fallbacks again.
|
||||||
const [isPending, startTokenTransition] = useTransition()
|
const [isPending, startTokenTransition] = useTransition()
|
||||||
@ -210,6 +211,7 @@ export default function TokenDetails({
|
|||||||
if (detailedToken === undefined || !address) {
|
if (detailedToken === undefined || !address) {
|
||||||
return <InvalidTokenDetails pageChainId={pageChainId} isInvalidAddress={!address} />
|
return <InvalidTokenDetails pageChainId={pageChainId} isInvalidAddress={!address} />
|
||||||
}
|
}
|
||||||
|
const tokenSymbolName = detailedToken && (detailedToken.symbol ?? <Trans>Symbol not found</Trans>)
|
||||||
return (
|
return (
|
||||||
<Trace
|
<Trace
|
||||||
page={InterfacePageName.TOKEN_DETAILS_PAGE}
|
page={InterfacePageName.TOKEN_DETAILS_PAGE}
|
||||||
@ -219,15 +221,37 @@ export default function TokenDetails({
|
|||||||
<TokenDetailsLayout>
|
<TokenDetailsLayout>
|
||||||
{detailedToken && !isPending ? (
|
{detailedToken && !isPending ? (
|
||||||
<LeftPanel>
|
<LeftPanel>
|
||||||
|
{isInfoTDPEnabled ? (
|
||||||
|
<BreadcrumbNav isInfoTDPEnabled>
|
||||||
|
<BreadcrumbNavLink to={`${isInfoExplorePageEnabled ? '/explore' : ''}/tokens/${chain.toLowerCase()}`}>
|
||||||
|
<Trans>Explore</Trans> <ChevronRight size={14} /> <Trans>Tokens</Trans> <ChevronRight size={14} />
|
||||||
|
</BreadcrumbNavLink>{' '}
|
||||||
|
{tokenSymbolName}{' '}
|
||||||
|
{!detailedToken.isNative && (
|
||||||
|
<>
|
||||||
|
(
|
||||||
|
<CopyContractAddress
|
||||||
|
address={address}
|
||||||
|
showTruncatedOnly
|
||||||
|
truncatedAddress={shortenAddress(address)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</BreadcrumbNav>
|
||||||
|
) : (
|
||||||
|
<BreadcrumbNav>
|
||||||
<BreadcrumbNavLink to={`${isInfoExplorePageEnabled ? '/explore' : ''}/tokens/${chain.toLowerCase()}`}>
|
<BreadcrumbNavLink to={`${isInfoExplorePageEnabled ? '/explore' : ''}/tokens/${chain.toLowerCase()}`}>
|
||||||
<ArrowLeft data-testid="token-details-return-button" size={14} /> Tokens
|
<ArrowLeft data-testid="token-details-return-button" size={14} /> Tokens
|
||||||
</BreadcrumbNavLink>
|
</BreadcrumbNavLink>
|
||||||
|
</BreadcrumbNav>
|
||||||
|
)}
|
||||||
<TokenInfoContainer data-testid="token-info-container">
|
<TokenInfoContainer data-testid="token-info-container">
|
||||||
<TokenNameCell>
|
<TokenNameCell>
|
||||||
<PortfolioLogo currencies={[detailedToken]} chainId={detailedToken.chainId} size="32px" />
|
<PortfolioLogo currencies={[detailedToken]} chainId={detailedToken.chainId} size="32px" />
|
||||||
<TokenTitle>
|
<TokenTitle>
|
||||||
{detailedToken.name ?? <Trans>Name not found</Trans>}
|
{detailedToken.name ?? <Trans>Name not found</Trans>}
|
||||||
<TokenSymbol>{detailedToken.symbol ?? <Trans>Symbol not found</Trans>}</TokenSymbol>
|
<TokenSymbol>{tokenSymbolName}</TokenSymbol>
|
||||||
</TokenTitle>
|
</TokenTitle>
|
||||||
</TokenNameCell>
|
</TokenNameCell>
|
||||||
<TokenActions>
|
<TokenActions>
|
||||||
|
@ -243,13 +243,14 @@ export function CopyLinkIcon({ toCopy }: { toCopy: string }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const FullAddress = styled.span`
|
const FullAddress = styled.span<{ showTruncated?: boolean }>`
|
||||||
|
${({ showTruncated }) => showTruncated && 'display: none;'}
|
||||||
@media only screen and (max-width: ${MOBILE_MEDIA_BREAKPOINT}) {
|
@media only screen and (max-width: ${MOBILE_MEDIA_BREAKPOINT}) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const TruncatedAddress = styled.span`
|
const TruncatedAddress = styled.span<{ showTruncated?: boolean }>`
|
||||||
display: none;
|
display: ${({ showTruncated }) => (showTruncated ? 'flex' : 'none')};
|
||||||
@media only screen and (max-width: ${MOBILE_MEDIA_BREAKPOINT}) {
|
@media only screen and (max-width: ${MOBILE_MEDIA_BREAKPOINT}) {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@ -273,7 +274,15 @@ const CopyContractAddressWrapper = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`
|
`
|
||||||
|
|
||||||
export function CopyContractAddress({ address }: { address: string }) {
|
export function CopyContractAddress({
|
||||||
|
address,
|
||||||
|
showTruncatedOnly,
|
||||||
|
truncatedAddress,
|
||||||
|
}: {
|
||||||
|
address: string
|
||||||
|
showTruncatedOnly?: boolean
|
||||||
|
truncatedAddress?: string
|
||||||
|
}) {
|
||||||
const [isCopied, setCopied] = useCopyClipboard()
|
const [isCopied, setCopied] = useCopyClipboard()
|
||||||
const [tooltipX, setTooltipX] = useState<number | undefined>()
|
const [tooltipX, setTooltipX] = useState<number | undefined>()
|
||||||
const copy = useCallback(
|
const copy = useCallback(
|
||||||
@ -284,12 +293,11 @@ export function CopyContractAddress({ address }: { address: string }) {
|
|||||||
[address, setCopied]
|
[address, setCopied]
|
||||||
)
|
)
|
||||||
|
|
||||||
const truncated = `${address.slice(0, 4)}...${address.slice(-3)}`
|
|
||||||
return (
|
return (
|
||||||
<CopyContractAddressWrapper onClick={copy}>
|
<CopyContractAddressWrapper onClick={copy}>
|
||||||
<CopyAddressRow isClicked={isCopied}>
|
<CopyAddressRow isClicked={isCopied}>
|
||||||
<FullAddress>{address}</FullAddress>
|
<FullAddress showTruncated={showTruncatedOnly}>{address}</FullAddress>
|
||||||
<TruncatedAddress>{truncated}</TruncatedAddress>
|
<TruncatedAddress showTruncated={showTruncatedOnly}>{truncatedAddress}</TruncatedAddress>
|
||||||
<Copy size={14} />
|
<Copy size={14} />
|
||||||
</CopyAddressRow>
|
</CopyAddressRow>
|
||||||
{isCopied && <Tooltip isCopyContractTooltip tooltipX={tooltipX} />}
|
{isCopied && <Tooltip isCopyContractTooltip tooltipX={tooltipX} />}
|
||||||
|
Loading…
Reference in New Issue
Block a user