@medialane/ui 0.309.0 → 0.311.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/account-page.cjs +3 -6
- package/dist/components/account-page.cjs.map +1 -1
- package/dist/components/account-page.js +3 -6
- package/dist/components/account-page.js.map +1 -1
- package/dist/components/activity-card.cjs +2 -2
- package/dist/components/activity-card.cjs.map +1 -1
- package/dist/components/activity-card.js +2 -2
- package/dist/components/activity-card.js.map +1 -1
- package/dist/components/animated-token-media.cjs +2 -2
- package/dist/components/animated-token-media.cjs.map +1 -1
- package/dist/components/animated-token-media.js +2 -2
- package/dist/components/animated-token-media.js.map +1 -1
- package/dist/components/asset-card.cjs +1 -1
- package/dist/components/asset-card.cjs.map +1 -1
- package/dist/components/asset-card.js +1 -1
- package/dist/components/asset-card.js.map +1 -1
- package/dist/components/button.d.cts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/collection-card.cjs +1 -1
- package/dist/components/collection-card.cjs.map +1 -1
- package/dist/components/collection-card.js +1 -1
- package/dist/components/collection-card.js.map +1 -1
- package/dist/components/creators-page.cjs +2 -2
- package/dist/components/creators-page.cjs.map +1 -1
- package/dist/components/creators-page.js +2 -2
- package/dist/components/creators-page.js.map +1 -1
- package/dist/components/drop/drop-card.cjs +1 -1
- package/dist/components/drop/drop-card.cjs.map +1 -1
- package/dist/components/drop/drop-card.js +1 -1
- package/dist/components/drop/drop-card.js.map +1 -1
- package/dist/components/editions-page.cjs +1 -1
- package/dist/components/editions-page.cjs.map +1 -1
- package/dist/components/editions-page.js +1 -1
- package/dist/components/editions-page.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.d.cts +2 -2
- package/dist/components/fast-mint/fast-mint.d.ts +2 -2
- package/dist/components/launchpad/edition-mint-schema.d.cts +2 -2
- package/dist/components/launchpad/edition-mint-schema.d.ts +2 -2
- package/dist/components/listing-card.cjs +4 -4
- package/dist/components/listing-card.cjs.map +1 -1
- package/dist/components/listing-card.js +4 -4
- package/dist/components/listing-card.js.map +1 -1
- package/dist/components/media-wallet/nft-strip.cjs +1 -1
- package/dist/components/media-wallet/nft-strip.cjs.map +1 -1
- package/dist/components/media-wallet/nft-strip.js +1 -1
- package/dist/components/media-wallet/nft-strip.js.map +1 -1
- package/dist/components/remix-browse-page.cjs +1 -1
- package/dist/components/remix-browse-page.cjs.map +1 -1
- package/dist/components/remix-browse-page.js +1 -1
- package/dist/components/remix-browse-page.js.map +1 -1
- package/dist/components/sheet.d.cts +1 -1
- package/dist/components/sheet.d.ts +1 -1
- package/dist/components/token-card.cjs +8 -18
- package/dist/components/token-card.cjs.map +1 -1
- package/dist/components/token-card.js +8 -18
- package/dist/components/token-card.js.map +1 -1
- package/dist/medialane.css +7 -0
- package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport { ShoppingCart, Check, Zap, ArrowUpRight } from \"lucide-react\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, type ApiOrder, type Chain } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nfunction PriceLine({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n if (!usdValue) {\n return (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={11} />}\n {formatDisplayPrice(amountFormatted)}\n </p>\n );\n }\n const stable = isStableCurrency(currency);\n return (\n <>\n <p className=\"text-2xs font-bold price-value\">\n {usdValue}\n </p>\n <p className=\"text-2xs text-muted-foreground/70 inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={10} />}\n {stable ? currency : `${formatDisplayPrice(amountFormatted)} ${currency}`}\n </p>\n </>\n );\n}\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n\n overflowMenu?: React.ReactNode;\n\n primaryAction?: React.ReactNode;\n compact?: boolean;\n\n imageUrl?: string | null;\n\n usdValue?: string | null;\n}\n\nexport function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }: ListingCardProps) {\n const resolveImage = useImageUrl();\n const order = rawOrder as OrderWithAnimation;\n const [imgError, setImgError] = useState(false);\n const isListing = order.offer.itemType === \"ERC721\" || order.offer.itemType === \"ERC1155\";\n const name = order.token?.name ?? `Token #${order.nftTokenId}`;\n const image = imageUrl !== undefined ? imageUrl : (order.token?.image ? resolveImage(order.token.image, { width: 480 }) : null);\n\n const animationUrl = order.token?.animationUrl ?? null;\n const live = !!(order.chain && order.nftContract) && isLivingRenderCollection(order.chain.toUpperCase() as Chain, order.nftContract!);\n const assetHref = buildAssetHref(\"STARKNET\", order.nftContract ?? \"\", order.nftTokenId ?? \"\");\n\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n if (compact) {\n return (\n <MotionCard className=\"card-base\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 33vw, 20vw\"\n className=\"object-cover group-hover:scale-105 transition-transform duration-500\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold line-clamp-2 break-words\">{name}</p>\n <PriceLine amountFormatted={order.price?.formatted} currency={order.price?.currency} usdValue={usdValue} />\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n return (\n <MotionCard className=\"card-base\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw\"\n className=\"object-cover group-hover:scale-105 transition-transform duration-500\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"text-base font-semibold tracking-tight line-clamp-2 break-words leading-snug\">{name}</p>\n </div>\n\n {order.price?.formatted && (\n <DualPrice amountFormatted={order.price.formatted} currency={order.price.currency} usdValue={usdValue} scale=\"card\" />\n )}\n\n {showActionBar && (\n <div className=\"flex items-center gap-1.5\">\n {isListing ? (\n primaryAction ? (\n primaryAction\n ) : onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={(e) => { e.preventDefault(); onBuy(order); }}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" /> Buy\n </button>\n </div>\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View\n </Link>\n )\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View asset\n </Link>\n )}\n {onCart && (\n <button\n className={cn(\n \"min-h-11 min-w-11 shrink-0 rounded-[9px] border flex items-center justify-center transition-colors\",\n inCart\n ? \"border-brand-orange/50 bg-brand-orange/10 text-brand-orange\"\n : \"border-border bg-background hover:bg-muted text-foreground\"\n )}\n onClick={(e) => { e.preventDefault(); if (!inCart) onCart(order); }}\n disabled={inCart}\n aria-label={inCart ? \"Added to cart\" : \"Add to cart\"}\n >\n {inCart ? <Check className=\"h-3.5 w-3.5\" /> : <ShoppingCart className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n {overflowMenu}\n </div>\n )}\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function ListingCardSkeleton() {\n return (\n <div className=\"card-base\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-2.5\">\n <div className=\"space-y-1\">\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-1/2 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-6 w-1/2 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-2/3 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["buildAssetHref","Link"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport { ShoppingCart, Check, Zap, ArrowUpRight } from \"lucide-react\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, type ApiOrder, type Chain } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nfunction PriceLine({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n if (!usdValue) {\n return (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={11} />}\n {formatDisplayPrice(amountFormatted)}\n </p>\n );\n }\n const stable = isStableCurrency(currency);\n return (\n <>\n <p className=\"text-2xs font-bold price-value\">\n {usdValue}\n </p>\n <p className=\"text-2xs text-muted-foreground/70 inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={10} />}\n {stable ? currency : `${formatDisplayPrice(amountFormatted)} ${currency}`}\n </p>\n </>\n );\n}\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n\n overflowMenu?: React.ReactNode;\n\n primaryAction?: React.ReactNode;\n compact?: boolean;\n\n imageUrl?: string | null;\n\n usdValue?: string | null;\n}\n\nexport function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }: ListingCardProps) {\n const resolveImage = useImageUrl();\n const order = rawOrder as OrderWithAnimation;\n const [imgError, setImgError] = useState(false);\n const isListing = order.offer.itemType === \"ERC721\" || order.offer.itemType === \"ERC1155\";\n const name = order.token?.name ?? `Token #${order.nftTokenId}`;\n const image = imageUrl !== undefined ? imageUrl : (order.token?.image ? resolveImage(order.token.image, { width: 480 }) : null);\n\n const animationUrl = order.token?.animationUrl ?? null;\n const live = !!(order.chain && order.nftContract) && isLivingRenderCollection(order.chain.toUpperCase() as Chain, order.nftContract!);\n const assetHref = buildAssetHref(\"STARKNET\", order.nftContract ?? \"\", order.nftTokenId ?? \"\");\n\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n if (compact) {\n return (\n <MotionCard className=\"card-base group\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 33vw, 20vw\"\n className=\"object-cover\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold line-clamp-2 break-words\">{name}</p>\n <PriceLine amountFormatted={order.price?.formatted} currency={order.price?.currency} usdValue={usdValue} />\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n return (\n <MotionCard className=\"card-base group\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw\"\n className=\"object-cover\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"text-base font-semibold tracking-tight line-clamp-2 break-words leading-snug\">{name}</p>\n </div>\n\n {order.price?.formatted && (\n <DualPrice amountFormatted={order.price.formatted} currency={order.price.currency} usdValue={usdValue} scale=\"card\" />\n )}\n\n {showActionBar && (\n <div className=\"flex items-center gap-1.5\">\n {isListing ? (\n primaryAction ? (\n primaryAction\n ) : onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={(e) => { e.preventDefault(); onBuy(order); }}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" /> Buy\n </button>\n </div>\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View\n </Link>\n )\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View asset\n </Link>\n )}\n {onCart && (\n <button\n className={cn(\n \"min-h-11 min-w-11 shrink-0 rounded-[9px] border flex items-center justify-center transition-colors\",\n inCart\n ? \"border-brand-orange/50 bg-brand-orange/10 text-brand-orange\"\n : \"border-border bg-background hover:bg-muted text-foreground\"\n )}\n onClick={(e) => { e.preventDefault(); if (!inCart) onCart(order); }}\n disabled={inCart}\n aria-label={inCart ? \"Added to cart\" : \"Add to cart\"}\n >\n {inCart ? <Check className=\"h-3.5 w-3.5\" /> : <ShoppingCart className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n {overflowMenu}\n </div>\n )}\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function ListingCardSkeleton() {\n return (\n <div className=\"card-base\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-2.5\">\n <div className=\"space-y-1\">\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-1/2 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-6 w-1/2 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-2/3 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["buildAssetHref","Link"]}
|
|
@@ -46,7 +46,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
|
|
|
46
46
|
const assetHref = buildAssetHref("STARKNET", order.nftContract ?? "", order.nftTokenId ?? "");
|
|
47
47
|
const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);
|
|
48
48
|
if (compact) {
|
|
49
|
-
return /* @__PURE__ */ jsx(MotionCard, { className: "card-base", children: /* @__PURE__ */ jsxs(Link, { href: assetHref, className: "block", children: [
|
|
49
|
+
return /* @__PURE__ */ jsx(MotionCard, { className: "card-base group", children: /* @__PURE__ */ jsxs(Link, { href: assetHref, className: "block", children: [
|
|
50
50
|
/* @__PURE__ */ jsx("div", { className: "relative aspect-square bg-muted overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
51
51
|
AnimatedTokenMedia,
|
|
52
52
|
{
|
|
@@ -56,7 +56,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
|
|
|
56
56
|
alt: name,
|
|
57
57
|
mode: "fill",
|
|
58
58
|
sizes: "(max-width: 640px) 33vw, 20vw",
|
|
59
|
-
className: "object-cover
|
|
59
|
+
className: "object-cover",
|
|
60
60
|
imgError,
|
|
61
61
|
onImageError: () => setImgError(true),
|
|
62
62
|
fallback: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15" })
|
|
@@ -69,7 +69,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
|
|
|
69
69
|
] })
|
|
70
70
|
] }) });
|
|
71
71
|
}
|
|
72
|
-
return /* @__PURE__ */ jsx(MotionCard, { className: "card-base", children: /* @__PURE__ */ jsxs(Link, { href: assetHref, className: "block", children: [
|
|
72
|
+
return /* @__PURE__ */ jsx(MotionCard, { className: "card-base group", children: /* @__PURE__ */ jsxs(Link, { href: assetHref, className: "block", children: [
|
|
73
73
|
/* @__PURE__ */ jsx("div", { className: "relative aspect-square bg-muted overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
74
74
|
AnimatedTokenMedia,
|
|
75
75
|
{
|
|
@@ -79,7 +79,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
|
|
|
79
79
|
alt: name,
|
|
80
80
|
mode: "fill",
|
|
81
81
|
sizes: "(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw",
|
|
82
|
-
className: "object-cover
|
|
82
|
+
className: "object-cover",
|
|
83
83
|
imgError,
|
|
84
84
|
onImageError: () => setImgError(true),
|
|
85
85
|
fallback: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport { ShoppingCart, Check, Zap, ArrowUpRight } from \"lucide-react\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, type ApiOrder, type Chain } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nfunction PriceLine({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n if (!usdValue) {\n return (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={11} />}\n {formatDisplayPrice(amountFormatted)}\n </p>\n );\n }\n const stable = isStableCurrency(currency);\n return (\n <>\n <p className=\"text-2xs font-bold price-value\">\n {usdValue}\n </p>\n <p className=\"text-2xs text-muted-foreground/70 inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={10} />}\n {stable ? currency : `${formatDisplayPrice(amountFormatted)} ${currency}`}\n </p>\n </>\n );\n}\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n\n overflowMenu?: React.ReactNode;\n\n primaryAction?: React.ReactNode;\n compact?: boolean;\n\n imageUrl?: string | null;\n\n usdValue?: string | null;\n}\n\nexport function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }: ListingCardProps) {\n const resolveImage = useImageUrl();\n const order = rawOrder as OrderWithAnimation;\n const [imgError, setImgError] = useState(false);\n const isListing = order.offer.itemType === \"ERC721\" || order.offer.itemType === \"ERC1155\";\n const name = order.token?.name ?? `Token #${order.nftTokenId}`;\n const image = imageUrl !== undefined ? imageUrl : (order.token?.image ? resolveImage(order.token.image, { width: 480 }) : null);\n\n const animationUrl = order.token?.animationUrl ?? null;\n const live = !!(order.chain && order.nftContract) && isLivingRenderCollection(order.chain.toUpperCase() as Chain, order.nftContract!);\n const assetHref = buildAssetHref(\"STARKNET\", order.nftContract ?? \"\", order.nftTokenId ?? \"\");\n\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n if (compact) {\n return (\n <MotionCard className=\"card-base\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 33vw, 20vw\"\n className=\"object-cover group-hover:scale-105 transition-transform duration-500\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold line-clamp-2 break-words\">{name}</p>\n <PriceLine amountFormatted={order.price?.formatted} currency={order.price?.currency} usdValue={usdValue} />\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n return (\n <MotionCard className=\"card-base\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw\"\n className=\"object-cover group-hover:scale-105 transition-transform duration-500\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"text-base font-semibold tracking-tight line-clamp-2 break-words leading-snug\">{name}</p>\n </div>\n\n {order.price?.formatted && (\n <DualPrice amountFormatted={order.price.formatted} currency={order.price.currency} usdValue={usdValue} scale=\"card\" />\n )}\n\n {showActionBar && (\n <div className=\"flex items-center gap-1.5\">\n {isListing ? (\n primaryAction ? (\n primaryAction\n ) : onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={(e) => { e.preventDefault(); onBuy(order); }}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" /> Buy\n </button>\n </div>\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View\n </Link>\n )\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View asset\n </Link>\n )}\n {onCart && (\n <button\n className={cn(\n \"min-h-11 min-w-11 shrink-0 rounded-[9px] border flex items-center justify-center transition-colors\",\n inCart\n ? \"border-brand-orange/50 bg-brand-orange/10 text-brand-orange\"\n : \"border-border bg-background hover:bg-muted text-foreground\"\n )}\n onClick={(e) => { e.preventDefault(); if (!inCart) onCart(order); }}\n disabled={inCart}\n aria-label={inCart ? \"Added to cart\" : \"Add to cart\"}\n >\n {inCart ? <Check className=\"h-3.5 w-3.5\" /> : <ShoppingCart className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n {overflowMenu}\n </div>\n )}\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function ListingCardSkeleton() {\n return (\n <div className=\"card-base\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-2.5\">\n <div className=\"space-y-1\">\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-1/2 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-6 w-1/2 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-2/3 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport { ShoppingCart, Check, Zap, ArrowUpRight } from \"lucide-react\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, type ApiOrder, type Chain } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nfunction PriceLine({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n if (!usdValue) {\n return (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={11} />}\n {formatDisplayPrice(amountFormatted)}\n </p>\n );\n }\n const stable = isStableCurrency(currency);\n return (\n <>\n <p className=\"text-2xs font-bold price-value\">\n {usdValue}\n </p>\n <p className=\"text-2xs text-muted-foreground/70 inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={10} />}\n {stable ? currency : `${formatDisplayPrice(amountFormatted)} ${currency}`}\n </p>\n </>\n );\n}\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n\n overflowMenu?: React.ReactNode;\n\n primaryAction?: React.ReactNode;\n compact?: boolean;\n\n imageUrl?: string | null;\n\n usdValue?: string | null;\n}\n\nexport function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }: ListingCardProps) {\n const resolveImage = useImageUrl();\n const order = rawOrder as OrderWithAnimation;\n const [imgError, setImgError] = useState(false);\n const isListing = order.offer.itemType === \"ERC721\" || order.offer.itemType === \"ERC1155\";\n const name = order.token?.name ?? `Token #${order.nftTokenId}`;\n const image = imageUrl !== undefined ? imageUrl : (order.token?.image ? resolveImage(order.token.image, { width: 480 }) : null);\n\n const animationUrl = order.token?.animationUrl ?? null;\n const live = !!(order.chain && order.nftContract) && isLivingRenderCollection(order.chain.toUpperCase() as Chain, order.nftContract!);\n const assetHref = buildAssetHref(\"STARKNET\", order.nftContract ?? \"\", order.nftTokenId ?? \"\");\n\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n if (compact) {\n return (\n <MotionCard className=\"card-base group\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 33vw, 20vw\"\n className=\"object-cover\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold line-clamp-2 break-words\">{name}</p>\n <PriceLine amountFormatted={order.price?.formatted} currency={order.price?.currency} usdValue={usdValue} />\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n return (\n <MotionCard className=\"card-base group\">\n <Link href={assetHref} className=\"block\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw\"\n className=\"object-cover\"\n imgError={imgError}\n onImageError={() => setImgError(true)}\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"text-base font-semibold tracking-tight line-clamp-2 break-words leading-snug\">{name}</p>\n </div>\n\n {order.price?.formatted && (\n <DualPrice amountFormatted={order.price.formatted} currency={order.price.currency} usdValue={usdValue} scale=\"card\" />\n )}\n\n {showActionBar && (\n <div className=\"flex items-center gap-1.5\">\n {isListing ? (\n primaryAction ? (\n primaryAction\n ) : onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={(e) => { e.preventDefault(); onBuy(order); }}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" /> Buy\n </button>\n </div>\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View\n </Link>\n )\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View asset\n </Link>\n )}\n {onCart && (\n <button\n className={cn(\n \"min-h-11 min-w-11 shrink-0 rounded-[9px] border flex items-center justify-center transition-colors\",\n inCart\n ? \"border-brand-orange/50 bg-brand-orange/10 text-brand-orange\"\n : \"border-border bg-background hover:bg-muted text-foreground\"\n )}\n onClick={(e) => { e.preventDefault(); if (!inCart) onCart(order); }}\n disabled={inCart}\n aria-label={inCart ? \"Added to cart\" : \"Add to cart\"}\n >\n {inCart ? <Check className=\"h-3.5 w-3.5\" /> : <ShoppingCart className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n {overflowMenu}\n </div>\n )}\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function ListingCardSkeleton() {\n return (\n <div className=\"card-base\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-2.5\">\n <div className=\"space-y-1\">\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-1/2 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-6 w-1/2 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-2/3 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n"],"mappings":";AA4BM,SAQF,UAPiB,KADf;AA1BN,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,cAAc,OAAO,KAAK,oBAAoB;AACvD,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,UAAU;AACnB,SAAS,oBAAoB,wBAAwB;AACrD,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,gCAAgC;AACzC,SAAS,aAAa,sBAAiD;AACvE,SAAS,mBAAmB;AAI5B,SAAS,UAAU;AAAA,EACjB;AAAA,EAAiB;AAAA,EAAU;AAC7B,GAIG;AACD,MAAI,CAAC,gBAAiB,QAAO;AAC7B,MAAI,CAAC,UAAU;AACb,WACE,qBAAC,OAAE,WAAU,iEACV;AAAA,kBAAY,oBAAC,gBAAa,QAAQ,UAAU,MAAM,IAAI;AAAA,MACtD,mBAAmB,eAAe;AAAA,OACrC;AAAA,EAEJ;AACA,QAAM,SAAS,iBAAiB,QAAQ;AACxC,SACE,iCACE;AAAA,wBAAC,OAAE,WAAU,kCACV,oBACH;AAAA,IACA,qBAAC,OAAE,WAAU,oEACV;AAAA,kBAAY,oBAAC,gBAAa,QAAQ,UAAU,MAAM,IAAI;AAAA,MACtD,SAAS,WAAW,GAAG,mBAAmB,eAAe,CAAC,IAAI,QAAQ;AAAA,OACzE;AAAA,KACF;AAEJ;AAkBO,SAAS,YAAY,EAAE,OAAO,UAAU,SAAS,OAAO,OAAO,QAAQ,cAAc,eAAe,UAAU,OAAO,UAAU,SAAS,GAAqB;AAClK,QAAM,eAAe,YAAY;AACjC,QAAM,QAAQ;AACd,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,YAAY,MAAM,MAAM,aAAa,YAAY,MAAM,MAAM,aAAa;AAChF,QAAM,OAAO,MAAM,OAAO,QAAQ,UAAU,MAAM,UAAU;AAC5D,QAAM,QAAQ,aAAa,SAAY,WAAY,MAAM,OAAO,QAAQ,aAAa,MAAM,MAAM,OAAO,EAAE,OAAO,IAAI,CAAC,IAAI;AAE1H,QAAM,eAAe,MAAM,OAAO,gBAAgB;AAClD,QAAM,OAAO,CAAC,EAAE,MAAM,SAAS,MAAM,gBAAgB,yBAAyB,MAAM,MAAM,YAAY,GAAY,MAAM,WAAY;AACpI,QAAM,YAAY,eAAe,YAAY,MAAM,eAAe,IAAI,MAAM,cAAc,EAAE;AAE5F,QAAM,gBAAgB,CAAC,EAAE,SAAS,UAAU,gBAAgB;AAE5D,MAAI,SAAS;AACX,WACE,oBAAC,cAAW,WAAU,mBACpB,+BAAC,QAAK,MAAM,WAAW,WAAU,SAC/B;AAAA,0BAAC,SAAI,WAAU,mDACb;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK;AAAA,UACL,MAAK;AAAA,UACL,OAAM;AAAA,UACN,WAAU;AAAA,UACV;AAAA,UACA,cAAc,MAAM,YAAY,IAAI;AAAA,UACpC,UACE,oBAAC,SAAI,WAAU,4EAA2E;AAAA;AAAA,MAE9F,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,qBACb;AAAA,4BAAC,OAAE,WAAU,kDAAkD,gBAAK;AAAA,QACpE,oBAAC,aAAU,iBAAiB,MAAM,OAAO,WAAW,UAAU,MAAM,OAAO,UAAU,UAAoB;AAAA,QACzG,oBAAC,OAAE,WAAU,kCAAkC,kBAAQ,MAAM,SAAS,GAAE;AAAA,SAC1E;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,cAAW,WAAU,mBACpB,+BAAC,QAAK,MAAM,WAAW,WAAU,SAC/B;AAAA,wBAAC,SAAI,WAAU,mDACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,MAAK;AAAA,QACL,OAAM;AAAA,QACN,WAAU;AAAA,QACV;AAAA,QACA,cAAc,MAAM,YAAY,IAAI;AAAA,QACpC,UACE,oBAAC,SAAI,WAAU,4EAA2E;AAAA;AAAA,IAE9F,GACF;AAAA,IAEA,qBAAC,SAAI,WAAU,mBACb;AAAA,0BAAC,SAAI,WAAU,WACb,8BAAC,OAAE,WAAU,gFAAgF,gBAAK,GACpG;AAAA,MAEC,MAAM,OAAO,aACZ,oBAAC,aAAU,iBAAiB,MAAM,MAAM,WAAW,UAAU,MAAM,MAAM,UAAU,UAAoB,OAAM,QAAO;AAAA,MAGrH,iBACC,qBAAC,SAAI,WAAU,6BACZ;AAAA,oBACC,gBACE,gBACE,QACF,oBAAC,SAAI,WAAU,2DACb;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,CAAC,MAAM;AAAE,gBAAE,eAAe;AAAG,oBAAM,KAAK;AAAA,YAAG;AAAA,YAEpD;AAAA,kCAAC,OAAI,WAAU,wBAAuB;AAAA,cAAE;AAAA;AAAA;AAAA,QAC1C,GACF,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,WAAU;AAAA,YAEV;AAAA,kCAAC,gBAAa,WAAU,wBAAuB;AAAA,cAAE;AAAA;AAAA;AAAA,QACnD,IAGF;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,WAAU;AAAA,YAEV;AAAA,kCAAC,gBAAa,WAAU,wBAAuB;AAAA,cAAE;AAAA;AAAA;AAAA,QACnD;AAAA,QAED,UACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,SACI,gEACA;AAAA,YACN;AAAA,YACA,SAAS,CAAC,MAAM;AAAE,gBAAE,eAAe;AAAG,kBAAI,CAAC,OAAQ,QAAO,KAAK;AAAA,YAAG;AAAA,YAClE,UAAU;AAAA,YACV,cAAY,SAAS,kBAAkB;AAAA,YAEtC,mBAAS,oBAAC,SAAM,WAAU,eAAc,IAAK,oBAAC,gBAAa,WAAU,eAAc;AAAA;AAAA,QACtF;AAAA,QAED;AAAA,SACH;AAAA,OAEJ;AAAA,KACF,GACF;AAEJ;AAEO,SAAS,sBAAsB;AACpC,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,SAAI,WAAU,+CAA8C;AAAA,IAC7D,qBAAC,SAAI,WAAU,mBACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,SAAI,WAAU,4CAA2C;AAAA,QAC1D,oBAAC,SAAI,WAAU,4CAA2C;AAAA,SAC5D;AAAA,MACA,oBAAC,SAAI,WAAU,4CAA2C;AAAA,MAC1D,oBAAC,SAAI,WAAU,4CAA2C;AAAA,OAC5D;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -63,7 +63,7 @@ function NftStrip({
|
|
|
63
63
|
alt: item.name,
|
|
64
64
|
fill: true,
|
|
65
65
|
unoptimized: true,
|
|
66
|
-
className: "object-cover
|
|
66
|
+
className: "object-cover card-media"
|
|
67
67
|
}
|
|
68
68
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid h-full w-full place-items-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AssetFallbackIcon, {}) })
|
|
69
69
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/nft-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"../link.js\";\nimport Image from \"../image.js\";\nimport type { NftItem } from \"../../utils/media-wallet/nft-items.js\";\n\nexport function NftStrip({\n items,\n isLoading,\n onNavigate,\n resolveImage,\n}: {\n items: NftItem[];\n isLoading: boolean;\n onNavigate?: () => void;\n resolveImage: (uri: string | null | undefined) => string | null;\n}) {\n if (isLoading) {\n return (\n <div data-testid=\"nft-strip-skeleton\" className=\"grid grid-cols-4 gap-2\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"aspect-square animate-pulse rounded-xl bg-foreground/[0.06]\" />\n ))}\n </div>\n );\n }\n\n if (items.length === 0) {\n return (\n <p className=\"text-sm text-muted-foreground\">\n No NFTs yet — mint or collect your first one to see it here.\n </p>\n );\n }\n\n return (\n <div className=\"grid grid-cols-4 gap-2\">\n {items.map((item) => {\n const resolved = resolveImage(item.image);\n return (\n <Link\n key={item.key}\n href={item.href}\n title={item.name}\n onClick={onNavigate}\n className=\"group relative aspect-square overflow-hidden rounded-xl bg-foreground/[0.06] transition-opacity hover:opacity-90\"\n >\n {resolved ? (\n <Image\n src={resolved}\n alt={item.name}\n fill\n unoptimized\n className=\"object-cover
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/nft-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"../link.js\";\nimport Image from \"../image.js\";\nimport type { NftItem } from \"../../utils/media-wallet/nft-items.js\";\n\nexport function NftStrip({\n items,\n isLoading,\n onNavigate,\n resolveImage,\n}: {\n items: NftItem[];\n isLoading: boolean;\n onNavigate?: () => void;\n resolveImage: (uri: string | null | undefined) => string | null;\n}) {\n if (isLoading) {\n return (\n <div data-testid=\"nft-strip-skeleton\" className=\"grid grid-cols-4 gap-2\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"aspect-square animate-pulse rounded-xl bg-foreground/[0.06]\" />\n ))}\n </div>\n );\n }\n\n if (items.length === 0) {\n return (\n <p className=\"text-sm text-muted-foreground\">\n No NFTs yet — mint or collect your first one to see it here.\n </p>\n );\n }\n\n return (\n <div className=\"grid grid-cols-4 gap-2\">\n {items.map((item) => {\n const resolved = resolveImage(item.image);\n return (\n <Link\n key={item.key}\n href={item.href}\n title={item.name}\n onClick={onNavigate}\n className=\"group relative aspect-square overflow-hidden rounded-xl bg-foreground/[0.06] transition-opacity hover:opacity-90\"\n >\n {resolved ? (\n <Image\n src={resolved}\n alt={item.name}\n fill\n unoptimized\n className=\"object-cover card-media\"\n />\n ) : (\n <div className=\"grid h-full w-full place-items-center\">\n <AssetFallbackIcon />\n </div>\n )}\n </Link>\n );\n })}\n </div>\n );\n}\n\nfunction AssetFallbackIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" className=\"text-muted-foreground\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\" />\n <circle cx=\"9\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\" />\n <path d=\"M21 15l-5-5-9 9\" />\n </svg>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBU;AAnBV,kBAAiB;AACjB,mBAAkB;AAGX,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,MAAI,WAAW;AACb,WACE,4CAAC,SAAI,eAAY,sBAAqB,WAAU,0BAC7C,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,4CAAC,SAAY,WAAU,iEAAb,CAA2E,CACtF,GACH;AAAA,EAEJ;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WACE,4CAAC,OAAE,WAAU,iCAAgC,+EAE7C;AAAA,EAEJ;AAEA,SACE,4CAAC,SAAI,WAAU,0BACZ,gBAAM,IAAI,CAAC,SAAS;AACnB,UAAM,WAAW,aAAa,KAAK,KAAK;AACxC,WACE;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QAEC,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,SAAS;AAAA,QACT,WAAU;AAAA,QAET,qBACC;AAAA,UAAC,aAAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK,KAAK;AAAA,YACV,MAAI;AAAA,YACJ,aAAW;AAAA,YACX,WAAU;AAAA;AAAA,QACZ,IAEA,4CAAC,SAAI,WAAU,yCACb,sDAAC,qBAAkB,GACrB;AAAA;AAAA,MAjBG,KAAK;AAAA,IAmBZ;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,SAAS,oBAAoB;AAC3B,SACE,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,WAAU,yBAAwB,eAAc,SAAQ,gBAAe,SACzK;AAAA,gDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,4CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM,MAAK,gBAAe,QAAO,QAAO;AAAA,IAChE,4CAAC,UAAK,GAAE,mBAAkB;AAAA,KAC5B;AAEJ;","names":["Link","Image"]}
|
|
@@ -30,7 +30,7 @@ function NftStrip({
|
|
|
30
30
|
alt: item.name,
|
|
31
31
|
fill: true,
|
|
32
32
|
unoptimized: true,
|
|
33
|
-
className: "object-cover
|
|
33
|
+
className: "object-cover card-media"
|
|
34
34
|
}
|
|
35
35
|
) : /* @__PURE__ */ jsx("div", { className: "grid h-full w-full place-items-center", children: /* @__PURE__ */ jsx(AssetFallbackIcon, {}) })
|
|
36
36
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/nft-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"../link.js\";\nimport Image from \"../image.js\";\nimport type { NftItem } from \"../../utils/media-wallet/nft-items.js\";\n\nexport function NftStrip({\n items,\n isLoading,\n onNavigate,\n resolveImage,\n}: {\n items: NftItem[];\n isLoading: boolean;\n onNavigate?: () => void;\n resolveImage: (uri: string | null | undefined) => string | null;\n}) {\n if (isLoading) {\n return (\n <div data-testid=\"nft-strip-skeleton\" className=\"grid grid-cols-4 gap-2\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"aspect-square animate-pulse rounded-xl bg-foreground/[0.06]\" />\n ))}\n </div>\n );\n }\n\n if (items.length === 0) {\n return (\n <p className=\"text-sm text-muted-foreground\">\n No NFTs yet — mint or collect your first one to see it here.\n </p>\n );\n }\n\n return (\n <div className=\"grid grid-cols-4 gap-2\">\n {items.map((item) => {\n const resolved = resolveImage(item.image);\n return (\n <Link\n key={item.key}\n href={item.href}\n title={item.name}\n onClick={onNavigate}\n className=\"group relative aspect-square overflow-hidden rounded-xl bg-foreground/[0.06] transition-opacity hover:opacity-90\"\n >\n {resolved ? (\n <Image\n src={resolved}\n alt={item.name}\n fill\n unoptimized\n className=\"object-cover
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/nft-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"../link.js\";\nimport Image from \"../image.js\";\nimport type { NftItem } from \"../../utils/media-wallet/nft-items.js\";\n\nexport function NftStrip({\n items,\n isLoading,\n onNavigate,\n resolveImage,\n}: {\n items: NftItem[];\n isLoading: boolean;\n onNavigate?: () => void;\n resolveImage: (uri: string | null | undefined) => string | null;\n}) {\n if (isLoading) {\n return (\n <div data-testid=\"nft-strip-skeleton\" className=\"grid grid-cols-4 gap-2\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"aspect-square animate-pulse rounded-xl bg-foreground/[0.06]\" />\n ))}\n </div>\n );\n }\n\n if (items.length === 0) {\n return (\n <p className=\"text-sm text-muted-foreground\">\n No NFTs yet — mint or collect your first one to see it here.\n </p>\n );\n }\n\n return (\n <div className=\"grid grid-cols-4 gap-2\">\n {items.map((item) => {\n const resolved = resolveImage(item.image);\n return (\n <Link\n key={item.key}\n href={item.href}\n title={item.name}\n onClick={onNavigate}\n className=\"group relative aspect-square overflow-hidden rounded-xl bg-foreground/[0.06] transition-opacity hover:opacity-90\"\n >\n {resolved ? (\n <Image\n src={resolved}\n alt={item.name}\n fill\n unoptimized\n className=\"object-cover card-media\"\n />\n ) : (\n <div className=\"grid h-full w-full place-items-center\">\n <AssetFallbackIcon />\n </div>\n )}\n </Link>\n );\n })}\n </div>\n );\n}\n\nfunction AssetFallbackIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" className=\"text-muted-foreground\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\" />\n <circle cx=\"9\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\" />\n <path d=\"M21 15l-5-5-9 9\" />\n </svg>\n );\n}\n"],"mappings":";AAqBU,cAgDN,YAhDM;AAnBV,OAAO,UAAU;AACjB,OAAO,WAAW;AAGX,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,MAAI,WAAW;AACb,WACE,oBAAC,SAAI,eAAY,sBAAqB,WAAU,0BAC7C,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,oBAAC,SAAY,WAAU,iEAAb,CAA2E,CACtF,GACH;AAAA,EAEJ;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WACE,oBAAC,OAAE,WAAU,iCAAgC,+EAE7C;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,0BACZ,gBAAM,IAAI,CAAC,SAAS;AACnB,UAAM,WAAW,aAAa,KAAK,KAAK;AACxC,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,SAAS;AAAA,QACT,WAAU;AAAA,QAET,qBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK,KAAK;AAAA,YACV,MAAI;AAAA,YACJ,aAAW;AAAA,YACX,WAAU;AAAA;AAAA,QACZ,IAEA,oBAAC,SAAI,WAAU,yCACb,8BAAC,qBAAkB,GACrB;AAAA;AAAA,MAjBG,KAAK;AAAA,IAmBZ;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,SAAS,oBAAoB;AAC3B,SACE,qBAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,WAAU,yBAAwB,eAAc,SAAQ,gBAAe,SACzK;AAAA,wBAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,oBAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM,MAAK,gBAAe,QAAO,QAAO;AAAA,IAChE,oBAAC,UAAK,GAAE,mBAAkB;AAAA,KAC5B;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/remix-browse-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { ServiceHeader } from \"./service-header.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { FadeIn, Stagger, StaggerItem } from \"./motion-primitives.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Button } from \"./button.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\nimport type { ApiToken } from \"@medialane/sdk\";\nimport { GitBranch, ImageIcon, Inbox } from \"lucide-react\";\n\nconst PAGE_SIZE = 24;\n\nfunction useRemixableTokens() {\n const client = useMedialaneClient();\n const [tokens, setTokens] = useState<ApiToken[]>([]);\n const [page, setPage] = useState(1);\n const [isLoading, setIsLoading] = useState(true);\n const [hasMore, setHasMore] = useState(false);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n client.api.tokens.list({ derivatives: \"allowed\", limit: PAGE_SIZE, page })\n .then((json) => {\n if (cancelled) return;\n setTokens((prev) => (page === 1 ? json.data : [...prev, ...json.data]));\n setHasMore(page * PAGE_SIZE < (json.meta?.total ?? 0));\n })\n .catch(() => { if (!cancelled) setError(true); })\n .finally(() => { if (!cancelled) setIsLoading(false); });\n return () => { cancelled = true; };\n }, [client, page]);\n\n return { tokens, isLoading, hasMore, error, loadMore: () => setPage((p) => p + 1) };\n}\n\nfunction RemixableCard({ token }: { token: ApiToken }) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = useImageUrl()(token.metadata?.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const name = token.metadata?.name ?? `#${token.tokenId}`;\n\n return (\n <Link\n href={`/create/remix/${token.contractAddress}/${token.tokenId}`}\n className=\"group flex flex-col rounded-2xl border border-border/60 bg-card overflow-hidden transition-colors sm:hover:border-brand-blue/50 active:scale-[0.99] motion-reduce:transform-none\"\n >\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={name}\n fill\n className=\"object-cover\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <ImageIcon className=\"h-8 w-8 text-muted-foreground/30\" />\n </div>\n )}\n </div>\n <div className=\"p-4 space-y-1\">\n <p className=\"font-semibold text-sm leading-tight truncate\">{name}</p>\n <p className=\"text-xs text-muted-foreground\">\n Derivatives: Allowed\n </p>\n <p className=\"text-xs font-semibold pt-1 inline-flex items-center gap-1.5\">\n <GitBranch className=\"h-3 w-3\" />\n Remix this work\n </p>\n </div>\n </Link>\n );\n}\n\nfunction RemixableCardSkeleton() {\n return (\n <div className=\"rounded-2xl border border-border/40 overflow-hidden\">\n <Skeleton className=\"aspect-square rounded-none\" />\n <div className=\"p-4 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n </div>\n );\n}\n\nexport function RemixBrowsePage() {\n const { tokens, isLoading, hasMore, error, loadMore } = useRemixableTokens();\n\n return (\n <div className=\"pb-16\">\n <section className=\"px-4 pt-10 max-w-5xl mx-auto\">\n <BackButton />\n <FadeIn>\n <div className=\"mt-6\">\n <ServiceHeader\n plain\n icon={<GitBranch className=\"h-4 w-4 text-white\" />}\n title=\"Remix\"\n subtitle=\"Pick a work that is open to remixing. Attribution and royalties flow back to the original creator.\"\n />\n </div>\n </FadeIn>\n </section>\n\n <section className=\"px-4 pt-8 max-w-5xl mx-auto space-y-6\">\n {isLoading && tokens.length === 0 ? (\n <div className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {Array.from({ length: 8 }).map((_, i) => (\n <RemixableCardSkeleton key={i} />\n ))}\n </div>\n ) : error && tokens.length === 0 ? (\n <div className=\"bento-cell p-10 flex flex-col items-center gap-3 text-center\">\n <p className=\"font-semibold\">Could not load works</p>\n <p className=\"text-sm text-muted-foreground\">Check your connection and try again.</p>\n <Button variant=\"outline\" size=\"sm\" onClick={() => location.reload()}>Retry</Button>\n </div>\n ) : tokens.length === 0 ? (\n <FadeIn>\n <div className=\"bento-cell p-10 flex flex-col items-center gap-4 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/30\" />\n <div>\n <p className=\"font-semibold\">No works open to remixing yet</p>\n <p className=\"text-sm text-muted-foreground mt-1 max-w-sm\">\n Works appear here when their creator sets the license to allow derivatives.\n </p>\n </div>\n </div>\n </FadeIn>\n ) : (\n <>\n <Stagger className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {tokens.map((t) => (\n <StaggerItem key={`${t.contractAddress}-${t.tokenId}`}>\n <RemixableCard token={t} />\n </StaggerItem>\n ))}\n </Stagger>\n {hasMore && (\n <div className=\"flex justify-center\">\n <Button variant=\"outline\" onClick={loadMore} disabled={isLoading}>\n {isLoading ? \"Loading…\" : \"Load more\"}\n </Button>\n </div>\n )}\n </>\n )}\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/remix-browse-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { ServiceHeader } from \"./service-header.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { FadeIn, Stagger, StaggerItem } from \"./motion-primitives.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Button } from \"./button.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\nimport type { ApiToken } from \"@medialane/sdk\";\nimport { GitBranch, ImageIcon, Inbox } from \"lucide-react\";\n\nconst PAGE_SIZE = 24;\n\nfunction useRemixableTokens() {\n const client = useMedialaneClient();\n const [tokens, setTokens] = useState<ApiToken[]>([]);\n const [page, setPage] = useState(1);\n const [isLoading, setIsLoading] = useState(true);\n const [hasMore, setHasMore] = useState(false);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n client.api.tokens.list({ derivatives: \"allowed\", limit: PAGE_SIZE, page })\n .then((json) => {\n if (cancelled) return;\n setTokens((prev) => (page === 1 ? json.data : [...prev, ...json.data]));\n setHasMore(page * PAGE_SIZE < (json.meta?.total ?? 0));\n })\n .catch(() => { if (!cancelled) setError(true); })\n .finally(() => { if (!cancelled) setIsLoading(false); });\n return () => { cancelled = true; };\n }, [client, page]);\n\n return { tokens, isLoading, hasMore, error, loadMore: () => setPage((p) => p + 1) };\n}\n\nfunction RemixableCard({ token }: { token: ApiToken }) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = useImageUrl()(token.metadata?.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const name = token.metadata?.name ?? `#${token.tokenId}`;\n\n return (\n <Link\n href={`/create/remix/${token.contractAddress}/${token.tokenId}`}\n className=\"group flex flex-col rounded-2xl border border-border/60 bg-card overflow-hidden transition-colors sm:hover:border-brand-blue/50 active:scale-[0.99] motion-reduce:transform-none\"\n >\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={name}\n fill\n className=\"object-cover card-media\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <ImageIcon className=\"h-8 w-8 text-muted-foreground/30\" />\n </div>\n )}\n </div>\n <div className=\"p-4 space-y-1\">\n <p className=\"font-semibold text-sm leading-tight truncate\">{name}</p>\n <p className=\"text-xs text-muted-foreground\">\n Derivatives: Allowed\n </p>\n <p className=\"text-xs font-semibold pt-1 inline-flex items-center gap-1.5\">\n <GitBranch className=\"h-3 w-3\" />\n Remix this work\n </p>\n </div>\n </Link>\n );\n}\n\nfunction RemixableCardSkeleton() {\n return (\n <div className=\"rounded-2xl border border-border/40 overflow-hidden\">\n <Skeleton className=\"aspect-square rounded-none\" />\n <div className=\"p-4 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n </div>\n );\n}\n\nexport function RemixBrowsePage() {\n const { tokens, isLoading, hasMore, error, loadMore } = useRemixableTokens();\n\n return (\n <div className=\"pb-16\">\n <section className=\"px-4 pt-10 max-w-5xl mx-auto\">\n <BackButton />\n <FadeIn>\n <div className=\"mt-6\">\n <ServiceHeader\n plain\n icon={<GitBranch className=\"h-4 w-4 text-white\" />}\n title=\"Remix\"\n subtitle=\"Pick a work that is open to remixing. Attribution and royalties flow back to the original creator.\"\n />\n </div>\n </FadeIn>\n </section>\n\n <section className=\"px-4 pt-8 max-w-5xl mx-auto space-y-6\">\n {isLoading && tokens.length === 0 ? (\n <div className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {Array.from({ length: 8 }).map((_, i) => (\n <RemixableCardSkeleton key={i} />\n ))}\n </div>\n ) : error && tokens.length === 0 ? (\n <div className=\"bento-cell p-10 flex flex-col items-center gap-3 text-center\">\n <p className=\"font-semibold\">Could not load works</p>\n <p className=\"text-sm text-muted-foreground\">Check your connection and try again.</p>\n <Button variant=\"outline\" size=\"sm\" onClick={() => location.reload()}>Retry</Button>\n </div>\n ) : tokens.length === 0 ? (\n <FadeIn>\n <div className=\"bento-cell p-10 flex flex-col items-center gap-4 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/30\" />\n <div>\n <p className=\"font-semibold\">No works open to remixing yet</p>\n <p className=\"text-sm text-muted-foreground mt-1 max-w-sm\">\n Works appear here when their creator sets the license to allow derivatives.\n </p>\n </div>\n </div>\n </FadeIn>\n ) : (\n <>\n <Stagger className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {tokens.map((t) => (\n <StaggerItem key={`${t.contractAddress}-${t.tokenId}`}>\n <RemixableCard token={t} />\n </StaggerItem>\n ))}\n </Stagger>\n {hasMore && (\n <div className=\"flex justify-center\">\n <Button variant=\"outline\" onClick={loadMore} disabled={isLoading}>\n {isLoading ? \"Loading…\" : \"Load more\"}\n </Button>\n </div>\n )}\n </>\n )}\n </section>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuDU;AArDV,mBAAoC;AACpC,kBAAiB;AACjB,mBAAkB;AAClB,4BAA8B;AAC9B,yBAA2B;AAC3B,+BAA6C;AAC7C,sBAAyB;AACzB,oBAAuB;AACvB,kCAAmC;AACnC,2BAA4B;AAE5B,0BAA4C;AAE5C,MAAM,YAAY;AAElB,SAAS,qBAAqB;AAC5B,QAAM,aAAS,gDAAmB;AAClC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAqB,CAAC,CAAC;AACnD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,CAAC;AAClC,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,IAAI;AAC/C,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,KAAK;AAExC,8BAAU,MAAM;AACd,QAAI,YAAY;AAChB,iBAAa,IAAI;AACjB,WAAO,IAAI,OAAO,KAAK,EAAE,aAAa,WAAW,OAAO,WAAW,KAAK,CAAC,EACtE,KAAK,CAAC,SAAS;AACd,UAAI,UAAW;AACf,gBAAU,CAAC,SAAU,SAAS,IAAI,KAAK,OAAO,CAAC,GAAG,MAAM,GAAG,KAAK,IAAI,CAAE;AACtE,iBAAW,OAAO,aAAa,KAAK,MAAM,SAAS,EAAE;AAAA,IACvD,CAAC,EACA,MAAM,MAAM;AAAE,UAAI,CAAC,UAAW,UAAS,IAAI;AAAA,IAAG,CAAC,EAC/C,QAAQ,MAAM;AAAE,UAAI,CAAC,UAAW,cAAa,KAAK;AAAA,IAAG,CAAC;AACzD,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAM;AAAA,EACnC,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,SAAO,EAAE,QAAQ,WAAW,SAAS,OAAO,UAAU,MAAM,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE;AACpF;AAEA,SAAS,cAAc,EAAE,MAAM,GAAwB;AACrD,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,eAAW,kCAAY,EAAE,MAAM,UAAU,OAAO,EAAE,OAAO,IAAI,CAAC;AACpE,QAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,OAAO,MAAM,UAAU,QAAQ,IAAI,MAAM,OAAO;AAEtD,SACE;AAAA,IAAC,YAAAA;AAAA,IAAA;AAAA,MACC,MAAM,iBAAiB,MAAM,eAAe,IAAI,MAAM,OAAO;AAAA,MAC7D,WAAU;AAAA,MAEV;AAAA,oDAAC,SAAI,WAAU,mDACZ,sBACC;AAAA,UAAC,aAAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL,MAAI;AAAA,YACJ,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA,YAC/B,aAAW;AAAA;AAAA,QACb,IAEA,4CAAC,SAAI,WAAU,qDACb,sDAAC,iCAAU,WAAU,oCAAmC,GAC1D,GAEJ;AAAA,QACA,6CAAC,SAAI,WAAU,iBACb;AAAA,sDAAC,OAAE,WAAU,gDAAgD,gBAAK;AAAA,UAClE,4CAAC,OAAE,WAAU,iCAAgC,kCAE7C;AAAA,UACA,6CAAC,OAAE,WAAU,+DACX;AAAA,wDAAC,iCAAU,WAAU,WAAU;AAAA,YAAE;AAAA,aAEnC;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,wBAAwB;AAC/B,SACE,6CAAC,SAAI,WAAU,uDACb;AAAA,gDAAC,4BAAS,WAAU,8BAA6B;AAAA,IACjD,6CAAC,SAAI,WAAU,iBACb;AAAA,kDAAC,4BAAS,WAAU,YAAW;AAAA,MAC/B,4CAAC,4BAAS,WAAU,YAAW;AAAA,OACjC;AAAA,KACF;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,EAAE,QAAQ,WAAW,SAAS,OAAO,SAAS,IAAI,mBAAmB;AAE3E,SACE,6CAAC,SAAI,WAAU,SACb;AAAA,iDAAC,aAAQ,WAAU,gCACjB;AAAA,kDAAC,iCAAW;AAAA,MACZ,4CAAC,mCACC,sDAAC,SAAI,WAAU,QACb;AAAA,QAAC;AAAA;AAAA,UACC,OAAK;AAAA,UACL,MAAM,4CAAC,iCAAU,WAAU,sBAAqB;AAAA,UAChD,OAAM;AAAA,UACN,UAAS;AAAA;AAAA,MACX,GACF,GACF;AAAA,OACF;AAAA,IAEA,4CAAC,aAAQ,WAAU,yCAChB,uBAAa,OAAO,WAAW,IAC9B,4CAAC,SAAI,WAAU,wDACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,4CAAC,2BAA2B,CAAG,CAChC,GACH,IACE,SAAS,OAAO,WAAW,IAC7B,6CAAC,SAAI,WAAU,gEACb;AAAA,kDAAC,OAAE,WAAU,iBAAgB,kCAAoB;AAAA,MACjD,4CAAC,OAAE,WAAU,iCAAgC,kDAAoC;AAAA,MACjF,4CAAC,wBAAO,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,SAAS,OAAO,GAAG,mBAAK;AAAA,OAC7E,IACE,OAAO,WAAW,IACpB,4CAAC,mCACC,uDAAC,SAAI,WAAU,gEACb;AAAA,kDAAC,6BAAM,WAAU,sCAAqC;AAAA,MACtD,6CAAC,SACC;AAAA,oDAAC,OAAE,WAAU,iBAAgB,2CAA6B;AAAA,QAC1D,4CAAC,OAAE,WAAU,+CAA8C,yFAE3D;AAAA,SACF;AAAA,OACF,GACF,IAEA,4EACE;AAAA,kDAAC,oCAAQ,WAAU,wDAChB,iBAAO,IAAI,CAAC,MACX,4CAAC,wCACC,sDAAC,iBAAc,OAAO,GAAG,KADT,GAAG,EAAE,eAAe,IAAI,EAAE,OAAO,EAEnD,CACD,GACH;AAAA,MACC,WACC,4CAAC,SAAI,WAAU,uBACb,sDAAC,wBAAO,SAAQ,WAAU,SAAS,UAAU,UAAU,WACpD,sBAAY,kBAAa,aAC5B,GACF;AAAA,OAEJ,GAEJ;AAAA,KACF;AAEJ;","names":["Link","Image"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/remix-browse-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { ServiceHeader } from \"./service-header.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { FadeIn, Stagger, StaggerItem } from \"./motion-primitives.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Button } from \"./button.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\nimport type { ApiToken } from \"@medialane/sdk\";\nimport { GitBranch, ImageIcon, Inbox } from \"lucide-react\";\n\nconst PAGE_SIZE = 24;\n\nfunction useRemixableTokens() {\n const client = useMedialaneClient();\n const [tokens, setTokens] = useState<ApiToken[]>([]);\n const [page, setPage] = useState(1);\n const [isLoading, setIsLoading] = useState(true);\n const [hasMore, setHasMore] = useState(false);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n client.api.tokens.list({ derivatives: \"allowed\", limit: PAGE_SIZE, page })\n .then((json) => {\n if (cancelled) return;\n setTokens((prev) => (page === 1 ? json.data : [...prev, ...json.data]));\n setHasMore(page * PAGE_SIZE < (json.meta?.total ?? 0));\n })\n .catch(() => { if (!cancelled) setError(true); })\n .finally(() => { if (!cancelled) setIsLoading(false); });\n return () => { cancelled = true; };\n }, [client, page]);\n\n return { tokens, isLoading, hasMore, error, loadMore: () => setPage((p) => p + 1) };\n}\n\nfunction RemixableCard({ token }: { token: ApiToken }) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = useImageUrl()(token.metadata?.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const name = token.metadata?.name ?? `#${token.tokenId}`;\n\n return (\n <Link\n href={`/create/remix/${token.contractAddress}/${token.tokenId}`}\n className=\"group flex flex-col rounded-2xl border border-border/60 bg-card overflow-hidden transition-colors sm:hover:border-brand-blue/50 active:scale-[0.99] motion-reduce:transform-none\"\n >\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={name}\n fill\n className=\"object-cover\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <ImageIcon className=\"h-8 w-8 text-muted-foreground/30\" />\n </div>\n )}\n </div>\n <div className=\"p-4 space-y-1\">\n <p className=\"font-semibold text-sm leading-tight truncate\">{name}</p>\n <p className=\"text-xs text-muted-foreground\">\n Derivatives: Allowed\n </p>\n <p className=\"text-xs font-semibold pt-1 inline-flex items-center gap-1.5\">\n <GitBranch className=\"h-3 w-3\" />\n Remix this work\n </p>\n </div>\n </Link>\n );\n}\n\nfunction RemixableCardSkeleton() {\n return (\n <div className=\"rounded-2xl border border-border/40 overflow-hidden\">\n <Skeleton className=\"aspect-square rounded-none\" />\n <div className=\"p-4 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n </div>\n );\n}\n\nexport function RemixBrowsePage() {\n const { tokens, isLoading, hasMore, error, loadMore } = useRemixableTokens();\n\n return (\n <div className=\"pb-16\">\n <section className=\"px-4 pt-10 max-w-5xl mx-auto\">\n <BackButton />\n <FadeIn>\n <div className=\"mt-6\">\n <ServiceHeader\n plain\n icon={<GitBranch className=\"h-4 w-4 text-white\" />}\n title=\"Remix\"\n subtitle=\"Pick a work that is open to remixing. Attribution and royalties flow back to the original creator.\"\n />\n </div>\n </FadeIn>\n </section>\n\n <section className=\"px-4 pt-8 max-w-5xl mx-auto space-y-6\">\n {isLoading && tokens.length === 0 ? (\n <div className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {Array.from({ length: 8 }).map((_, i) => (\n <RemixableCardSkeleton key={i} />\n ))}\n </div>\n ) : error && tokens.length === 0 ? (\n <div className=\"bento-cell p-10 flex flex-col items-center gap-3 text-center\">\n <p className=\"font-semibold\">Could not load works</p>\n <p className=\"text-sm text-muted-foreground\">Check your connection and try again.</p>\n <Button variant=\"outline\" size=\"sm\" onClick={() => location.reload()}>Retry</Button>\n </div>\n ) : tokens.length === 0 ? (\n <FadeIn>\n <div className=\"bento-cell p-10 flex flex-col items-center gap-4 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/30\" />\n <div>\n <p className=\"font-semibold\">No works open to remixing yet</p>\n <p className=\"text-sm text-muted-foreground mt-1 max-w-sm\">\n Works appear here when their creator sets the license to allow derivatives.\n </p>\n </div>\n </div>\n </FadeIn>\n ) : (\n <>\n <Stagger className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {tokens.map((t) => (\n <StaggerItem key={`${t.contractAddress}-${t.tokenId}`}>\n <RemixableCard token={t} />\n </StaggerItem>\n ))}\n </Stagger>\n {hasMore && (\n <div className=\"flex justify-center\">\n <Button variant=\"outline\" onClick={loadMore} disabled={isLoading}>\n {isLoading ? \"Loading…\" : \"Load more\"}\n </Button>\n </div>\n )}\n </>\n )}\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/remix-browse-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { ServiceHeader } from \"./service-header.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { FadeIn, Stagger, StaggerItem } from \"./motion-primitives.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Button } from \"./button.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\nimport type { ApiToken } from \"@medialane/sdk\";\nimport { GitBranch, ImageIcon, Inbox } from \"lucide-react\";\n\nconst PAGE_SIZE = 24;\n\nfunction useRemixableTokens() {\n const client = useMedialaneClient();\n const [tokens, setTokens] = useState<ApiToken[]>([]);\n const [page, setPage] = useState(1);\n const [isLoading, setIsLoading] = useState(true);\n const [hasMore, setHasMore] = useState(false);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n client.api.tokens.list({ derivatives: \"allowed\", limit: PAGE_SIZE, page })\n .then((json) => {\n if (cancelled) return;\n setTokens((prev) => (page === 1 ? json.data : [...prev, ...json.data]));\n setHasMore(page * PAGE_SIZE < (json.meta?.total ?? 0));\n })\n .catch(() => { if (!cancelled) setError(true); })\n .finally(() => { if (!cancelled) setIsLoading(false); });\n return () => { cancelled = true; };\n }, [client, page]);\n\n return { tokens, isLoading, hasMore, error, loadMore: () => setPage((p) => p + 1) };\n}\n\nfunction RemixableCard({ token }: { token: ApiToken }) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = useImageUrl()(token.metadata?.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const name = token.metadata?.name ?? `#${token.tokenId}`;\n\n return (\n <Link\n href={`/create/remix/${token.contractAddress}/${token.tokenId}`}\n className=\"group flex flex-col rounded-2xl border border-border/60 bg-card overflow-hidden transition-colors sm:hover:border-brand-blue/50 active:scale-[0.99] motion-reduce:transform-none\"\n >\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={name}\n fill\n className=\"object-cover card-media\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <ImageIcon className=\"h-8 w-8 text-muted-foreground/30\" />\n </div>\n )}\n </div>\n <div className=\"p-4 space-y-1\">\n <p className=\"font-semibold text-sm leading-tight truncate\">{name}</p>\n <p className=\"text-xs text-muted-foreground\">\n Derivatives: Allowed\n </p>\n <p className=\"text-xs font-semibold pt-1 inline-flex items-center gap-1.5\">\n <GitBranch className=\"h-3 w-3\" />\n Remix this work\n </p>\n </div>\n </Link>\n );\n}\n\nfunction RemixableCardSkeleton() {\n return (\n <div className=\"rounded-2xl border border-border/40 overflow-hidden\">\n <Skeleton className=\"aspect-square rounded-none\" />\n <div className=\"p-4 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n </div>\n );\n}\n\nexport function RemixBrowsePage() {\n const { tokens, isLoading, hasMore, error, loadMore } = useRemixableTokens();\n\n return (\n <div className=\"pb-16\">\n <section className=\"px-4 pt-10 max-w-5xl mx-auto\">\n <BackButton />\n <FadeIn>\n <div className=\"mt-6\">\n <ServiceHeader\n plain\n icon={<GitBranch className=\"h-4 w-4 text-white\" />}\n title=\"Remix\"\n subtitle=\"Pick a work that is open to remixing. Attribution and royalties flow back to the original creator.\"\n />\n </div>\n </FadeIn>\n </section>\n\n <section className=\"px-4 pt-8 max-w-5xl mx-auto space-y-6\">\n {isLoading && tokens.length === 0 ? (\n <div className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {Array.from({ length: 8 }).map((_, i) => (\n <RemixableCardSkeleton key={i} />\n ))}\n </div>\n ) : error && tokens.length === 0 ? (\n <div className=\"bento-cell p-10 flex flex-col items-center gap-3 text-center\">\n <p className=\"font-semibold\">Could not load works</p>\n <p className=\"text-sm text-muted-foreground\">Check your connection and try again.</p>\n <Button variant=\"outline\" size=\"sm\" onClick={() => location.reload()}>Retry</Button>\n </div>\n ) : tokens.length === 0 ? (\n <FadeIn>\n <div className=\"bento-cell p-10 flex flex-col items-center gap-4 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/30\" />\n <div>\n <p className=\"font-semibold\">No works open to remixing yet</p>\n <p className=\"text-sm text-muted-foreground mt-1 max-w-sm\">\n Works appear here when their creator sets the license to allow derivatives.\n </p>\n </div>\n </div>\n </FadeIn>\n ) : (\n <>\n <Stagger className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4\">\n {tokens.map((t) => (\n <StaggerItem key={`${t.contractAddress}-${t.tokenId}`}>\n <RemixableCard token={t} />\n </StaggerItem>\n ))}\n </Stagger>\n {hasMore && (\n <div className=\"flex justify-center\">\n <Button variant=\"outline\" onClick={loadMore} disabled={isLoading}>\n {isLoading ? \"Loading…\" : \"Load more\"}\n </Button>\n </div>\n )}\n </>\n )}\n </section>\n </div>\n );\n}\n"],"mappings":";AAuDU,SAqFA,UArFA,KAmBF,YAnBE;AArDV,SAAS,WAAW,gBAAgB;AACpC,OAAO,UAAU;AACjB,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,QAAQ,SAAS,mBAAmB;AAC7C,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAE5B,SAAS,WAAW,WAAW,aAAa;AAE5C,MAAM,YAAY;AAElB,SAAS,qBAAqB;AAC5B,QAAM,SAAS,mBAAmB;AAClC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAqB,CAAC,CAAC;AACnD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,CAAC;AAClC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AAExC,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,iBAAa,IAAI;AACjB,WAAO,IAAI,OAAO,KAAK,EAAE,aAAa,WAAW,OAAO,WAAW,KAAK,CAAC,EACtE,KAAK,CAAC,SAAS;AACd,UAAI,UAAW;AACf,gBAAU,CAAC,SAAU,SAAS,IAAI,KAAK,OAAO,CAAC,GAAG,MAAM,GAAG,KAAK,IAAI,CAAE;AACtE,iBAAW,OAAO,aAAa,KAAK,MAAM,SAAS,EAAE;AAAA,IACvD,CAAC,EACA,MAAM,MAAM;AAAE,UAAI,CAAC,UAAW,UAAS,IAAI;AAAA,IAAG,CAAC,EAC/C,QAAQ,MAAM;AAAE,UAAI,CAAC,UAAW,cAAa,KAAK;AAAA,IAAG,CAAC;AACzD,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAM;AAAA,EACnC,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,SAAO,EAAE,QAAQ,WAAW,SAAS,OAAO,UAAU,MAAM,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE;AACpF;AAEA,SAAS,cAAc,EAAE,MAAM,GAAwB;AACrD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,WAAW,YAAY,EAAE,MAAM,UAAU,OAAO,EAAE,OAAO,IAAI,CAAC;AACpE,QAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,OAAO,MAAM,UAAU,QAAQ,IAAI,MAAM,OAAO;AAEtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,iBAAiB,MAAM,eAAe,IAAI,MAAM,OAAO;AAAA,MAC7D,WAAU;AAAA,MAEV;AAAA,4BAAC,SAAI,WAAU,mDACZ,sBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL,MAAI;AAAA,YACJ,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA,YAC/B,aAAW;AAAA;AAAA,QACb,IAEA,oBAAC,SAAI,WAAU,qDACb,8BAAC,aAAU,WAAU,oCAAmC,GAC1D,GAEJ;AAAA,QACA,qBAAC,SAAI,WAAU,iBACb;AAAA,8BAAC,OAAE,WAAU,gDAAgD,gBAAK;AAAA,UAClE,oBAAC,OAAE,WAAU,iCAAgC,kCAE7C;AAAA,UACA,qBAAC,OAAE,WAAU,+DACX;AAAA,gCAAC,aAAU,WAAU,WAAU;AAAA,YAAE;AAAA,aAEnC;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,wBAAwB;AAC/B,SACE,qBAAC,SAAI,WAAU,uDACb;AAAA,wBAAC,YAAS,WAAU,8BAA6B;AAAA,IACjD,qBAAC,SAAI,WAAU,iBACb;AAAA,0BAAC,YAAS,WAAU,YAAW;AAAA,MAC/B,oBAAC,YAAS,WAAU,YAAW;AAAA,OACjC;AAAA,KACF;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,EAAE,QAAQ,WAAW,SAAS,OAAO,SAAS,IAAI,mBAAmB;AAE3E,SACE,qBAAC,SAAI,WAAU,SACb;AAAA,yBAAC,aAAQ,WAAU,gCACjB;AAAA,0BAAC,cAAW;AAAA,MACZ,oBAAC,UACC,8BAAC,SAAI,WAAU,QACb;AAAA,QAAC;AAAA;AAAA,UACC,OAAK;AAAA,UACL,MAAM,oBAAC,aAAU,WAAU,sBAAqB;AAAA,UAChD,OAAM;AAAA,UACN,UAAS;AAAA;AAAA,MACX,GACF,GACF;AAAA,OACF;AAAA,IAEA,oBAAC,aAAQ,WAAU,yCAChB,uBAAa,OAAO,WAAW,IAC9B,oBAAC,SAAI,WAAU,wDACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,oBAAC,2BAA2B,CAAG,CAChC,GACH,IACE,SAAS,OAAO,WAAW,IAC7B,qBAAC,SAAI,WAAU,gEACb;AAAA,0BAAC,OAAE,WAAU,iBAAgB,kCAAoB;AAAA,MACjD,oBAAC,OAAE,WAAU,iCAAgC,kDAAoC;AAAA,MACjF,oBAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,SAAS,OAAO,GAAG,mBAAK;AAAA,OAC7E,IACE,OAAO,WAAW,IACpB,oBAAC,UACC,+BAAC,SAAI,WAAU,gEACb;AAAA,0BAAC,SAAM,WAAU,sCAAqC;AAAA,MACtD,qBAAC,SACC;AAAA,4BAAC,OAAE,WAAU,iBAAgB,2CAA6B;AAAA,QAC1D,oBAAC,OAAE,WAAU,+CAA8C,yFAE3D;AAAA,SACF;AAAA,OACF,GACF,IAEA,iCACE;AAAA,0BAAC,WAAQ,WAAU,wDAChB,iBAAO,IAAI,CAAC,MACX,oBAAC,eACC,8BAAC,iBAAc,OAAO,GAAG,KADT,GAAG,EAAE,eAAe,IAAI,EAAE,OAAO,EAEnD,CACD,GACH;AAAA,MACC,WACC,oBAAC,SAAI,WAAU,uBACb,8BAAC,UAAO,SAAQ,WAAU,SAAS,UAAU,UAAU,WACpD,sBAAY,kBAAa,aAC5B,GACF;AAAA,OAEJ,GAEJ;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -10,7 +10,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
|
|
|
10
10
|
declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
|
|
11
11
|
declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const sheetVariants: (props?: ({
|
|
13
|
-
side?: "
|
|
13
|
+
side?: "bottom" | "left" | "right" | "top" | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
15
15
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
|
|
16
16
|
overlayClassName?: string;
|
|
@@ -10,7 +10,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
|
|
|
10
10
|
declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
|
|
11
11
|
declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const sheetVariants: (props?: ({
|
|
13
|
-
side?: "
|
|
13
|
+
side?: "bottom" | "left" | "right" | "top" | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
15
15
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
|
|
16
16
|
overlayClassName?: string;
|
|
@@ -69,6 +69,7 @@ function TokenCard({
|
|
|
69
69
|
(o) => o.offer.itemType === "ERC721" || o.offer.itemType === "ERC1155"
|
|
70
70
|
);
|
|
71
71
|
const profileLink = (0, import_token_profile_link.tokenProfileLink)(token);
|
|
72
|
+
const hasPrimaryAction = isOwner ? !listingOrder : listingOrder ? !!onBuy : !!onOffer;
|
|
72
73
|
const chain = token.chain.toUpperCase();
|
|
73
74
|
const live = (0, import_living_render_collections.isLivingRenderCollection)(chain, token.contractAddress);
|
|
74
75
|
const assetHref = (0, import_sdk.assetHref)(chain, token.contractAddress, token.tokenId);
|
|
@@ -84,7 +85,7 @@ function TokenCard({
|
|
|
84
85
|
e.stopPropagation();
|
|
85
86
|
onOffer?.(token);
|
|
86
87
|
};
|
|
87
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "card-base relative overflow-hidden flex flex-col w-full", children: [
|
|
88
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "card-base group relative overflow-hidden flex flex-col w-full", children: [
|
|
88
89
|
ipType && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute top-2 right-2 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType, size: "sm" }) }),
|
|
89
90
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: assetHref, className: "flex flex-col flex-1", children: [
|
|
90
91
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-square bg-muted overflow-hidden shrink-0", children: [
|
|
@@ -118,19 +119,11 @@ function TokenCard({
|
|
|
118
119
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-3 pt-2.5 pb-4 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-base font-bold line-clamp-2 leading-snug", children: name }) })
|
|
119
120
|
] }),
|
|
120
121
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-3 pb-3 flex items-center gap-1.5", children: [
|
|
121
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
href: assetHref,
|
|
125
|
-
className: (0, import_cn.cn)(BTN_OUTLINE, "w-8 shrink-0 px-0"),
|
|
126
|
-
title: "View asset",
|
|
127
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpRight, { className: "h-3.5 w-3.5" })
|
|
128
|
-
}
|
|
129
|
-
),
|
|
130
|
-
isOwner ? listingOrder ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: assetHref, className: (0, import_cn.cn)(BTN_OUTLINE, "flex-1"), children: [
|
|
131
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpRight, { className: "h-3.5 w-3.5 mr-1.5" }),
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: assetHref, className: (0, import_cn.cn)(BTN_OUTLINE, "px-2.5", hasPrimaryAction ? "shrink-0" : "flex-1"), children: [
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpRight, { className: "h-3.5 w-3.5" }),
|
|
132
124
|
"View"
|
|
133
|
-
] })
|
|
125
|
+
] }),
|
|
126
|
+
isOwner ? !listingOrder ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
134
127
|
"button",
|
|
135
128
|
{
|
|
136
129
|
className: (0, import_cn.cn)(BTN_OUTLINE, "flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple"),
|
|
@@ -144,7 +137,7 @@ function TokenCard({
|
|
|
144
137
|
"List"
|
|
145
138
|
]
|
|
146
139
|
}
|
|
147
|
-
) : listingOrder && onBuy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
140
|
+
) : null : listingOrder && onBuy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
148
141
|
"button",
|
|
149
142
|
{
|
|
150
143
|
className: "w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]",
|
|
@@ -164,10 +157,7 @@ function TokenCard({
|
|
|
164
157
|
"Offer"
|
|
165
158
|
]
|
|
166
159
|
}
|
|
167
|
-
) :
|
|
168
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpRight, { className: "h-3.5 w-3.5 mr-1.5" }),
|
|
169
|
-
"View"
|
|
170
|
-
] }),
|
|
160
|
+
) : null,
|
|
171
161
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_dropdown_menu.DropdownMenu, { children: [
|
|
172
162
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dropdown_menu.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
173
163
|
"button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport {\n Loader2, ArrowUpRight, MoreHorizontal, Zap, HandCoins, Tag,\n Layers, GitBranch, Flag, UserCircle2, ArrowRightLeft, XCircle,\n} from \"lucide-react\";\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuSeparator, DropdownMenuTrigger,\n} from \"./dropdown-menu.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { PriceChipContent } from \"./dual-price.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\nimport { tokenProfileLink } from \"../utils/token-profile-link.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\n\nconst BTN_BASE = \"h-8 rounded-[9px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n isOwner?: boolean;\n onList?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onBuy?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n\n usdValue?: string | null;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n usdValue,\n}: TokenCardProps) {\n const resolveImage = useImageUrl();\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image, { width: 480 });\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const profileLink = tokenProfileLink(token);\n\n const chain = token.chain.toUpperCase() as Chain;\n const live = isLivingRenderCollection(chain, token.contractAddress);\n const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);\n const collectionHref = buildCollectionHref(chain, token.contractAddress);\n const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;\n\n const handleBuy = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onBuy?.(token);\n };\n\n const handleOffer = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onOffer?.(token);\n };\n\n return (\n <div className=\"card-base relative overflow-hidden flex flex-col w-full\">\n {ipType && (\n <div className=\"absolute top-2 right-2 z-10\">\n <IpTypeBadge ipType={ipType as any} size=\"sm\" />\n </div>\n )}\n\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n\n {listingOrder && (\n <div className=\"absolute bottom-2 right-2 z-10\">\n <span className=\"inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-full text-sm font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm tabular-nums\">\n <PriceChipContent\n amountFormatted={listingOrder.price.formatted}\n currency={listingOrder.price.currency}\n usdValue={usdValue}\n tone=\"card\"\n />\n </span>\n </div>\n )}\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-2xs text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n <div className=\"px-3 pt-2.5 pb-4 flex-1\">\n <p className=\"text-base font-bold line-clamp-2 leading-snug\">{name}</p>\n </div>\n </Link>\n\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n <Link\n href={assetHref}\n className={cn(BTN_OUTLINE, \"w-8 shrink-0 px-0\")}\n title=\"View asset\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n </Link>\n\n {isOwner ? (\n listingOrder ? (\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5 mr-1.5\" />\n View\n </Link>\n ) : (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList?.(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 mr-1.5\" />\n List\n </button>\n )\n ) : listingOrder && onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n </div>\n ) : !listingOrder && onOffer ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-orange border-brand-orange/30 hover:bg-brand-orange/10 hover:text-brand-orange\")}\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5 mr-1.5\" />\n Offer\n </button>\n ) : (\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5 mr-1.5\" />\n View\n </Link>\n )}\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n className={cn(BTN_OUTLINE, \"w-8 p-0 shrink-0\")}\n aria-label=\"More actions\"\n >\n <MoreHorizontal className=\"h-3.5 w-3.5\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n\n <DropdownMenuItem asChild>\n <Link href={assetHref} className=\"flex items-center gap-2\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View asset\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n {isOwner ? (\n <>\n {!listingOrder && onList && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\"\n onClick={() => onList(token)}\n >\n <Tag className=\"h-3.5 w-3.5\" />\n List\n </DropdownMenuItem>\n )}\n {onTransfer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2\"\n onClick={() => onTransfer(token)}\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5 text-muted-foreground\" />\n Transfer\n </DropdownMenuItem>\n )}\n {listingOrder && onCancel && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={() => onCancel(token)}\n >\n <XCircle className=\"h-3.5 w-3.5\" />\n Cancel listing\n </DropdownMenuItem>\n )}\n </>\n ) : (\n <>\n {listingOrder && onBuy && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-blue focus:text-brand-blue\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5\" />\n <span className=\"flex items-center gap-1\">\n Buy —\n <CurrencyIcon symbol={listingOrder.price.currency} size={12} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n </span>\n </DropdownMenuItem>\n )}\n {onOffer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n Make offer\n </DropdownMenuItem>\n )}\n </>\n )}\n\n <DropdownMenuItem asChild>\n <Link href={remixHref} className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\">\n <GitBranch className=\"h-3.5 w-3.5\" />\n Remix\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild>\n <Link href={collectionHref} className=\"flex items-center gap-2\">\n <Layers className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View collection\n </Link>\n </DropdownMenuItem>\n\n {profileLink && (\n <DropdownMenuItem asChild>\n <Link href={profileLink.href} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {profileLink.label}\n </Link>\n </DropdownMenuItem>\n )}\n\n {onReport && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-muted-foreground focus:text-muted-foreground\"\n onClick={() => onReport(token)}\n >\n <Flag className=\"h-3.5 w-3.5\" />\n Report\n </DropdownMenuItem>\n </>\n )}\n\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-3 space-y-1.5\">\n <div className=\"h-4 w-3/4 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-3 pb-3 flex gap-1.5\">\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 flex-1 rounded-[9px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["buildAssetHref","buildCollectionHref","Link"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport {\n Loader2, ArrowUpRight, MoreHorizontal, Zap, HandCoins, Tag,\n Layers, GitBranch, Flag, UserCircle2, ArrowRightLeft, XCircle,\n} from \"lucide-react\";\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuSeparator, DropdownMenuTrigger,\n} from \"./dropdown-menu.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { PriceChipContent } from \"./dual-price.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\nimport { tokenProfileLink } from \"../utils/token-profile-link.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\n\nconst BTN_BASE = \"h-8 rounded-[9px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n isOwner?: boolean;\n onList?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onBuy?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n\n usdValue?: string | null;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n usdValue,\n}: TokenCardProps) {\n const resolveImage = useImageUrl();\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image, { width: 480 });\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const profileLink = tokenProfileLink(token);\n const hasPrimaryAction = isOwner ? !listingOrder : listingOrder ? !!onBuy : !!onOffer;\n\n const chain = token.chain.toUpperCase() as Chain;\n const live = isLivingRenderCollection(chain, token.contractAddress);\n const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);\n const collectionHref = buildCollectionHref(chain, token.contractAddress);\n const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;\n\n const handleBuy = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onBuy?.(token);\n };\n\n const handleOffer = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onOffer?.(token);\n };\n\n return (\n <div className=\"card-base group relative overflow-hidden flex flex-col w-full\">\n {ipType && (\n <div className=\"absolute top-2 right-2 z-10\">\n <IpTypeBadge ipType={ipType as any} size=\"sm\" />\n </div>\n )}\n\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n\n {listingOrder && (\n <div className=\"absolute bottom-2 right-2 z-10\">\n <span className=\"inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-full text-sm font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm tabular-nums\">\n <PriceChipContent\n amountFormatted={listingOrder.price.formatted}\n currency={listingOrder.price.currency}\n usdValue={usdValue}\n tone=\"card\"\n />\n </span>\n </div>\n )}\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-2xs text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n <div className=\"px-3 pt-2.5 pb-4 flex-1\">\n <p className=\"text-base font-bold line-clamp-2 leading-snug\">{name}</p>\n </div>\n </Link>\n\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"px-2.5\", hasPrimaryAction ? \"shrink-0\" : \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n View\n </Link>\n\n {isOwner ? (\n !listingOrder ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList?.(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 mr-1.5\" />\n List\n </button>\n ) : null\n ) : listingOrder && onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n </div>\n ) : !listingOrder && onOffer ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-orange border-brand-orange/30 hover:bg-brand-orange/10 hover:text-brand-orange\")}\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5 mr-1.5\" />\n Offer\n </button>\n ) : null}\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n className={cn(BTN_OUTLINE, \"w-8 p-0 shrink-0\")}\n aria-label=\"More actions\"\n >\n <MoreHorizontal className=\"h-3.5 w-3.5\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n\n <DropdownMenuItem asChild>\n <Link href={assetHref} className=\"flex items-center gap-2\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View asset\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n {isOwner ? (\n <>\n {!listingOrder && onList && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\"\n onClick={() => onList(token)}\n >\n <Tag className=\"h-3.5 w-3.5\" />\n List\n </DropdownMenuItem>\n )}\n {onTransfer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2\"\n onClick={() => onTransfer(token)}\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5 text-muted-foreground\" />\n Transfer\n </DropdownMenuItem>\n )}\n {listingOrder && onCancel && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={() => onCancel(token)}\n >\n <XCircle className=\"h-3.5 w-3.5\" />\n Cancel listing\n </DropdownMenuItem>\n )}\n </>\n ) : (\n <>\n {listingOrder && onBuy && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-blue focus:text-brand-blue\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5\" />\n <span className=\"flex items-center gap-1\">\n Buy —\n <CurrencyIcon symbol={listingOrder.price.currency} size={12} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n </span>\n </DropdownMenuItem>\n )}\n {onOffer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n Make offer\n </DropdownMenuItem>\n )}\n </>\n )}\n\n <DropdownMenuItem asChild>\n <Link href={remixHref} className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\">\n <GitBranch className=\"h-3.5 w-3.5\" />\n Remix\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild>\n <Link href={collectionHref} className=\"flex items-center gap-2\">\n <Layers className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View collection\n </Link>\n </DropdownMenuItem>\n\n {profileLink && (\n <DropdownMenuItem asChild>\n <Link href={profileLink.href} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {profileLink.label}\n </Link>\n </DropdownMenuItem>\n )}\n\n {onReport && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-muted-foreground focus:text-muted-foreground\"\n onClick={() => onReport(token)}\n >\n <Flag className=\"h-3.5 w-3.5\" />\n Report\n </DropdownMenuItem>\n </>\n )}\n\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-3 space-y-1.5\">\n <div className=\"h-4 w-3/4 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-3 pb-3 flex gap-1.5\">\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 flex-1 rounded-[9px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["buildAssetHref","buildCollectionHref","Link"]}
|