Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

O/noun 257 manage automated derivatives addition #153

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions @media/NFTCard2/NFTCard2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { ImageElement } from 'components'
import { Link } from 'components/Link'
import {
ImageEncodingTypes,
NounsTokensByOwnerAddressQuery,
} from 'types/zora.api.generated'

import { useMemo } from 'react'

import { NFTCardMarket } from '@market'
import { CollectionThumbnail } from '@media/CollectionThumbnail'
import {
cardImageWrapper,
cardWrapper,
titleHeading,
titleScroll,
titleWrapper,
} from '@media/NftMedia.css'
import { useRawImageTransform } from '@media/hooks/useRawImageTransform'
import { FallbackThumbnail } from '@noun-auction'
import { useIsOwner } from '@shared'
import { Box, Flex, Heading, Separator, Stack } from '@zoralabs/zord'

/**
tokenId
collectionAddress
collectionName
tokenOwner
token?.image?.url or token?.image?.mediaEncoding?.poster
*/
Comment on lines +25 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bye bye?


type ImageType = NounsTokensByOwnerAddressQuery['tokens']['nodes'][0]['token']['image']
type Props = {
collectionAddress: string
tokenId: string
collectionName?: string
tokenName?: string
// optionally set this as flag for /manage page (where we know for sure that user is owner)
isOwner?: boolean
image: ImageType
}

export function NFTCard2({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that this eliminates the useNFTProvider() calls, which seemed to me like a super weird pattern.

collectionAddress,
tokenId,
collectionName,
image,
tokenName,
}: Props) {
console.log('NFTCard2', collectionAddress, tokenId, collectionName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console

// maybe it makes sense to have fallback for image here
if (!tokenId || !collectionAddress || !image) return null

return (
<NFTCardComponent
tokenId={tokenId}
collectionAddress={collectionAddress}
collectionName={collectionName}
image={image}
tokenName={tokenName}
/>
)
}

type ImageWithFallbackProps = {
collectionAddress: string
tokenId: string
image: any // very bad type from api, FIXME later
}

export function ImageWithNounFallback({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to an external component?

collectionAddress,
tokenId,
image,
}: ImageWithFallbackProps) {
const { image: rawImageFallback } = useRawImageTransform(image?.url ?? undefined)

const decodedImgSrc = useMemo(() => {
const imageUrl = image?.url
if (image?.mimeType === 'image/svg+xml') {
return imageUrl?.includes('data:image/svg+xml') ||
imageUrl?.includes('https://api.zora.co')
? imageUrl
: `data:image/svg+xml,${imageUrl}` // proper handling of URI-encoded SVG
} else {
return image?.mediaEncoding?.poster ?? imageUrl
}
}, [image])

const srcImg = useMemo(
() => decodedImgSrc ?? rawImageFallback,
[decodedImgSrc, rawImageFallback]
)
Comment on lines +78 to +93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest moving this all into useRawImageTransform


if (srcImg) {
return (
<ImageElement
src={srcImg}
w="100%"
h="100%"
position="absolute"
inset="x0"
objectFit="cover"
/>
)
}

return <FallbackThumbnail tokenContract={collectionAddress} tokenId={tokenId} />
}

export function NFTCardComponent({
collectionAddress,
collectionName,
tokenId,
isOwner,
tokenName,
image,
}: Props) {
const fallbackTitle = collectionName ?? '..'

const useTitleScroll = useMemo(() => {
if (tokenName) {
return tokenName.split('').length > 25
}
}, [tokenName])

return (
<Stack w="100%" position="relative" overflow="hidden" className={cardWrapper}>
<Link href={`/collections/${collectionAddress}/${tokenId}`}>
<Box w="100%" className={cardImageWrapper} backgroundColor="background2">
<ImageWithNounFallback
collectionAddress={collectionAddress}
tokenId={tokenId}
image={image}
/>
</Box>
</Link>
<Stack gap="x2" px="x4" py="x4" flex={1}>
<Flex
className={[titleWrapper, useTitleScroll && titleScroll]}
style={{
/* @ts-ignore-next-line */
'--titlePad': titleScroll ? '40px' : '0px',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like we can manage this inside of the stylesheet

}}
>
<Heading as="h4" size="sm" className={titleHeading}>
{fallbackTitle}
</Heading>
</Flex>
<Flex align="center" gap="x2" justify="space-between">
<Link href={`/collections/${collectionAddress}`}>
<Flex align="center" gap="x2">
<CollectionThumbnail
collectionAddress={collectionAddress}
radius="round"
size="xs"
/>
<Heading size="xs">{collectionName}</Heading>
</Flex>
</Link>
</Flex>
{/* <Separator mt="x1" />
<NFTCardMarket /> */}
</Stack>
</Stack>
)
}
1 change: 1 addition & 0 deletions @media/NFTCard2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './NFTCard2'
38 changes: 38 additions & 0 deletions @media/NFTGrid2/NFTGrid2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NounsTokensByOwnerAddressQuery } from 'types/zora.api.generated'

import { NFTCard2 } from '@media/NFTCard2'
import { Grid, GridProps, Stack } from '@zoralabs/zord'

export interface NFTGridProps extends GridProps {
items: NounsTokensByOwnerAddressQuery['tokens']['nodes']
// allows skip computation of isOwner, when we know for sure
isOwner?: boolean
}

export function NFTGrid2({ items, ...props }: NFTGridProps) {
console.log(items)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console

return (
<>
<Stack gap="x14" pb="x10">
<Grid {...props} p="x0">
{items.map((nft) => {
const collectionAddress = nft.token.collectionAddress
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to destructure these from nft.token

const tokenId = nft.token.tokenId

return (
<NFTCard2
isOwner={props.isOwner}
key={`${collectionAddress}-${tokenId}`}
tokenId={tokenId}
collectionAddress={collectionAddress}
collectionName={nft?.token?.collectionName ?? '..'}
tokenName={nft?.token?.name ?? '..'}
image={nft?.token?.image ?? null}
/>
)
})}
</Grid>
</Stack>
</>
)
}
1 change: 1 addition & 0 deletions @media/NFTGrid2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './NFTGrid2'
95 changes: 95 additions & 0 deletions data/tokensByAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import gql from 'graphql-tag'

export const TOKENS_BY_ADDRESS_QUERY = gql`
query NounsTokensByOwnerAddress($ownerAddress: String!) {
tokens(where: { ownerAddresses: [$ownerAddress] }) {
nodes {
token {
collectionAddress
collectionName
description
image {
url
size
mimeType
mediaEncoding {
... on ImageEncodingTypes {
large
poster
}
}
}
lastRefreshTime
metadata
name
tokenContract {
collectionAddress
symbol
totalSupply
}
tokenId
}
marketsSummary {
collectionAddress
marketAddress
marketType
properties {
... on V3Ask {
address
askCurrency
askPrice {
blockNumber
}
buyer
collectionAddress
seller
tokenId
v3AskStatus
}
... on V3ReserveAuction {
estimatedDurationTime
address
collectionAddress
currency
duration
extended
finder
findersFeeBps
firstBid
firstBidTime
highestBid
highestBidder
reserve
highestBidPrice {
blockNumber
usdcPrice {
decimal
raw
}
nativePrice {
decimal
raw
}
}
reservePrice {
usdcPrice {
decimal
raw
}
nativePrice {
decimal
raw
}
}
seller
sellerFundsRecipient
startTime
status
tokenId
}
}
}
}
}
}
`
Loading