Commit 92a6ec67 authored by Jack Short's avatar Jack Short Committed by GitHub

feat: [DetailsV2] different media types on landing page (#6492)

* initial layout assuming media type exists

* fixing embeds

* media type function

* updated snapshot test

* initial shadow impl

* better shadows

* audio player controls

* updating tests

* content not available handlers

* errors on all media types

* removing fullscreen from iframe

* adding snapshot tests

* responding to comments

* text align center

* updating tests
parent 1d6a1e90
......@@ -3,7 +3,9 @@ import Row from 'components/Row'
import { VerifiedIcon } from 'nft/components/icons'
import { CollectionInfoForAsset, GenieAsset } from 'nft/types'
import styled from 'styled-components/macro'
import { BREAKPOINTS, ThemedText } from 'theme'
import { BREAKPOINTS } from 'theme'
import { MediaRenderer } from './MediaRenderer'
const MAX_WIDTH = 560
......@@ -14,6 +16,7 @@ const LandingPageContainer = styled.div`
align-items: center;
padding: 22px 20px 0px;
gap: 26px;
width: 100%;
@media screen and (min-width: ${BREAKPOINTS.sm}px) {
gap: 64px;
......@@ -29,6 +32,7 @@ const LandingPageContainer = styled.div`
padding-top: 0px;
padding-bottom: ${({ theme }) => `${theme.navHeight}px`};
gap: 80px;
justify-content: center;
}
`
......@@ -40,40 +44,57 @@ const InfoContainer = styled(ColumnCenter)`
}
`
const InfoDetailsContainer = styled(Column)`
gap: 4px;
align-items: center;
`
const MediaContainer = styled.div`
width: 100%;
height: 100%;
const StyledHeadlineText = styled.div`
font-weight: 600;
font-size: 20px;
line-height: 28px;
text-align: center;
color: ${({ theme }) => theme.textPrimary};
@media screen and (min-width: ${BREAKPOINTS.sm}px) {
width: ${MAX_WIDTH}px;
height: ${MAX_WIDTH}px;
line-height: 44px;
font-size: 36px;
}
`
const StyledSubheaderText = styled.div`
font-weight: 500;
font-size: 14px;
line-height: 20px;
text-align: center;
color: ${({ theme }) => theme.textSecondary};
const StyledMedia = styled.img`
object-fit: contain;
height: 100%;
width: 100%;
@media screen and (min-width: ${BREAKPOINTS.sm}px) {
line-height: 24px;
font-size: 16px;
}
`
const StyledSubheaderText = styled(ThemedText.SubHeaderSmall)`
line-height: 20px;
const InfoDetailsContainer = styled(Column)`
gap: 4px;
align-items: center;
@media screen and (min-width: ${BREAKPOINTS.sm}px) {
line-height: 24px !important;
font-size: 16px !important;
${StyledHeadlineText} {
line-height: 44px;
font-size: 36px;
}
${StyledSubheaderText} {
line-height: 24px;
font-size: 16px;
}
}
`
const StyledHeadlineText = styled(ThemedText.HeadlineSmall)`
const MediaContainer = styled.div`
position: relative;
width: 100%;
height: 100%;
filter: drop-shadow(0px 12px 20px rgba(0, 0, 0, 0.1));
@media screen and (min-width: ${BREAKPOINTS.sm}px) {
line-height: 44px !important;
font-size: 36px !important;
width: ${MAX_WIDTH}px;
height: ${MAX_WIDTH}px;
}
`
......@@ -86,7 +107,7 @@ export const LandingPage = ({ asset, collection }: LandingPageProps) => {
return (
<LandingPageContainer>
<MediaContainer>
<StyledMedia src={asset.imageUrl} />
<MediaRenderer asset={asset} />
</MediaContainer>
<InfoContainer>
<InfoDetailsContainer>
......
import {
TEST_AUDIO_NFT_ASSET,
TEST_EMBEDDED_NFT_ASSET,
TEST_NFT_ASSET,
TEST_VIDEO_NFT_ASSET,
} from 'test-utils/nft/fixtures'
import { render } from 'test-utils/render'
import { MediaRenderer } from './MediaRenderer'
describe('Media renderer', () => {
it('renders image nft correctly', () => {
const { asFragment } = render(<MediaRenderer asset={TEST_NFT_ASSET} />)
expect(asFragment()).toMatchSnapshot()
})
it('renders an embedded nft correctly', () => {
const { asFragment } = render(<MediaRenderer asset={TEST_EMBEDDED_NFT_ASSET} />)
expect(asFragment()).toMatchSnapshot()
})
it('renders a video nft correctly', () => {
const { asFragment } = render(<MediaRenderer asset={TEST_VIDEO_NFT_ASSET} />)
expect(asFragment()).toMatchSnapshot()
})
it('renders an audio nft correctly', () => {
const { asFragment } = render(<MediaRenderer asset={TEST_AUDIO_NFT_ASSET} />)
expect(asFragment()).toMatchSnapshot()
})
})
import { GenieAsset } from 'nft/types'
import { isAudio, isVideo } from 'nft/utils'
import { useState } from 'react'
import styled, { css } from 'styled-components/macro'
import { BREAKPOINTS, ThemedText } from 'theme'
const MediaStyle = css`
position: relative;
object-fit: contain;
height: 100%;
width: 100%;
aspect-ratio: 1;
z-index: 1;
`
const StyledImage = styled.img`
${MediaStyle}
`
const StyledVideo = styled.video`
${MediaStyle}
`
const MediaShadow = styled.img`
object-fit: contain;
height: 100%;
aspect-ratio: 1;
border-radius: 20px;
filter: blur(25px);
@media screen and (min-width: ${BREAKPOINTS.xl}px) {
filter: blur(50px);
}
`
const MediaShadowContainer = styled.div`
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
`
const StyledEmbed = styled.div`
position: relative;
overflow: hidden;
width: 100%;
padding-top: 100%;
z-index: 1;
`
const StyledIFrame = styled.iframe`
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
`
const AudioContainer = styled.div`
position: relative;
`
const StyledAudio = styled.audio`
position: absolute;
left: 0;
bottom: 0;
z-index: 2;
width: 100%;
`
const AudioPlayer = ({ asset, onError }: { asset: GenieAsset; onError: () => void }) => {
return (
<AudioContainer>
<StyledImage
src={asset.imageUrl}
alt={asset.name ?? asset.collectionName + ' #' + asset.tokenId}
onError={onError}
/>
<StyledAudio controls src={asset.animationUrl} onError={onError} />
</AudioContainer>
)
}
const EmbeddedMediaPlayer = ({ asset, onError }: { asset: GenieAsset; onError: () => void }) => {
return (
<StyledEmbed>
<StyledIFrame
title={asset.name ?? `${asset.collectionName} #${asset.tokenId}`}
src={asset.animationUrl}
frameBorder={0}
sandbox="allow-scripts"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
onError={onError}
/>
</StyledEmbed>
)
}
const ContentNotAvailable = styled(ThemedText.BodySmall)`
display: flex;
background-color: ${({ theme }) => theme.backgroundSurface};
color: ${({ theme }) => theme.textSecondary};
align-items: center;
justify-content: center;
${MediaStyle}
`
// TODO: when assets query is moved to nxyz update with mediaType from the query
enum MediaType {
Audio = 'audio',
Video = 'video',
Image = 'image',
Raw = 'raw',
}
function assetMediaType(asset: GenieAsset): MediaType {
if (isAudio(asset.animationUrl ?? '')) {
return MediaType.Audio
} else if (isVideo(asset.animationUrl ?? '')) {
return MediaType.Video
} else if (asset.animationUrl) {
return MediaType.Raw
}
return MediaType.Image
}
const RenderMediaShadow = ({ imageUrl }: { imageUrl: string | undefined }) => {
const [contentNotAvailable, setContentNotAvailable] = useState(false)
if (!imageUrl || contentNotAvailable) {
return null
}
return (
<MediaShadowContainer>
<MediaShadow src={imageUrl} onError={() => setContentNotAvailable(true)} />
</MediaShadowContainer>
)
}
const RenderMediaType = ({ asset }: { asset: GenieAsset }) => {
const [contentNotAvailable, setContentNotAvailable] = useState(false)
if (contentNotAvailable) {
return <ContentNotAvailable>Content not available</ContentNotAvailable>
}
switch (assetMediaType(asset)) {
case MediaType.Image:
return (
<StyledImage
src={asset.imageUrl}
alt={asset.name || asset.collectionName}
onError={() => setContentNotAvailable(true)}
/>
)
case MediaType.Video:
return (
<StyledVideo
src={asset.animationUrl}
autoPlay
controls
muted
loop
onError={() => setContentNotAvailable(true)}
/>
)
case MediaType.Audio:
return <AudioPlayer asset={asset} onError={() => setContentNotAvailable(true)} />
case MediaType.Raw:
return <EmbeddedMediaPlayer asset={asset} onError={() => setContentNotAvailable(true)} />
}
}
export const MediaRenderer = ({ asset }: { asset: GenieAsset }) => (
<>
<RenderMediaType asset={asset} />
<RenderMediaShadow imageUrl={asset.imageUrl} />
</>
)
......@@ -2,13 +2,13 @@
exports[`LandingPage renders it correctly 1`] = `
<DocumentFragment>
.c7 {
.c9 {
box-sizing: border-box;
margin: 0;
min-width: 0;
}
.c8 {
.c10 {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
......@@ -26,15 +26,7 @@ exports[`LandingPage renders it correctly 1`] = `
gap: 4px;
}
.c9 {
color: #7780A0;
}
.c11 {
color: #0D111C;
}
.c3 {
.c5 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
......@@ -48,7 +40,7 @@ exports[`LandingPage renders it correctly 1`] = `
justify-content: flex-start;
}
.c4 {
.c6 {
width: 100%;
-webkit-align-items: center;
-webkit-box-align: center;
......@@ -56,6 +48,32 @@ exports[`LandingPage renders it correctly 1`] = `
align-items: center;
}
.c2 {
position: relative;
object-fit: contain;
height: 100%;
width: 100%;
aspect-ratio: 1;
z-index: 1;
}
.c4 {
object-fit: contain;
height: 100%;
aspect-ratio: 1;
border-radius: 20px;
-webkit-filter: blur(25px);
filter: blur(25px);
}
.c3 {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.c0 {
display: -webkit-box;
display: -webkit-flex;
......@@ -71,13 +89,30 @@ exports[`LandingPage renders it correctly 1`] = `
align-items: center;
padding: 22px 20px 0px;
gap: 26px;
width: 100%;
}
.c5 {
.c7 {
gap: 40px;
}
.c6 {
.c14 {
font-weight: 600;
font-size: 20px;
line-height: 28px;
text-align: center;
color: #0D111C;
}
.c12 {
font-weight: 500;
font-size: 14px;
line-height: 20px;
text-align: center;
color: #7780A0;
}
.c8 {
gap: 4px;
-webkit-align-items: center;
-webkit-box-align: center;
......@@ -86,18 +121,18 @@ exports[`LandingPage renders it correctly 1`] = `
}
.c1 {
position: relative;
width: 100%;
height: 100%;
-webkit-filter: drop-shadow(0px 12px 20px rgba(0,0,0,0.1));
filter: drop-shadow(0px 12px 20px rgba(0,0,0,0.1));
}
.c2 {
object-fit: contain;
height: 100%;
width: 100%;
}
.c10 {
line-height: 20px;
@media screen and (min-width:1280px) {
.c4 {
-webkit-filter: blur(50px);
filter: blur(50px);
}
}
@media screen and (min-width:640px) {
......@@ -121,33 +156,49 @@ exports[`LandingPage renders it correctly 1`] = `
padding-top: 0px;
padding-bottom: 72px;
gap: 80px;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
}
@media screen and (min-width:640px) {
.c5 {
.c7 {
width: 560px;
}
}
@media screen and (min-width:640px) {
.c1 {
width: 560px;
height: 560px;
.c14 {
line-height: 44px;
font-size: 36px;
}
}
@media screen and (min-width:640px) {
.c10 {
line-height: 24px !important;
font-size: 16px !important;
.c12 {
line-height: 24px;
font-size: 16px;
}
}
@media screen and (min-width:640px) {
.c12 {
line-height: 44px !important;
font-size: 36px !important;
.c8 .c13 {
line-height: 44px;
font-size: 36px;
}
.c8 .c11 {
line-height: 24px;
font-size: 16px;
}
}
@media screen and (min-width:640px) {
.c1 {
width: 560px;
height: 560px;
}
}
......@@ -158,21 +209,30 @@ exports[`LandingPage renders it correctly 1`] = `
class="c1"
>
<img
alt="Azuki #3318"
class="c2"
src="https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/3318/50ed67ad647d0aa0cad0b830d136a677efc2fb72a44587bc35f2a5fb334a7fdf.png"
/>
<div
class="c3"
>
<img
class="c4"
src="https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/3318/50ed67ad647d0aa0cad0b830d136a677efc2fb72a44587bc35f2a5fb334a7fdf.png"
/>
</div>
</div>
<div
class="c3 c4 c5"
class="c5 c6 c7"
>
<div
class="c3 c6"
class="c5 c8"
>
<div
class="c7 c8"
class="c9 c10"
>
<div
class="c9 c10 css-1aekuku"
class="c11 c12"
>
Azuki
</div>
......@@ -194,7 +254,7 @@ exports[`LandingPage renders it correctly 1`] = `
</svg>
</div>
<div
class="c11 c12 css-iapcxi"
class="c13 c14"
>
Azuki #3318
</div>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Media renderer renders a video nft correctly 1`] = `
<DocumentFragment>
.c0 {
position: relative;
object-fit: contain;
height: 100%;
width: 100%;
aspect-ratio: 1;
z-index: 1;
}
@media screen and (min-width:1280px) {
}
<video
autoplay=""
class="c0"
controls=""
loop=""
src="https://openseauserdata.com/files/5af92728200027caa4f3f5ae87a486a7.mp4"
/>
.c1 {
object-fit: contain;
height: 100%;
aspect-ratio: 1;
border-radius: 20px;
-webkit-filter: blur(25px);
filter: blur(25px);
}
.c0 {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
@media screen and (min-width:1280px) {
.c1 {
-webkit-filter: blur(50px);
filter: blur(50px);
}
}
<div
class="c0"
>
<img
class="c1"
src="https://i.seadn.io/gae/tkDbNhjjBZV2PmYaJbJOOigywZCrlcyGRxeQFkZS1YZyihyG5GoWNWj3N9f1T7YVuaxOqdxhfJylC9ejtoCvdgBE932vd7jorVqA?w=500&auto=format"
/>
</div>
</DocumentFragment>
`;
exports[`Media renderer renders an audio nft correctly 1`] = `
<DocumentFragment>
.c1 {
position: relative;
object-fit: contain;
height: 100%;
width: 100%;
aspect-ratio: 1;
z-index: 1;
}
.c0 {
position: relative;
}
.c2 {
position: absolute;
left: 0;
bottom: 0;
z-index: 2;
width: 100%;
}
@media screen and (min-width:1280px) {
}
<div
class="c0"
>
<img
alt="Death Row Session: Vol. 2 (420 Edition) #320"
class="c1"
src="https://i.seadn.io/gae/Kze9SBqn_6O0qrHKxspo1gRkkDV2A5EmTeWtvdS-dNxBsvi_wPXUYjc6De0sUC-DYzL093102mUftenWxwWuTelqsdw-ngoBC3o2XFU?w=500&auto=format"
/>
<audio
class="c2"
controls=""
src="https://openseauserdata.com/files/4a22253e44e10baa11484a2e43efefda.mp3"
/>
</div>
.c1 {
object-fit: contain;
height: 100%;
aspect-ratio: 1;
border-radius: 20px;
-webkit-filter: blur(25px);
filter: blur(25px);
}
.c0 {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
@media screen and (min-width:1280px) {
.c1 {
-webkit-filter: blur(50px);
filter: blur(50px);
}
}
<div
class="c0"
>
<img
class="c1"
src="https://i.seadn.io/gae/Kze9SBqn_6O0qrHKxspo1gRkkDV2A5EmTeWtvdS-dNxBsvi_wPXUYjc6De0sUC-DYzL093102mUftenWxwWuTelqsdw-ngoBC3o2XFU?w=500&auto=format"
/>
</div>
</DocumentFragment>
`;
exports[`Media renderer renders an embedded nft correctly 1`] = `
<DocumentFragment>
.c0 {
position: relative;
overflow: hidden;
width: 100%;
padding-top: 100%;
z-index: 1;
}
.c1 {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
@media screen and (min-width:1280px) {
}
<div
class="c0"
>
<iframe
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
class="c1"
frameborder="0"
sandbox="allow-scripts"
src="https://tokens.mathcastles.xyz/terraforms/token-html/7202"
title="Level 13 at {28, 3}"
/>
</div>
.c1 {
object-fit: contain;
height: 100%;
aspect-ratio: 1;
border-radius: 20px;
-webkit-filter: blur(25px);
filter: blur(25px);
}
.c0 {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
@media screen and (min-width:1280px) {
.c1 {
-webkit-filter: blur(50px);
filter: blur(50px);
}
}
<div
class="c0"
>
<img
class="c1"
src="https://cdn.center.app/v2/1/06ff92279474add6ce06176e2a65447396edf786d169d8ccc03fddfa45ce004f/bb01f8a2f093ea4619498dae58fc19e5ba3fa38a84cabf92948994609489d566.png"
/>
</div>
</DocumentFragment>
`;
exports[`Media renderer renders image nft correctly 1`] = `
<DocumentFragment>
.c0 {
position: relative;
object-fit: contain;
height: 100%;
width: 100%;
aspect-ratio: 1;
z-index: 1;
}
@media screen and (min-width:1280px) {
}
<img
alt="Azuki #3318"
class="c0"
src="https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/3318/50ed67ad647d0aa0cad0b830d136a677efc2fb72a44587bc35f2a5fb334a7fdf.png"
/>
.c1 {
object-fit: contain;
height: 100%;
aspect-ratio: 1;
border-radius: 20px;
-webkit-filter: blur(25px);
filter: blur(25px);
}
.c0 {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
@media screen and (min-width:1280px) {
.c1 {
-webkit-filter: blur(50px);
filter: blur(50px);
}
}
<div
class="c0"
>
<img
class="c1"
src="https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/3318/50ed67ad647d0aa0cad0b830d136a677efc2fb72a44587bc35f2a5fb334a7fdf.png"
/>
</div>
</DocumentFragment>
`;
import { NftStandard } from 'graphql/data/__generated__/types-and-hooks'
import { MediaType, NftStandard } from 'graphql/data/__generated__/types-and-hooks'
import { SortBy } from 'nft/hooks'
import { SellOrder } from '../sell'
......@@ -87,6 +87,7 @@ export interface GenieAsset {
collectionSymbol?: string
imageUrl?: string
animationUrl?: string
mediaType?: MediaType
marketplace?: Markets
name?: string
priceInfo: PriceInfo
......
import { NftActivityType, NftStandard, OrderStatus } from 'graphql/data/__generated__/types-and-hooks'
import { MediaType, NftActivityType, NftStandard, OrderStatus } from 'graphql/data/__generated__/types-and-hooks'
import { ActivityEvent, CollectionInfoForAsset, GenieAsset, Markets, WalletAsset } from 'nft/types'
export const TEST_NFT_ASSET: GenieAsset = {
......@@ -8,6 +8,7 @@ export const TEST_NFT_ASSET: GenieAsset = {
collectionName: 'Azuki',
imageUrl:
'https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/3318/50ed67ad647d0aa0cad0b830d136a677efc2fb72a44587bc35f2a5fb334a7fdf.png',
mediaType: MediaType.Image,
marketplace: Markets.Opensea,
name: 'Azuki #3318',
priceInfo: {
......@@ -33,6 +34,108 @@ export const TEST_NFT_ASSET: GenieAsset = {
creator: {},
}
export const TEST_VIDEO_NFT_ASSET: GenieAsset = {
id: 'TmZ0QXNzZXQ6MHg0ZTFmNDE2MTNjOTA4NGZkYjllMzRlMTFmYWU5NDEyNDI3NDgwZTU2XzcyMDI=',
address: '0x6c9369dc930fd794ad0af7511f483d936a2ef7f3',
notForSale: false,
collectionName: 'Terraforms by Mathcastles',
imageUrl:
'https://i.seadn.io/gae/tkDbNhjjBZV2PmYaJbJOOigywZCrlcyGRxeQFkZS1YZyihyG5GoWNWj3N9f1T7YVuaxOqdxhfJylC9ejtoCvdgBE932vd7jorVqA?w=500&auto=format',
animationUrl: 'https://openseauserdata.com/files/5af92728200027caa4f3f5ae87a486a7.mp4',
mediaType: MediaType.Video,
marketplace: Markets.Opensea,
name: 'Aku Chapter IV: Aku x Ady #884',
priceInfo: {
ETHPrice: '1295000000000000000',
baseAsset: 'ETH',
baseDecimals: '18',
basePrice: '1295000000000000000',
},
susFlag: false,
tokenId: '1455',
tokenType: NftStandard.Erc721,
collectionIsVerified: false,
totalCount: 9910,
rarity: {
primaryProvider: 'Rarity Sniper',
providers: [
{
rank: 7079,
provider: 'Rarity Sniper',
},
],
},
creator: {},
}
export const TEST_AUDIO_NFT_ASSET: GenieAsset = {
id: 'TmZ0QXNzZXQ6MHg0ZTFmNDE2MTNjOTA4NGZkYjllMzRlMTFmYWU5NDEyNDI3NDgwZTU2XzcyMDI=',
address: '0x37a03d4af1d7046d1126987b20117a0fdcbf6535',
notForSale: false,
collectionName: 'Snoop Dogg on Sound XYZ',
imageUrl:
'https://i.seadn.io/gae/Kze9SBqn_6O0qrHKxspo1gRkkDV2A5EmTeWtvdS-dNxBsvi_wPXUYjc6De0sUC-DYzL093102mUftenWxwWuTelqsdw-ngoBC3o2XFU?w=500&auto=format',
animationUrl: 'https://openseauserdata.com/files/4a22253e44e10baa11484a2e43efefda.mp3',
mediaType: MediaType.Audio,
marketplace: Markets.Opensea,
name: 'Death Row Session: Vol. 2 (420 Edition) #320',
priceInfo: {
ETHPrice: '1295000000000000000',
baseAsset: 'ETH',
baseDecimals: '18',
basePrice: '1295000000000000000',
},
susFlag: false,
tokenId: '680564733841876926926749214863536423232',
tokenType: NftStandard.Erc721,
collectionIsVerified: false,
totalCount: 9910,
rarity: {
primaryProvider: 'Rarity Sniper',
providers: [
{
rank: 7079,
provider: 'Rarity Sniper',
},
],
},
creator: {},
}
export const TEST_EMBEDDED_NFT_ASSET: GenieAsset = {
id: 'TmZ0QXNzZXQ6MHg0ZTFmNDE2MTNjOTA4NGZkYjllMzRlMTFmYWU5NDEyNDI3NDgwZTU2XzcyMDI=',
address: '0x4e1f41613c9084fdb9e34e11fae9412427480e56',
notForSale: false,
collectionName: 'Terraforms by Mathcastles',
imageUrl:
'https://cdn.center.app/v2/1/06ff92279474add6ce06176e2a65447396edf786d169d8ccc03fddfa45ce004f/bb01f8a2f093ea4619498dae58fc19e5ba3fa38a84cabf92948994609489d566.png',
animationUrl: 'https://tokens.mathcastles.xyz/terraforms/token-html/7202',
mediaType: MediaType.Raw,
marketplace: Markets.Opensea,
name: 'Level 13 at {28, 3}',
priceInfo: {
ETHPrice: '1295000000000000000',
baseAsset: 'ETH',
baseDecimals: '18',
basePrice: '1295000000000000000',
},
susFlag: false,
tokenId: '7202',
tokenType: NftStandard.Erc721,
collectionIsVerified: false,
totalCount: 9910,
rarity: {
primaryProvider: 'Rarity Sniper',
providers: [
{
rank: 7079,
provider: 'Rarity Sniper',
},
],
},
creator: { address: '0xe72eb31b59f85b19499a0f3b3260011894fa0d65' },
}
export const TEST_NFT_WALLET_ASSET: WalletAsset = {
id: 'TmZ0QXNzZXQ6RVRIRVJFVU1fMHgyOTY1MkMyZTlEMzY1NjQzNEJjODEzM2M2OTI1OEM4ZDA1MjkwZjQxXzIzNTk=',
imageUrl: 'https://c.neevacdn.net/image/upload/xyz/T96PksTnWGNh79CrzLn-zpYfqRWtD5wME0MBPL_Md6Q.png',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment