diff --git a/src/graphql/data/nft/Details.ts b/src/graphql/data/nft/Details.ts
index f34e8c198b..a1833efb37 100644
--- a/src/graphql/data/nft/Details.ts
+++ b/src/graphql/data/nft/Details.ts
@@ -49,7 +49,7 @@ gql`
}
description
}
- listings(first: 1) {
+ listings(first: 25) {
edges {
node {
address
diff --git a/src/nft/components/details/detailsV2/DataPage.tsx b/src/nft/components/details/detailsV2/DataPage.tsx
index c89318f2ec..24b9783499 100644
--- a/src/nft/components/details/detailsV2/DataPage.tsx
+++ b/src/nft/components/details/detailsV2/DataPage.tsx
@@ -9,13 +9,14 @@ import { DataPageHeader } from './DataPageHeader'
import { DataPageTable } from './DataPageTable'
import { DataPageTraits } from './DataPageTraits'
-const DataPageContainer = styled(Column)`
+const DataPagePaddingContainer = styled.div`
padding: 24px 64px;
height: 100vh;
width: 100%;
- gap: 36px;
- max-width: ${({ theme }) => theme.maxWidth};
- margin: 0 auto;
+
+ @media screen and (max-width: ${BREAKPOINTS.md}px) {
+ height: 100%;
+ }
@media screen and (max-width: ${BREAKPOINTS.sm}px) {
padding: 24px 48px;
@@ -26,6 +27,14 @@ const DataPageContainer = styled(Column)`
}
`
+const DataPageContainer = styled(Column)`
+ height: 100%;
+ width: 100%;
+ gap: 36px;
+ max-width: ${({ theme }) => theme.maxWidth};
+ margin: 0 auto;
+`
+
const ContentContainer = styled(Row)`
gap: 24px;
padding-bottom: 45px;
@@ -50,7 +59,7 @@ export const DataPage = ({ asset }: { asset: GenieAsset }) => {
{!!asset.traits?.length && }
-
+
)
diff --git a/src/nft/components/details/detailsV2/DataPageTable.test.tsx b/src/nft/components/details/detailsV2/DataPageTable.test.tsx
new file mode 100644
index 0000000000..c9fc63996c
--- /dev/null
+++ b/src/nft/components/details/detailsV2/DataPageTable.test.tsx
@@ -0,0 +1,23 @@
+import { TEST_NFT_ASSET, TEST_OFFER, TEST_SELL_ORDER } from 'test-utils/nft/fixtures'
+import { render } from 'test-utils/render'
+
+import { ListingsTableContent } from './ListingsTableContent'
+import { OffersTableContent } from './OffersTableContent'
+
+it('data page offers table content loads with a given asset', () => {
+ const assetWithOffer = {
+ ...TEST_NFT_ASSET,
+ offers: [TEST_OFFER],
+ }
+ const { asFragment } = render()
+ expect(asFragment()).toMatchSnapshot()
+})
+
+it('data page listings table content loads with a given asset', () => {
+ const assetWithOrder = {
+ ...TEST_NFT_ASSET,
+ sellorders: [TEST_SELL_ORDER],
+ }
+ const { asFragment } = render()
+ expect(asFragment()).toMatchSnapshot()
+})
diff --git a/src/nft/components/details/detailsV2/DataPageTable.tsx b/src/nft/components/details/detailsV2/DataPageTable.tsx
index 3592e1014d..5c4637d8ff 100644
--- a/src/nft/components/details/detailsV2/DataPageTable.tsx
+++ b/src/nft/components/details/detailsV2/DataPageTable.tsx
@@ -1,45 +1,50 @@
import { Trans } from '@lingui/macro'
+import { GenieAsset } from 'nft/types'
+import { useMemo } from 'react'
import { ActivityTableContent } from './ActivityTableContent'
import { ListingsTableContent } from './ListingsTableContent'
import { OffersTableContent } from './OffersTableContent'
import { Tab, TabbedComponent } from './TabbedComponent'
-enum TableTabsKeys {
+export enum TableTabsKeys {
Activity = 'activity',
Offers = 'offers',
Listings = 'listings',
}
-const TableTabs: Map = new Map([
- [
- TableTabsKeys.Activity,
- {
- title: Activity,
- key: TableTabsKeys.Activity,
- content: ,
- },
- ],
- [
- TableTabsKeys.Offers,
- {
- title: Offers,
- key: TableTabsKeys.Offers,
- content: ,
- count: 11, // TODO Replace Placeholder with real data
- },
- ],
- [
- TableTabsKeys.Listings,
- {
- title: Listings,
- key: TableTabsKeys.Listings,
- content: ,
- count: 11, // TODO Replace Placeholder with real data
- },
- ],
-])
-
-export const DataPageTable = () => {
+export const DataPageTable = ({ asset }: { asset: GenieAsset }) => {
+ const TableTabs: Map = useMemo(
+ () =>
+ new Map([
+ [
+ TableTabsKeys.Activity,
+ {
+ title: Activity,
+ key: TableTabsKeys.Activity,
+ content: ,
+ },
+ ],
+ [
+ TableTabsKeys.Offers,
+ {
+ title: Offers,
+ key: TableTabsKeys.Offers,
+ content: ,
+ count: 11, // TODO Replace Placeholder with real data
+ },
+ ],
+ [
+ TableTabsKeys.Listings,
+ {
+ title: Listings,
+ key: TableTabsKeys.Listings,
+ content: ,
+ count: asset.sellorders?.length,
+ },
+ ],
+ ]),
+ [asset]
+ )
return
}
diff --git a/src/nft/components/details/detailsV2/DataPageTraits.tsx b/src/nft/components/details/detailsV2/DataPageTraits.tsx
index 80701b094c..f24ae549c7 100644
--- a/src/nft/components/details/detailsV2/DataPageTraits.tsx
+++ b/src/nft/components/details/detailsV2/DataPageTraits.tsx
@@ -7,8 +7,8 @@ import { GenieAsset } from 'nft/types'
import { useMemo } from 'react'
import styled from 'styled-components/macro'
import { BREAKPOINTS, ThemedText } from 'theme'
-import { opacify } from 'theme/utils'
+import { Scrim } from './shared'
import { Tab, TabbedComponent } from './TabbedComponent'
import { TraitRow } from './TraitRow'
@@ -45,26 +45,6 @@ const TraitRowScrollableContainer = styled.div`
${ScrollBarStyles}
`
-// Scrim that fades out the top and bottom of the scrollable container, isBottom changes the direction and placement of the fade
-const Scrim = styled.div<{ isBottom?: boolean }>`
- position: absolute;
- height: 88px;
- left: 0px;
- right: 6px;
-
- ${({ isBottom }) =>
- isBottom
- ? 'bottom: 0px'
- : `
- top: 0px;
- transform: matrix(1, 0, 0, -1, 0, 0);
- `};
-
- background: ${({ theme }) =>
- `linear-gradient(180deg, ${opacify(0, theme.backgroundSurface)} 0%, ${theme.backgroundSurface} 100%)`};
- display: flex;
-`
-
const TraitsContent = ({ asset }: { asset: GenieAsset }) => {
const { userCanScroll, scrollRef, scrollProgress, scrollHandler } = useSubscribeScrollState()
diff --git a/src/nft/components/details/detailsV2/ListingsTableContent.tsx b/src/nft/components/details/detailsV2/ListingsTableContent.tsx
index 374b57eb95..ced9994146 100644
--- a/src/nft/components/details/detailsV2/ListingsTableContent.tsx
+++ b/src/nft/components/details/detailsV2/ListingsTableContent.tsx
@@ -1,5 +1,25 @@
-import { TableContentContainer } from './shared'
+import { Trans } from '@lingui/macro'
+import { NftStandard } from 'graphql/data/__generated__/types-and-hooks'
+import { AddToBagIcon } from 'nft/components/icons'
+import { useIsMobile } from 'nft/hooks'
+import { GenieAsset } from 'nft/types'
+import { useTheme } from 'styled-components/macro'
-export const ListingsTableContent = () => {
- return Listings Content
+import { TableTabsKeys } from './DataPageTable'
+import { TableContentComponent } from './TableContentComponent'
+import { ContentRow, HeaderRow } from './TableRowComponent'
+
+export const ListingsTableContent = ({ asset }: { asset: GenieAsset }) => {
+ const isMobile = useIsMobile()
+ const theme = useTheme()
+ const headers =
+ const contentRows = (asset.sellorders || []).map((offer, index) => (
+ : Add to Bag}
+ is1155={asset.tokenType === NftStandard.Erc1155}
+ />
+ ))
+ return
}
diff --git a/src/nft/components/details/detailsV2/NftDetails.tsx b/src/nft/components/details/detailsV2/NftDetails.tsx
index 8f56c1c94d..93f3756af7 100644
--- a/src/nft/components/details/detailsV2/NftDetails.tsx
+++ b/src/nft/components/details/detailsV2/NftDetails.tsx
@@ -23,6 +23,7 @@ const DetailsBackground = styled.div<{ backgroundImage: string }>`
const DetailsContentContainer = styled.div`
z-index: ${Z_INDEX.hover};
+ width: 100%;
`
export const NftDetails = ({ asset, collection }: NftDetailsProps) => {
diff --git a/src/nft/components/details/detailsV2/OffersTableContent.tsx b/src/nft/components/details/detailsV2/OffersTableContent.tsx
index 14c302d75b..1fc90508ec 100644
--- a/src/nft/components/details/detailsV2/OffersTableContent.tsx
+++ b/src/nft/components/details/detailsV2/OffersTableContent.tsx
@@ -1,5 +1,28 @@
-import { TableContentContainer } from './shared'
+import { Trans } from '@lingui/macro'
+import { NftStandard } from 'graphql/data/__generated__/types-and-hooks'
+import { useIsMobile } from 'nft/hooks'
+import { GenieAsset } from 'nft/types'
+import { Check } from 'react-feather'
+import { useTheme } from 'styled-components/macro'
+import { TEST_OFFER } from 'test-utils/nft/fixtures'
-export const OffersTableContent = () => {
- return Offers Content
+import { TableTabsKeys } from './DataPageTable'
+import { TableContentComponent } from './TableContentComponent'
+import { ContentRow, HeaderRow } from './TableRowComponent'
+
+export const OffersTableContent = ({ asset }: { asset: GenieAsset }) => {
+ // TODO(NFT-1189) Replace with real offer data when BE supports
+ const mockOffers = new Array(11).fill(TEST_OFFER)
+ const isMobile = useIsMobile()
+ const theme = useTheme()
+ const headers =
+ const contentRows = mockOffers.map((offer, index) => (
+ : Accept}
+ is1155={asset.tokenType === NftStandard.Erc1155}
+ />
+ ))
+ return
}
diff --git a/src/nft/components/details/detailsV2/TableContentComponent.tsx b/src/nft/components/details/detailsV2/TableContentComponent.tsx
new file mode 100644
index 0000000000..79a713af51
--- /dev/null
+++ b/src/nft/components/details/detailsV2/TableContentComponent.tsx
@@ -0,0 +1,55 @@
+import { ScrollBarStyles } from 'components/Common'
+import { useSubscribeScrollState } from 'nft/hooks'
+import styled from 'styled-components/macro'
+
+import { TableTabsKeys } from './DataPageTable'
+import { Scrim } from './shared'
+
+const TableRowsContainer = styled.div`
+ position: relative;
+`
+
+const TableRowScrollableContainer = styled.div`
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 264px;
+
+ ${ScrollBarStyles}
+`
+
+const TableHeaderRowContainer = styled.div<{ userCanScroll: boolean }>`
+ margin-right: ${({ userCanScroll }) => (userCanScroll ? '11px' : '0')};
+`
+
+const TableRowContainer = styled.div`
+ border-bottom: 1px solid ${({ theme }) => theme.backgroundOutline};
+
+ &:last-child {
+ border-bottom: none;
+ }
+`
+
+interface TableContentComponentProps {
+ headerRow: React.ReactNode
+ contentRows: React.ReactNode[]
+ type: TableTabsKeys
+}
+
+export const TableContentComponent = ({ headerRow, contentRows, type }: TableContentComponentProps) => {
+ const { userCanScroll, scrollRef, scrollProgress, scrollHandler } = useSubscribeScrollState()
+
+ return (
+ <>
+ {headerRow}
+
+ {scrollProgress > 0 && }
+
+ {contentRows.map((row, index) => (
+ {row}
+ ))}
+
+ {userCanScroll && scrollProgress !== 100 && }
+
+ >
+ )
+}
diff --git a/src/nft/components/details/detailsV2/TableRowComponent.tsx b/src/nft/components/details/detailsV2/TableRowComponent.tsx
new file mode 100644
index 0000000000..6f3939b0d6
--- /dev/null
+++ b/src/nft/components/details/detailsV2/TableRowComponent.tsx
@@ -0,0 +1,156 @@
+import { Trans } from '@lingui/macro'
+import { formatCurrencyAmount, NumberType } from '@uniswap/conedison/format'
+import { useWeb3React } from '@web3-react/core'
+import { OpacityHoverState } from 'components/Common'
+import Row from 'components/Row'
+import { OrderType } from 'graphql/data/__generated__/types-and-hooks'
+import { useScreenSize } from 'hooks/useScreenSize'
+import { useStablecoinValue } from 'hooks/useStablecoinPrice'
+import useNativeCurrency from 'lib/hooks/useNativeCurrency'
+import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
+import { HomeSearchIcon } from 'nft/components/icons'
+import { Offer, SellOrder } from 'nft/types'
+import { formatEth, getMarketplaceIcon, timeUntil } from 'nft/utils'
+import styled from 'styled-components/macro'
+import { BREAKPOINTS, ExternalLink, ThemedText } from 'theme'
+import { shortenAddress } from 'utils'
+
+import { TableTabsKeys } from './DataPageTable'
+
+const TableCell = styled.div<{ $flex?: number; $justifyContent?: string; $color?: string; hideOnSmall?: boolean }>`
+ display: flex;
+ flex: ${({ $flex }) => $flex ?? 1};
+ justify-content: ${({ $justifyContent }) => $justifyContent};
+ color: ${({ $color }) => $color};
+ flex-shrink: 0;
+
+ @media screen and (max-width: ${BREAKPOINTS.sm}px) {
+ display: ${({ hideOnSmall }) => (hideOnSmall ? 'none' : 'flex')};
+ }
+`
+
+const ActionButton = styled.div`
+ cursor: pointer;
+ white-space: nowrap;
+ ${OpacityHoverState}
+`
+
+const USDPrice = styled(ThemedText.BodySmall)`
+ color: ${({ theme }) => theme.textSecondary};
+ line-height: 20px;
+
+ @media screen and (max-width: ${BREAKPOINTS.sm}px) {
+ display: none;
+ }
+
+ @media screen and (min-width: ${BREAKPOINTS.lg}px) and (max-width: ${BREAKPOINTS.xl - 1}px) {
+ display: none;
+ }
+`
+
+const Link = styled(ExternalLink)`
+ height: 20px;
+`
+
+const PriceCell = ({ price }: { price: number }) => {
+ const { chainId } = useWeb3React()
+ const nativeCurrency = useNativeCurrency(chainId)
+ const parsedAmount = tryParseCurrencyAmount(price.toString(), nativeCurrency)
+ const usdValue = useStablecoinValue(parsedAmount)
+ return (
+
+
+ {formatEth(price)}
+
+ {formatCurrencyAmount(usdValue, NumberType.FiatTokenPrice)}
+
+ )
+}
+
+export const HeaderRow = ({ type, is1155 }: { type: TableTabsKeys; is1155?: boolean }) => {
+ const screenSize = useScreenSize()
+ const isMobile = !screenSize['sm']
+ const isLargeScreen = screenSize['lg'] && !screenSize['xl']
+ const reducedPriceWidth = isMobile || isLargeScreen
+
+ return (
+
+
+
+
+ Price
+
+
+ {is1155 && (
+
+
+ Quantity
+
+
+ )}
+ {(type === TableTabsKeys.Offers || is1155) && (
+
+
+ {type === TableTabsKeys.Offers ? From : Seller}
+
+
+ )}
+
+
+ Expires in
+
+
+ {/* An empty cell is needed in the headers for proper vertical alignment with the action buttons */}
+
+
+ )
+}
+
+export const ContentRow = ({
+ content,
+ buttonCTA,
+ is1155,
+}: {
+ content: Offer | SellOrder
+ buttonCTA: React.ReactNode
+ is1155?: boolean
+}) => {
+ const screenSize = useScreenSize()
+ const isMobile = !screenSize['sm']
+ const date = content.endAt && new Date(content.endAt)
+ const isSellOrder = 'type' in content && content.type === OrderType.Listing
+ const reducedPriceWidth = isMobile || (screenSize['lg'] && !screenSize['xl'])
+
+ return (
+
+ {getMarketplaceIcon(content.marketplace, '20')}
+ {content.price && (
+
+
+
+ )}
+ {is1155 && (
+
+ {content.quantity}
+
+ )}
+ {(!isSellOrder || is1155) && (
+
+
+ {shortenAddress(content.maker)}
+
+
+ )}
+
+
+ {date ? timeUntil(date) : Never}
+
+
+
+
+ {buttonCTA}
+
+
+
+ )
+}
diff --git a/src/nft/components/details/detailsV2/__snapshots__/DataPage.test.tsx.snap b/src/nft/components/details/detailsV2/__snapshots__/DataPage.test.tsx.snap
index a959f678aa..052e89b8cd 100644
--- a/src/nft/components/details/detailsV2/__snapshots__/DataPage.test.tsx.snap
+++ b/src/nft/components/details/detailsV2/__snapshots__/DataPage.test.tsx.snap
@@ -142,6 +142,7 @@ exports[`placeholder containers load 1`] = `
.c18 {
background: #FFFFFF;
+ border: 1px solid #D2D9EE;
border-radius: 16px;
padding: 16px 20px;
width: 100%;
@@ -287,8 +288,7 @@ exports[`placeholder containers load 1`] = `
}
.c1 {
- padding: 24px 64px;
- height: 100vh;
+ height: 100%;
width: 100%;
gap: 36px;
max-width: 1200px;
@@ -320,18 +320,6 @@ exports[`placeholder containers load 1`] = `
}
}
-@media screen and (max-width:640px) {
- .c1 {
- padding: 24px 48px;
- }
-}
-
-@media screen and (max-width:396px) {
- .c1 {
- padding: 24px 20px;
- }
-}
-
@media screen and (max-width:1024px) {
.c16 {
-webkit-flex-wrap: wrap;
@@ -469,11 +457,6 @@ exports[`placeholder containers load 1`] = `
class="c2 c21"
>
Listings
-
- 10+
-
diff --git a/src/nft/components/details/detailsV2/__snapshots__/DataPageTable.test.tsx.snap b/src/nft/components/details/detailsV2/__snapshots__/DataPageTable.test.tsx.snap
new file mode 100644
index 0000000000..19e8986ce1
--- /dev/null
+++ b/src/nft/components/details/detailsV2/__snapshots__/DataPageTable.test.tsx.snap
@@ -0,0 +1,2318 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`data page listings table content loads with a given asset 1`] = `
+
+ .c1 {
+ box-sizing: border-box;
+ margin: 0;
+ min-width: 0;
+ padding: 6px 6px 6px 0px;
+}
+
+.c2 {
+ width: 100%;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ padding: 6px 6px 6px 0px;
+ gap: 12px;
+}
+
+.c4 {
+ color: #7780A0;
+}
+
+.c0 {
+ margin-right: 0;
+}
+
+.c3 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c5 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+@media screen and (max-width:640px) {
+ .c3 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c5 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+
+}
+
+@media screen and (max-width:640px) {
+
+}
+
+@media screen and (min-width:1024px) and (max-width:1279px) {
+
+}
+
+
+ .c3 {
+ box-sizing: border-box;
+ margin: 0;
+ min-width: 0;
+ padding: 16px 6px 16px 0px;
+}
+
+.c8 {
+ box-sizing: border-box;
+ margin: 0;
+ min-width: 0;
+}
+
+.c4 {
+ width: 100%;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ padding: 16px 6px 16px 0px;
+ gap: 12px;
+}
+
+.c9 {
+ width: 100%;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ gap: 8px;
+}
+
+.c15 {
+ color: #7780A0;
+}
+
+.c10 {
+ color: #0D111C;
+}
+
+.c5 {
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ cursor: pointer;
+ -webkit-transition-duration: 125ms;
+ transition-duration: 125ms;
+ color: #FB118E;
+ stroke: #FB118E;
+ font-weight: 500;
+}
+
+.c5:hover {
+ opacity: 0.6;
+}
+
+.c5:active {
+ opacity: 0.4;
+}
+
+.c0 {
+ position: relative;
+}
+
+.c1 {
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 264px;
+ -webkit-scrollbar-width: thin;
+ -moz-scrollbar-width: thin;
+ -ms-scrollbar-width: thin;
+ scrollbar-width: thin;
+ -webkit-scrollbar-color: #D2D9EE transparent;
+ -moz-scrollbar-color: #D2D9EE transparent;
+ -ms-scrollbar-color: #D2D9EE transparent;
+ scrollbar-color: #D2D9EE transparent;
+ height: 100%;
+}
+
+.c1::-webkit-scrollbar {
+ background: transparent;
+ width: 4px;
+ overflow-y: scroll;
+}
+
+.c1::-webkit-scrollbar-thumb {
+ background: #D2D9EE;
+ border-radius: 8px;
+}
+
+.c2 {
+ border-bottom: 1px solid #D2D9EE;
+}
+
+.c2:last-child {
+ border-bottom: none;
+}
+
+.c7 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c12 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c13 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c14 {
+ cursor: pointer;
+ white-space: nowrap;
+ -webkit-transition: opacity 250ms ease;
+ transition: opacity 250ms ease;
+}
+
+.c14:hover {
+ opacity: 0.6;
+}
+
+.c14:active {
+ opacity: 0.4;
+}
+
+.c11 {
+ color: #7780A0;
+ line-height: 20px;
+}
+
+.c6 {
+ height: 20px;
+}
+
+@media screen and (max-width:640px) {
+ .c7 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c12 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c13 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c11 {
+ display: none;
+ }
+}
+
+@media screen and (min-width:1024px) and (max-width:1279px) {
+ .c11 {
+ display: none;
+ }
+}
+
+
+
+`;
+
+exports[`data page offers table content loads with a given asset 1`] = `
+
+ .c1 {
+ box-sizing: border-box;
+ margin: 0;
+ min-width: 0;
+ padding: 6px 6px 6px 0px;
+}
+
+.c2 {
+ width: 100%;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ padding: 6px 6px 6px 0px;
+ gap: 12px;
+}
+
+.c4 {
+ color: #7780A0;
+}
+
+.c0 {
+ margin-right: 0;
+}
+
+.c3 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c5 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c6 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+@media screen and (max-width:640px) {
+ .c3 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c5 {
+ display: none;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c6 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+
+}
+
+@media screen and (max-width:640px) {
+
+}
+
+@media screen and (min-width:1024px) and (max-width:1279px) {
+
+}
+
+
+ .c3 {
+ box-sizing: border-box;
+ margin: 0;
+ min-width: 0;
+ padding: 16px 6px 16px 0px;
+}
+
+.c8 {
+ box-sizing: border-box;
+ margin: 0;
+ min-width: 0;
+}
+
+.c4 {
+ width: 100%;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ padding: 16px 6px 16px 0px;
+ gap: 12px;
+}
+
+.c9 {
+ width: 100%;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ gap: 8px;
+}
+
+.c16 {
+ color: #7780A0;
+}
+
+.c10 {
+ color: #0D111C;
+}
+
+.c5 {
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ cursor: pointer;
+ -webkit-transition-duration: 125ms;
+ transition-duration: 125ms;
+ color: #FB118E;
+ stroke: #FB118E;
+ font-weight: 500;
+}
+
+.c5:hover {
+ opacity: 0.6;
+}
+
+.c5:active {
+ opacity: 0.4;
+}
+
+.c0 {
+ position: relative;
+}
+
+.c1 {
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 264px;
+ -webkit-scrollbar-width: thin;
+ -moz-scrollbar-width: thin;
+ -ms-scrollbar-width: thin;
+ scrollbar-width: thin;
+ -webkit-scrollbar-color: #D2D9EE transparent;
+ -moz-scrollbar-color: #D2D9EE transparent;
+ -ms-scrollbar-color: #D2D9EE transparent;
+ scrollbar-color: #D2D9EE transparent;
+ height: 100%;
+}
+
+.c1::-webkit-scrollbar {
+ background: transparent;
+ width: 4px;
+ overflow-y: scroll;
+}
+
+.c1::-webkit-scrollbar-thumb {
+ background: #D2D9EE;
+ border-radius: 8px;
+}
+
+.c2 {
+ border-bottom: 1px solid #D2D9EE;
+}
+
+.c2:last-child {
+ border-bottom: none;
+}
+
+.c7 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c12 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c13 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c14 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c15 {
+ cursor: pointer;
+ white-space: nowrap;
+ -webkit-transition: opacity 250ms ease;
+ transition: opacity 250ms ease;
+}
+
+.c15:hover {
+ opacity: 0.6;
+}
+
+.c15:active {
+ opacity: 0.4;
+}
+
+.c11 {
+ color: #7780A0;
+ line-height: 20px;
+}
+
+.c6 {
+ height: 20px;
+}
+
+@media screen and (max-width:640px) {
+ .c7 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c12 {
+ display: none;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c13 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c14 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+@media screen and (max-width:640px) {
+ .c11 {
+ display: none;
+ }
+}
+
+@media screen and (min-width:1024px) and (max-width:1279px) {
+ .c11 {
+ display: none;
+ }
+}
+
+
+
+`;
diff --git a/src/nft/components/details/detailsV2/__snapshots__/DataPageTraits.test.tsx.snap b/src/nft/components/details/detailsV2/__snapshots__/DataPageTraits.test.tsx.snap
index a416764c69..8d4a93d749 100644
--- a/src/nft/components/details/detailsV2/__snapshots__/DataPageTraits.test.tsx.snap
+++ b/src/nft/components/details/detailsV2/__snapshots__/DataPageTraits.test.tsx.snap
@@ -67,6 +67,7 @@ exports[`data page trait component does not load with asset with no traits 1`] =
.c0 {
background: #FFFFFF;
+ border: 1px solid #D2D9EE;
border-radius: 16px;
padding: 16px 20px;
width: 100%;
diff --git a/src/nft/components/details/detailsV2/shared.ts b/src/nft/components/details/detailsV2/shared.ts
index 8ff2e797a1..c84791fb50 100644
--- a/src/nft/components/details/detailsV2/shared.ts
+++ b/src/nft/components/details/detailsV2/shared.ts
@@ -1,7 +1,9 @@
import styled, { css } from 'styled-components/macro'
+import { opacify } from 'theme/utils'
export const containerStyles = css`
background: ${({ theme }) => theme.backgroundSurface};
+ border: 1px solid ${({ theme }) => theme.backgroundOutline};
border-radius: 16px;
padding: 16px 20px;
width: 100%;
@@ -11,3 +13,24 @@ export const containerStyles = css`
export const TableContentContainer = styled.div`
height: 568px;
`
+
+// Scrim that fades out the top and bottom of the scrollable container, isBottom changes the direction and placement of the fade
+export const Scrim = styled.div<{ isBottom?: boolean }>`
+ position: absolute;
+ pointer-events: none;
+ height: 88px;
+ left: 0px;
+ right: 6px;
+
+ ${({ isBottom }) =>
+ isBottom
+ ? 'bottom: 0px'
+ : `
+ top: 0px;
+ transform: matrix(1, 0, 0, -1, 0, 0);
+ `};
+
+ background: ${({ theme }) =>
+ `linear-gradient(180deg, ${opacify(0, theme.backgroundSurface)} 0%, ${theme.backgroundSurface} 100%)`};
+ display: flex;
+`
diff --git a/src/nft/components/icons.tsx b/src/nft/components/icons.tsx
index d9b357bf59..a1453b52eb 100644
--- a/src/nft/components/icons.tsx
+++ b/src/nft/components/icons.tsx
@@ -1351,6 +1351,35 @@ export const UniswapMagentaIcon = (props: SVGProps) => (
)
+export const HomeSearchIcon = (props: SVGProps) => (
+
+)
+
+export const AddToBagIcon = (props: SVGProps) => (
+
+)
export const HandHoldingDollarIcon = (props: SVGProps) => (