-
Notifications
You must be signed in to change notification settings - Fork 13
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
*/ | ||
|
||
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({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './NFTCard2' |
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
</> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './NFTGrid2' |
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 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bye bye?