Commit 63d0290a authored by Charles Bachmeier's avatar Charles Bachmeier Committed by GitHub

feat: [DetailsV2] more shared component content (#6420)

* add page break and placeholder files

* container layout

* description tabs

* add table tabs

* mobile wrap

* remove todo

* adaptive padding

* add extensible tabbed component

* add new file

* add snapshot test for empty data page

* update snapshot

* add new snapshot

* undo unrelated snapshot change

* draft: details v2 containers

* Revert "draft: details v2 containers"

This reverts commit 7c6580c974a7c749490c909778757a51a13b8e07.

* uniform padding and single tab styling

* update snapshot

* update default tab behaviour

* add trait bubble

* working chevrons

* shared bubble tab title

* add placeholder nums for offers and listings

* remove styles and update snapshot

* remove chevron and update snapshot

* use test asset for snapshot

* max width

* convert to map with keys

* remove bubbletext helper

* remove extra brace

* use styled components and memo

* update trait component height

* update snapshot

* Add count field to Tab

* add comment

* update snapshot

* move styled component to shared folder

* update snapshot

---------
Co-authored-by: default avatarCharles Bachmeier <charlie@genie.xyz>
Co-authored-by: default avatarJack Short <john.short.tj@gmail.com>
parent 963121f1
import { TableContentContainer } from './shared'
export const ActivityTableContent = () => { export const ActivityTableContent = () => {
return <div>Activity Content</div> return <TableContentContainer>Activity Content</TableContentContainer>
} }
import { TEST_NFT_ASSET } from 'test-utils/constants'
import { render } from 'test-utils/render' import { render } from 'test-utils/render'
import { DataPage } from './DataPage' import { DataPage } from './DataPage'
it('placeholder containers load', () => { it('placeholder containers load', () => {
const { asFragment } = render(<DataPage />) const { asFragment } = render(<DataPage asset={TEST_NFT_ASSET} />)
expect(asFragment()).toMatchSnapshot() expect(asFragment()).toMatchSnapshot()
}) })
import Column from 'components/Column' import Column from 'components/Column'
import Row from 'components/Row' import Row from 'components/Row'
import { GenieAsset } from 'nft/types'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import { BREAKPOINTS } from 'theme' import { BREAKPOINTS } from 'theme'
...@@ -37,15 +38,16 @@ const ContentContainer = styled(Row)` ...@@ -37,15 +38,16 @@ const ContentContainer = styled(Row)`
const LeftColumn = styled(Column)` const LeftColumn = styled(Column)`
gap: 24px; gap: 24px;
width: 100%; width: 100%;
align-self: flex-start;
` `
export const DataPage = () => { export const DataPage = ({ asset }: { asset: GenieAsset }) => {
return ( return (
<DataPageContainer> <DataPageContainer>
<DataPageHeader /> <DataPageHeader />
<ContentContainer> <ContentContainer>
<LeftColumn> <LeftColumn>
<DataPageTraits /> <DataPageTraits asset={asset} />
<DataPageDescription /> <DataPageDescription />
</LeftColumn> </LeftColumn>
<DataPageTable /> <DataPageTable />
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import styled from 'styled-components/macro'
import { Tab, TabbedComponent } from './TabbedComponent' import { Tab, TabbedComponent } from './TabbedComponent'
const DescriptionContentContainer = styled.div`
height: 252px;
`
const DescriptionContent = () => { const DescriptionContent = () => {
return <div>Description Content</div> return <DescriptionContentContainer>Description Content</DescriptionContentContainer>
} }
const DetailsContent = () => { const DetailsContent = () => {
return <div>Details Content</div> return <DescriptionContentContainer>Details Content</DescriptionContentContainer>
} }
enum DescriptionTabsKeys { enum DescriptionTabsKeys {
...@@ -35,5 +40,5 @@ const DescriptionTabs: Map<string, Tab> = new Map([ ...@@ -35,5 +40,5 @@ const DescriptionTabs: Map<string, Tab> = new Map([
]) ])
export const DataPageDescription = () => { export const DataPageDescription = () => {
return <TabbedComponent tabs={DescriptionTabs} style={{ height: '288px' }} /> return <TabbedComponent tabs={DescriptionTabs} />
} }
...@@ -26,6 +26,7 @@ const TableTabs: Map<string, Tab> = new Map([ ...@@ -26,6 +26,7 @@ const TableTabs: Map<string, Tab> = new Map([
title: <Trans>Offers</Trans>, title: <Trans>Offers</Trans>,
key: TableTabsKeys.Offers, key: TableTabsKeys.Offers,
content: <OffersTableContent />, content: <OffersTableContent />,
count: 11, // TODO Replace Placeholder with real data
}, },
], ],
[ [
...@@ -34,10 +35,11 @@ const TableTabs: Map<string, Tab> = new Map([ ...@@ -34,10 +35,11 @@ const TableTabs: Map<string, Tab> = new Map([
title: <Trans>Listings</Trans>, title: <Trans>Listings</Trans>,
key: TableTabsKeys.Listings, key: TableTabsKeys.Listings,
content: <ListingsTableContent />, content: <ListingsTableContent />,
count: 11, // TODO Replace Placeholder with real data
}, },
], ],
]) ])
export const DataPageTable = () => { export const DataPageTable = () => {
return <TabbedComponent tabs={TableTabs} style={{ height: '604px' }} /> return <TabbedComponent tabs={TableTabs} />
} }
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { GenieAsset } from 'nft/types'
import { useMemo } from 'react'
import styled from 'styled-components/macro'
import { Tab, TabbedComponent } from './TabbedComponent' import { Tab, TabbedComponent } from './TabbedComponent'
const TraitsContentContainer = styled.div`
height: 492px;
`
const TraitsContent = () => { const TraitsContent = () => {
return <div>Traits Content</div> return <TraitsContentContainer>Traits Content</TraitsContentContainer>
} }
enum TraitTabsKeys { enum TraitTabsKeys {
Traits = 'traits', Traits = 'traits',
} }
const TraitTabs: Map<string, Tab> = new Map([ export const DataPageTraits = ({ asset }: { asset: GenieAsset }) => {
[ const TraitTabs: Map<string, Tab> = useMemo(
TraitTabsKeys.Traits, () =>
{ new Map([
title: <Trans>Traits</Trans>, [
key: TraitTabsKeys.Traits, TraitTabsKeys.Traits,
content: <TraitsContent />, {
}, title: <Trans>Traits</Trans>,
], key: TraitTabsKeys.Traits,
]) content: <TraitsContent />,
count: asset.traits?.length,
export const DataPageTraits = () => { },
return <TabbedComponent tabs={TraitTabs} style={{ height: '528px' }} /> ],
]),
[asset.traits?.length]
)
return <TabbedComponent tabs={TraitTabs} />
} }
import { TableContentContainer } from './shared'
export const ListingsTableContent = () => { export const ListingsTableContent = () => {
return <div>Listings Content</div> return <TableContentContainer>Listings Content</TableContentContainer>
} }
...@@ -18,7 +18,7 @@ export const NftDetails = ({ asset, collection }: NftDetailsProps) => { ...@@ -18,7 +18,7 @@ export const NftDetails = ({ asset, collection }: NftDetailsProps) => {
<LandingPage> <LandingPage>
Details page for {asset.name} from {collection.collectionName} Details page for {asset.name} from {collection.collectionName}
</LandingPage> </LandingPage>
<DataPage /> <DataPage asset={asset} />
</> </>
) )
} }
import { TableContentContainer } from './shared'
export const OffersTableContent = () => { export const OffersTableContent = () => {
return <div>Offers Content</div> return <TableContentContainer>Offers Content</TableContentContainer>
} }
...@@ -6,8 +6,6 @@ import { ThemedText } from 'theme' ...@@ -6,8 +6,6 @@ import { ThemedText } from 'theme'
import { containerStyles } from './shared' import { containerStyles } from './shared'
const TabbedComponentContainer = styled.div` const TabbedComponentContainer = styled.div`
height: 288px;
${containerStyles} ${containerStyles}
` `
...@@ -23,29 +21,37 @@ const Tab = styled(ThemedText.SubHeader)<{ isActive: boolean; numTabs: number }> ...@@ -23,29 +21,37 @@ const Tab = styled(ThemedText.SubHeader)<{ isActive: boolean; numTabs: number }>
cursor: ${({ numTabs }) => (numTabs > 1 ? 'pointer' : 'default')}; cursor: ${({ numTabs }) => (numTabs > 1 ? 'pointer' : 'default')};
&:hover { &:hover {
opacity: ${({ numTabs, theme }) => numTabs > 1 && theme.opacity.hover}}; opacity: ${({ numTabs, theme }) => numTabs > 1 && theme.opacity.hover};
} }
` `
const TabNumBubble = styled(ThemedText.UtilityBadge)`
background: ${({ theme }) => theme.backgroundOutline};
border-radius: 4px;
padding: 2px 4px;
color: ${({ theme }) => theme.textSecondary};
line-height: 12px;
`
export interface Tab { export interface Tab {
title: React.ReactNode title: React.ReactNode
key: string key: string
content: JSX.Element content: JSX.Element
count?: number
} }
interface TabbedComponentProps { interface TabbedComponentProps {
tabs: Map<string, Tab> tabs: Map<string, Tab>
defaultTabKey?: string defaultTabKey?: string
style?: React.CSSProperties
} }
export const TabbedComponent = ({ tabs, defaultTabKey, style }: TabbedComponentProps) => { export const TabbedComponent = ({ tabs, defaultTabKey }: TabbedComponentProps) => {
const firstKey = tabs.keys().next().value const firstKey = tabs.keys().next().value
const [activeKey, setActiveKey] = useState(defaultTabKey ?? firstKey) const [activeKey, setActiveKey] = useState(defaultTabKey ?? firstKey)
const activeContent = tabs.get(activeKey)?.content const activeContent = tabs.get(activeKey)?.content
const tabArray = Array.from(tabs.values()) const tabArray = Array.from(tabs.values())
return ( return (
<TabbedComponentContainer style={style}> <TabbedComponentContainer>
<TabsRow> <TabsRow>
{tabArray.map((tab) => ( {tabArray.map((tab) => (
<Tab <Tab
...@@ -54,7 +60,10 @@ export const TabbedComponent = ({ tabs, defaultTabKey, style }: TabbedComponentP ...@@ -54,7 +60,10 @@ export const TabbedComponent = ({ tabs, defaultTabKey, style }: TabbedComponentP
onClick={() => setActiveKey(tab.key)} onClick={() => setActiveKey(tab.key)}
key={tab.key} key={tab.key}
> >
{tab.title} <Row gap="8px">
{tab.title}
{!!tab.count && <TabNumBubble>{tab.count > 10 ? '10+' : tab.count}</TabNumBubble>}
</Row>
</Tab> </Tab>
))} ))}
</TabsRow> </TabsRow>
......
...@@ -25,6 +25,24 @@ exports[`placeholder containers load 1`] = ` ...@@ -25,6 +25,24 @@ exports[`placeholder containers load 1`] = `
justify-content: flex-start; justify-content: flex-start;
} }
.c11 {
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;
}
.c9 { .c9 {
color: #0D111C; color: #0D111C;
} }
...@@ -43,8 +61,11 @@ exports[`placeholder containers load 1`] = ` ...@@ -43,8 +61,11 @@ exports[`placeholder containers load 1`] = `
justify-content: flex-start; justify-content: flex-start;
} }
.c17 {
height: 568px;
}
.c7 { .c7 {
height: 288px;
background: #FFFFFF; background: #FFFFFF;
border-radius: 16px; border-radius: 16px;
padding: 16px 20px; padding: 16px 20px;
...@@ -66,26 +87,38 @@ exports[`placeholder containers load 1`] = ` ...@@ -66,26 +87,38 @@ exports[`placeholder containers load 1`] = `
cursor: default; cursor: default;
} }
.c11 { .c13 {
color: #0D111C; color: #0D111C;
line-height: 24px; line-height: 24px;
cursor: pointer; cursor: pointer;
} }
.c11:hover { .c13:hover {
opacity: 0.6; opacity: 0.6;
} }
.c12 { .c14 {
color: #98A1C0; color: #98A1C0;
line-height: 24px; line-height: 24px;
cursor: pointer; cursor: pointer;
} }
.c12:hover { .c14:hover {
opacity: 0.6; opacity: 0.6;
} }
.c16 {
background: #D2D9EE;
border-radius: 4px;
padding: 2px 4px;
color: #7780A0;
line-height: 12px;
}
.c15 {
height: 252px;
}
.c2 { .c2 {
height: 96px; height: 96px;
-webkit-flex-shrink: 0; -webkit-flex-shrink: 0;
...@@ -101,6 +134,10 @@ exports[`placeholder containers load 1`] = ` ...@@ -101,6 +134,10 @@ exports[`placeholder containers load 1`] = `
padding-left: 0px; padding-left: 0px;
} }
.c12 {
height: 492px;
}
.c1 { .c1 {
padding: 24px 64px; padding: 24px 64px;
height: 100vh; height: 100vh;
...@@ -118,6 +155,9 @@ exports[`placeholder containers load 1`] = ` ...@@ -118,6 +155,9 @@ exports[`placeholder containers load 1`] = `
.c6 { .c6 {
gap: 24px; gap: 24px;
width: 100%; width: 100%;
-webkit-align-self: flex-start;
-ms-flex-item-align: start;
align-self: flex-start;
} }
@media screen and (max-width:640px) { @media screen and (max-width:640px) {
...@@ -156,7 +196,6 @@ exports[`placeholder containers load 1`] = ` ...@@ -156,7 +196,6 @@ exports[`placeholder containers load 1`] = `
> >
<div <div
class="c7" class="c7"
style="height: 528px;"
> >
<div <div
class="c3 c4 c8" class="c3 c4 c8"
...@@ -164,60 +203,98 @@ exports[`placeholder containers load 1`] = ` ...@@ -164,60 +203,98 @@ exports[`placeholder containers load 1`] = `
<div <div
class="c9 c10 css-rjqmed" class="c9 c10 css-rjqmed"
> >
Traits <div
class="c3 c11"
>
Traits
</div>
</div> </div>
</div> </div>
<div> <div
class="c12"
>
Traits Content Traits Content
</div> </div>
</div> </div>
<div <div
class="c7" class="c7"
style="height: 288px;"
> >
<div <div
class="c3 c4 c8" class="c3 c4 c8"
> >
<div <div
class="c9 c11 css-rjqmed" class="c9 c13 css-rjqmed"
> >
Description <div
class="c3 c11"
>
Description
</div>
</div> </div>
<div <div
class="c9 c12 css-rjqmed" class="c9 c14 css-rjqmed"
> >
Details <div
class="c3 c11"
>
Details
</div>
</div> </div>
</div> </div>
<div> <div
class="c15"
>
Description Content Description Content
</div> </div>
</div> </div>
</div> </div>
<div <div
class="c7" class="c7"
style="height: 604px;"
> >
<div <div
class="c3 c4 c8" class="c3 c4 c8"
> >
<div <div
class="c9 c11 css-rjqmed" class="c9 c13 css-rjqmed"
> >
Activity <div
class="c3 c11"
>
Activity
</div>
</div> </div>
<div <div
class="c9 c12 css-rjqmed" class="c9 c14 css-rjqmed"
> >
Offers <div
class="c3 c11"
>
Offers
<div
class="c16 css-f8aq60"
>
10+
</div>
</div>
</div> </div>
<div <div
class="c9 c12 css-rjqmed" class="c9 c14 css-rjqmed"
> >
Listings <div
class="c3 c11"
>
Listings
<div
class="c16 css-f8aq60"
>
10+
</div>
</div>
</div> </div>
</div> </div>
<div> <div
class="c17"
>
Activity Content Activity Content
</div> </div>
</div> </div>
......
import { css } from 'styled-components/macro' import styled, { css } from 'styled-components/macro'
export const containerStyles = css` export const containerStyles = css`
background: ${({ theme }) => theme.backgroundSurface}; background: ${({ theme }) => theme.backgroundSurface};
...@@ -7,3 +7,7 @@ export const containerStyles = css` ...@@ -7,3 +7,7 @@ export const containerStyles = css`
width: 100%; width: 100%;
align-self: flex-start; align-self: flex-start;
` `
export const TableContentContainer = styled.div`
height: 568px;
`
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