@medialane/ui 0.83.0 → 0.85.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/animated-token-media.cjs +100 -0
- package/dist/components/animated-token-media.cjs.map +1 -0
- package/dist/components/animated-token-media.d.cts +28 -0
- package/dist/components/animated-token-media.d.ts +28 -0
- package/dist/components/animated-token-media.js +66 -0
- package/dist/components/animated-token-media.js.map +1 -0
- package/dist/components/asset-card.cjs +14 -13
- package/dist/components/asset-card.cjs.map +1 -1
- package/dist/components/asset-card.d.cts +5 -1
- package/dist/components/asset-card.d.ts +5 -1
- package/dist/components/asset-card.js +14 -13
- package/dist/components/asset-card.js.map +1 -1
- package/dist/components/asset-top-sections.cjs +58 -27
- package/dist/components/asset-top-sections.cjs.map +1 -1
- package/dist/components/asset-top-sections.d.cts +19 -2
- package/dist/components/asset-top-sections.d.ts +19 -2
- package/dist/components/asset-top-sections.js +58 -27
- package/dist/components/asset-top-sections.js.map +1 -1
- package/dist/components/nav-command-menu.cjs +10 -3
- package/dist/components/nav-command-menu.cjs.map +1 -1
- package/dist/components/nav-command-menu.d.cts +13 -1
- package/dist/components/nav-command-menu.d.ts +13 -1
- package/dist/components/nav-command-menu.js +10 -3
- package/dist/components/nav-command-menu.js.map +1 -1
- package/dist/components/token-card.cjs +15 -13
- package/dist/components/token-card.cjs.map +1 -1
- package/dist/components/token-card.js +15 -13
- package/dist/components/token-card.js.map +1 -1
- package/dist/data/living-render-collections.cjs +43 -0
- package/dist/data/living-render-collections.cjs.map +1 -0
- package/dist/data/living-render-collections.d.cts +16 -0
- package/dist/data/living-render-collections.d.ts +16 -0
- package/dist/data/living-render-collections.js +18 -0
- package/dist/data/living-render-collections.js.map +1 -0
- package/dist/index.cjs +11 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/use-intersection-active.cjs +49 -0
- package/dist/utils/use-intersection-active.cjs.map +1 -0
- package/dist/utils/use-intersection-active.d.cts +12 -0
- package/dist/utils/use-intersection-active.d.ts +12 -0
- package/dist/utils/use-intersection-active.js +25 -0
- package/dist/utils/use-intersection-active.js.map +1 -0
- package/package.json +4 -3
|
@@ -34,9 +34,7 @@ __export(token_card_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(token_card_exports);
|
|
36
36
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
37
|
-
var import_react = require("react");
|
|
38
37
|
var import_link = __toESM(require("next/link"), 1);
|
|
39
|
-
var import_image = __toESM(require("next/image"), 1);
|
|
40
38
|
var import_lucide_react = require("lucide-react");
|
|
41
39
|
var import_dropdown_menu = require("./dropdown-menu.js");
|
|
42
40
|
var import_cn = require("../utils/cn.js");
|
|
@@ -44,6 +42,8 @@ var import_ipfs = require("../utils/ipfs.js");
|
|
|
44
42
|
var import_format = require("../utils/format.js");
|
|
45
43
|
var import_currency_icon = require("./currency-icon.js");
|
|
46
44
|
var import_ip_type_badge = require("./ip-type-badge.js");
|
|
45
|
+
var import_animated_token_media = require("./animated-token-media.js");
|
|
46
|
+
var import_living_render_collections = require("../data/living-render-collections.js");
|
|
47
47
|
var import_sdk = require("@medialane/sdk");
|
|
48
48
|
const 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";
|
|
49
49
|
const BTN_OUTLINE = (0, import_cn.cn)(BTN_BASE, "border border-border/60 text-foreground hover:bg-muted/60");
|
|
@@ -57,9 +57,9 @@ function TokenCard({
|
|
|
57
57
|
onOffer,
|
|
58
58
|
onReport
|
|
59
59
|
}) {
|
|
60
|
-
const [imgError, setImgError] = (0, import_react.useState)(false);
|
|
61
60
|
const name = token.metadata?.name || `Token #${token.tokenId}`;
|
|
62
61
|
const image = (0, import_ipfs.ipfsToHttp)(token.metadata?.image);
|
|
62
|
+
const animationUrl = token.metadata?.animationUrl ?? null;
|
|
63
63
|
const ipType = token.metadata?.ipType;
|
|
64
64
|
const listingOrder = token.activeOrders?.find(
|
|
65
65
|
(o) => o.offer.itemType === "ERC721" || o.offer.itemType === "ERC1155"
|
|
@@ -68,6 +68,7 @@ function TokenCard({
|
|
|
68
68
|
const creator = typeof creatorAttr?.value === "string" ? creatorAttr.value : null;
|
|
69
69
|
const owner = token.balances?.[0]?.owner ?? token.owner ?? null;
|
|
70
70
|
const chain = token.chain.toUpperCase();
|
|
71
|
+
const live = (0, import_living_render_collections.isLivingRenderCollection)(chain, token.contractAddress);
|
|
71
72
|
const assetHref = (0, import_sdk.assetHref)(chain, token.contractAddress, token.tokenId);
|
|
72
73
|
const collectionHref = (0, import_sdk.collectionHref)(chain, token.contractAddress);
|
|
73
74
|
const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;
|
|
@@ -84,21 +85,22 @@ function TokenCard({
|
|
|
84
85
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "card-base relative overflow-hidden flex flex-col w-full", children: [
|
|
85
86
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: assetHref, className: "flex flex-col flex-1", children: [
|
|
86
87
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-square bg-muted overflow-hidden shrink-0", children: [
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
89
|
+
import_animated_token_media.AnimatedTokenMedia,
|
|
89
90
|
{
|
|
90
|
-
|
|
91
|
+
image,
|
|
92
|
+
animationUrl,
|
|
93
|
+
live,
|
|
91
94
|
alt: name,
|
|
92
|
-
|
|
93
|
-
unoptimized: true,
|
|
95
|
+
mode: "fill",
|
|
94
96
|
sizes: "(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw",
|
|
95
97
|
className: "object-cover",
|
|
96
|
-
|
|
98
|
+
fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-2xl tabular-nums text-muted-foreground", children: [
|
|
99
|
+
"#",
|
|
100
|
+
token.tokenId
|
|
101
|
+
] }) })
|
|
97
102
|
}
|
|
98
|
-
)
|
|
99
|
-
"#",
|
|
100
|
-
token.tokenId
|
|
101
|
-
] }) }),
|
|
103
|
+
),
|
|
102
104
|
listingOrder && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-2 right-2 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm", children: [
|
|
103
105
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: listingOrder.price.currency ?? "", size: 10 }),
|
|
104
106
|
(0, import_format.formatDisplayPrice)(listingOrder.price.formatted),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\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\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n}: TokenCardProps) {\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = ipfsToHttp(token.metadata?.image);\n const ipType = token.metadata?.ipType;\n\n // First listing-type active order (offer.itemType = ERC721 or ERC1155)\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const creatorAttr = token.metadata?.attributes?.find((a) => a.trait_type === \"Creator\");\n const creator = typeof creatorAttr?.value === \"string\" ? creatorAttr.value : null;\n const owner = token.balances?.[0]?.owner ?? token.owner ?? null;\n\n const chain = token.chain.toUpperCase() as Chain;\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\n {/* ── Clickable image + info ─────────────────────────────── */}\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n {/* Image */}\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n {!imgError ? (\n <Image\n src={image}\n alt={name}\n fill\n unoptimized\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl tabular-nums text-muted-foreground\">#{token.tokenId}</span>\n </div>\n )}\n\n {/* Price chip — bottom right overlay */}\n {listingOrder && (\n <div className=\"absolute bottom-2 right-2 z-10\">\n <span className=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm\">\n <CurrencyIcon symbol={listingOrder.price.currency ?? \"\"} size={10} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n <span className=\"text-muted-foreground font-normal\">{listingOrder.price.currency}</span>\n </span>\n </div>\n )}\n\n {/* Indexing indicator */}\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-[10px] text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n {/* Info */}\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 className=\"flex items-center gap-1.5 mt-1.5 flex-wrap\">\n {ipType && <IpTypeBadge ipType={ipType as any} size=\"sm\" />}\n {creator ? (\n <p className=\"text-[10px] tabular-nums text-muted-foreground/60 truncate\">\n {creator.slice(0, 8)}…{creator.slice(-6)}\n </p>\n ) : token.metadata?.description ? (\n <p className=\"text-[10px] text-muted-foreground truncate leading-snug\">\n {token.metadata.description}\n </p>\n ) : null}\n </div>\n </div>\n </Link>\n\n {/* ── Action row ────────────────────────────────────────── */}\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n {/* Expand */}\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 {/* Owner: List (or Listed label) — Buyer: Buy / Make offer */}\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 ? (\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 ) : (\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\n {/* 3-dot menu */}\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 {(owner ?? creator) && (\n <DropdownMenuItem asChild>\n <Link href={`/account/${owner ?? creator}`} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View owner\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 className=\"h-2.5 w-2/5 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","Image"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.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\";\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\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n}: TokenCardProps) {\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = ipfsToHttp(token.metadata?.image);\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n // First listing-type active order (offer.itemType = ERC721 or ERC1155)\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const creatorAttr = token.metadata?.attributes?.find((a) => a.trait_type === \"Creator\");\n const creator = typeof creatorAttr?.value === \"string\" ? creatorAttr.value : null;\n const owner = token.balances?.[0]?.owner ?? token.owner ?? null;\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\n {/* ── Clickable image + info ─────────────────────────────── */}\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n {/* Image */}\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl tabular-nums text-muted-foreground\">#{token.tokenId}</span>\n </div>\n }\n />\n\n {/* Price chip — bottom right overlay */}\n {listingOrder && (\n <div className=\"absolute bottom-2 right-2 z-10\">\n <span className=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm\">\n <CurrencyIcon symbol={listingOrder.price.currency ?? \"\"} size={10} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n <span className=\"text-muted-foreground font-normal\">{listingOrder.price.currency}</span>\n </span>\n </div>\n )}\n\n {/* Indexing indicator */}\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-[10px] text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n {/* Info */}\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 className=\"flex items-center gap-1.5 mt-1.5 flex-wrap\">\n {ipType && <IpTypeBadge ipType={ipType as any} size=\"sm\" />}\n {creator ? (\n <p className=\"text-[10px] tabular-nums text-muted-foreground/60 truncate\">\n {creator.slice(0, 8)}…{creator.slice(-6)}\n </p>\n ) : token.metadata?.description ? (\n <p className=\"text-[10px] text-muted-foreground truncate leading-snug\">\n {token.metadata.description}\n </p>\n ) : null}\n </div>\n </div>\n </Link>\n\n {/* ── Action row ────────────────────────────────────────── */}\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n {/* Expand */}\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 {/* Owner: List (or Listed label) — Buyer: Buy / Make offer */}\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 ? (\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 ) : (\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\n {/* 3-dot menu */}\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 {(owner ?? creator) && (\n <DropdownMenuItem asChild>\n <Link href={`/account/${owner ?? creator}`} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View owner\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 className=\"h-2.5 w-2/5 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,8 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
4
3
|
import Link from "next/link";
|
|
5
|
-
import Image from "next/image";
|
|
6
4
|
import {
|
|
7
5
|
Loader2,
|
|
8
6
|
ArrowUpRight,
|
|
@@ -29,6 +27,8 @@ import { ipfsToHttp } from "../utils/ipfs.js";
|
|
|
29
27
|
import { formatDisplayPrice } from "../utils/format.js";
|
|
30
28
|
import { CurrencyIcon } from "./currency-icon.js";
|
|
31
29
|
import { IpTypeBadge } from "./ip-type-badge.js";
|
|
30
|
+
import { AnimatedTokenMedia } from "./animated-token-media.js";
|
|
31
|
+
import { isLivingRenderCollection } from "../data/living-render-collections.js";
|
|
32
32
|
import { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from "@medialane/sdk";
|
|
33
33
|
const 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";
|
|
34
34
|
const BTN_OUTLINE = cn(BTN_BASE, "border border-border/60 text-foreground hover:bg-muted/60");
|
|
@@ -42,9 +42,9 @@ function TokenCard({
|
|
|
42
42
|
onOffer,
|
|
43
43
|
onReport
|
|
44
44
|
}) {
|
|
45
|
-
const [imgError, setImgError] = useState(false);
|
|
46
45
|
const name = token.metadata?.name || `Token #${token.tokenId}`;
|
|
47
46
|
const image = ipfsToHttp(token.metadata?.image);
|
|
47
|
+
const animationUrl = token.metadata?.animationUrl ?? null;
|
|
48
48
|
const ipType = token.metadata?.ipType;
|
|
49
49
|
const listingOrder = token.activeOrders?.find(
|
|
50
50
|
(o) => o.offer.itemType === "ERC721" || o.offer.itemType === "ERC1155"
|
|
@@ -53,6 +53,7 @@ function TokenCard({
|
|
|
53
53
|
const creator = typeof creatorAttr?.value === "string" ? creatorAttr.value : null;
|
|
54
54
|
const owner = token.balances?.[0]?.owner ?? token.owner ?? null;
|
|
55
55
|
const chain = token.chain.toUpperCase();
|
|
56
|
+
const live = isLivingRenderCollection(chain, token.contractAddress);
|
|
56
57
|
const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);
|
|
57
58
|
const collectionHref = buildCollectionHref(chain, token.contractAddress);
|
|
58
59
|
const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;
|
|
@@ -69,21 +70,22 @@ function TokenCard({
|
|
|
69
70
|
return /* @__PURE__ */ jsxs("div", { className: "card-base relative overflow-hidden flex flex-col w-full", children: [
|
|
70
71
|
/* @__PURE__ */ jsxs(Link, { href: assetHref, className: "flex flex-col flex-1", children: [
|
|
71
72
|
/* @__PURE__ */ jsxs("div", { className: "relative aspect-square bg-muted overflow-hidden shrink-0", children: [
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
AnimatedTokenMedia,
|
|
74
75
|
{
|
|
75
|
-
|
|
76
|
+
image,
|
|
77
|
+
animationUrl,
|
|
78
|
+
live,
|
|
76
79
|
alt: name,
|
|
77
|
-
|
|
78
|
-
unoptimized: true,
|
|
80
|
+
mode: "fill",
|
|
79
81
|
sizes: "(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw",
|
|
80
82
|
className: "object-cover",
|
|
81
|
-
|
|
83
|
+
fallback: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15", children: /* @__PURE__ */ jsxs("span", { className: "text-2xl tabular-nums text-muted-foreground", children: [
|
|
84
|
+
"#",
|
|
85
|
+
token.tokenId
|
|
86
|
+
] }) })
|
|
82
87
|
}
|
|
83
|
-
)
|
|
84
|
-
"#",
|
|
85
|
-
token.tokenId
|
|
86
|
-
] }) }),
|
|
88
|
+
),
|
|
87
89
|
listingOrder && /* @__PURE__ */ jsx("div", { className: "absolute bottom-2 right-2 z-10", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm", children: [
|
|
88
90
|
/* @__PURE__ */ jsx(CurrencyIcon, { symbol: listingOrder.price.currency ?? "", size: 10 }),
|
|
89
91
|
formatDisplayPrice(listingOrder.price.formatted),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\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\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n}: TokenCardProps) {\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = ipfsToHttp(token.metadata?.image);\n const ipType = token.metadata?.ipType;\n\n // First listing-type active order (offer.itemType = ERC721 or ERC1155)\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const creatorAttr = token.metadata?.attributes?.find((a) => a.trait_type === \"Creator\");\n const creator = typeof creatorAttr?.value === \"string\" ? creatorAttr.value : null;\n const owner = token.balances?.[0]?.owner ?? token.owner ?? null;\n\n const chain = token.chain.toUpperCase() as Chain;\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\n {/* ── Clickable image + info ─────────────────────────────── */}\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n {/* Image */}\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n {!imgError ? (\n <Image\n src={image}\n alt={name}\n fill\n unoptimized\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl tabular-nums text-muted-foreground\">#{token.tokenId}</span>\n </div>\n )}\n\n {/* Price chip — bottom right overlay */}\n {listingOrder && (\n <div className=\"absolute bottom-2 right-2 z-10\">\n <span className=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm\">\n <CurrencyIcon symbol={listingOrder.price.currency ?? \"\"} size={10} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n <span className=\"text-muted-foreground font-normal\">{listingOrder.price.currency}</span>\n </span>\n </div>\n )}\n\n {/* Indexing indicator */}\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-[10px] text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n {/* Info */}\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 className=\"flex items-center gap-1.5 mt-1.5 flex-wrap\">\n {ipType && <IpTypeBadge ipType={ipType as any} size=\"sm\" />}\n {creator ? (\n <p className=\"text-[10px] tabular-nums text-muted-foreground/60 truncate\">\n {creator.slice(0, 8)}…{creator.slice(-6)}\n </p>\n ) : token.metadata?.description ? (\n <p className=\"text-[10px] text-muted-foreground truncate leading-snug\">\n {token.metadata.description}\n </p>\n ) : null}\n </div>\n </div>\n </Link>\n\n {/* ── Action row ────────────────────────────────────────── */}\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n {/* Expand */}\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 {/* Owner: List (or Listed label) — Buyer: Buy / Make offer */}\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 ? (\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 ) : (\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\n {/* 3-dot menu */}\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 {(owner ?? creator) && (\n <DropdownMenuItem asChild>\n <Link href={`/account/${owner ?? creator}`} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View owner\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 className=\"h-2.5 w-2/5 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":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.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\";\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\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n}: TokenCardProps) {\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = ipfsToHttp(token.metadata?.image);\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n // First listing-type active order (offer.itemType = ERC721 or ERC1155)\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const creatorAttr = token.metadata?.attributes?.find((a) => a.trait_type === \"Creator\");\n const creator = typeof creatorAttr?.value === \"string\" ? creatorAttr.value : null;\n const owner = token.balances?.[0]?.owner ?? token.owner ?? null;\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\n {/* ── Clickable image + info ─────────────────────────────── */}\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n {/* Image */}\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl tabular-nums text-muted-foreground\">#{token.tokenId}</span>\n </div>\n }\n />\n\n {/* Price chip — bottom right overlay */}\n {listingOrder && (\n <div className=\"absolute bottom-2 right-2 z-10\">\n <span className=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-[11px] font-bold bg-background/90 backdrop-blur-sm border border-border/40 shadow-sm\">\n <CurrencyIcon symbol={listingOrder.price.currency ?? \"\"} size={10} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n <span className=\"text-muted-foreground font-normal\">{listingOrder.price.currency}</span>\n </span>\n </div>\n )}\n\n {/* Indexing indicator */}\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-[10px] text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n {/* Info */}\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 className=\"flex items-center gap-1.5 mt-1.5 flex-wrap\">\n {ipType && <IpTypeBadge ipType={ipType as any} size=\"sm\" />}\n {creator ? (\n <p className=\"text-[10px] tabular-nums text-muted-foreground/60 truncate\">\n {creator.slice(0, 8)}…{creator.slice(-6)}\n </p>\n ) : token.metadata?.description ? (\n <p className=\"text-[10px] text-muted-foreground truncate leading-snug\">\n {token.metadata.description}\n </p>\n ) : null}\n </div>\n </div>\n </Link>\n\n {/* ── Action row ────────────────────────────────────────── */}\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n {/* Expand */}\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 {/* Owner: List (or Listed label) — Buyer: Buy / Make offer */}\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 ? (\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 ) : (\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\n {/* 3-dot menu */}\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 {(owner ?? creator) && (\n <DropdownMenuItem asChild>\n <Link href={`/account/${owner ?? creator}`} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View owner\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 className=\"h-2.5 w-2/5 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":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var living_render_collections_exports = {};
|
|
20
|
+
__export(living_render_collections_exports, {
|
|
21
|
+
LIVING_RENDER_COLLECTIONS: () => LIVING_RENDER_COLLECTIONS,
|
|
22
|
+
isLivingRenderCollection: () => isLivingRenderCollection
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(living_render_collections_exports);
|
|
25
|
+
var import_sdk = require("@medialane/sdk");
|
|
26
|
+
const LIVING_RENDER_COLLECTIONS = {
|
|
27
|
+
STARKNET: [
|
|
28
|
+
// TODO(gol_starknet mainnet launch): GolLifeformsV3 ("Digital Bacteria" / BACT)
|
|
29
|
+
// TODO(gol_starknet mainnet launch): GolWanderersV3 ("Digital Wanderers" / WNDR)
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
function isLivingRenderCollection(chain, contractAddress) {
|
|
33
|
+
const listed = LIVING_RENDER_COLLECTIONS[chain];
|
|
34
|
+
if (!listed || listed.length === 0) return false;
|
|
35
|
+
const normalized = (0, import_sdk.normalizeAddress)(chain, contractAddress);
|
|
36
|
+
return listed.some((addr) => (0, import_sdk.normalizeAddress)(chain, addr) === normalized);
|
|
37
|
+
}
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
LIVING_RENDER_COLLECTIONS,
|
|
41
|
+
isLivingRenderCollection
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=living-render-collections.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/living-render-collections.ts"],"sourcesContent":["import { normalizeAddress, type Chain } from \"@medialane/sdk\";\n\n/**\n * Curated allowlist of external collections whose asset media renders as a\n * live on-chain animation (`animation_url`, sandboxed iframe) instead of the\n * static `image` everywhere else. Not protocol coordinates — this is\n * partner-launch curation, deliberately kept out of the SDK\n * (see medialane-core/docs/specs/2026-07-28-gol-starknet-living-render-design.md §7).\n *\n * Empty until gol_starknet (https://github.com/l-henri/gol_starknet) deploys\n * to Starknet mainnet — Sepolia-only as of this file's creation.\n */\nexport const LIVING_RENDER_COLLECTIONS: Partial<Record<Chain, string[]>> = {\n STARKNET: [\n // TODO(gol_starknet mainnet launch): GolLifeformsV3 (\"Digital Bacteria\" / BACT)\n // TODO(gol_starknet mainnet launch): GolWanderersV3 (\"Digital Wanderers\" / WNDR)\n ],\n};\n\nexport function isLivingRenderCollection(chain: Chain, contractAddress: string): boolean {\n const listed = LIVING_RENDER_COLLECTIONS[chain];\n if (!listed || listed.length === 0) return false;\n const normalized = normalizeAddress(chain, contractAddress);\n return listed.some((addr) => normalizeAddress(chain, addr) === normalized);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA6C;AAYtC,MAAM,4BAA8D;AAAA,EACzE,UAAU;AAAA;AAAA;AAAA,EAGV;AACF;AAEO,SAAS,yBAAyB,OAAc,iBAAkC;AACvF,QAAM,SAAS,0BAA0B,KAAK;AAC9C,MAAI,CAAC,UAAU,OAAO,WAAW,EAAG,QAAO;AAC3C,QAAM,iBAAa,6BAAiB,OAAO,eAAe;AAC1D,SAAO,OAAO,KAAK,CAAC,aAAS,6BAAiB,OAAO,IAAI,MAAM,UAAU;AAC3E;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Chain } from '@medialane/sdk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Curated allowlist of external collections whose asset media renders as a
|
|
5
|
+
* live on-chain animation (`animation_url`, sandboxed iframe) instead of the
|
|
6
|
+
* static `image` everywhere else. Not protocol coordinates — this is
|
|
7
|
+
* partner-launch curation, deliberately kept out of the SDK
|
|
8
|
+
* (see medialane-core/docs/specs/2026-07-28-gol-starknet-living-render-design.md §7).
|
|
9
|
+
*
|
|
10
|
+
* Empty until gol_starknet (https://github.com/l-henri/gol_starknet) deploys
|
|
11
|
+
* to Starknet mainnet — Sepolia-only as of this file's creation.
|
|
12
|
+
*/
|
|
13
|
+
declare const LIVING_RENDER_COLLECTIONS: Partial<Record<Chain, string[]>>;
|
|
14
|
+
declare function isLivingRenderCollection(chain: Chain, contractAddress: string): boolean;
|
|
15
|
+
|
|
16
|
+
export { LIVING_RENDER_COLLECTIONS, isLivingRenderCollection };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Chain } from '@medialane/sdk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Curated allowlist of external collections whose asset media renders as a
|
|
5
|
+
* live on-chain animation (`animation_url`, sandboxed iframe) instead of the
|
|
6
|
+
* static `image` everywhere else. Not protocol coordinates — this is
|
|
7
|
+
* partner-launch curation, deliberately kept out of the SDK
|
|
8
|
+
* (see medialane-core/docs/specs/2026-07-28-gol-starknet-living-render-design.md §7).
|
|
9
|
+
*
|
|
10
|
+
* Empty until gol_starknet (https://github.com/l-henri/gol_starknet) deploys
|
|
11
|
+
* to Starknet mainnet — Sepolia-only as of this file's creation.
|
|
12
|
+
*/
|
|
13
|
+
declare const LIVING_RENDER_COLLECTIONS: Partial<Record<Chain, string[]>>;
|
|
14
|
+
declare function isLivingRenderCollection(chain: Chain, contractAddress: string): boolean;
|
|
15
|
+
|
|
16
|
+
export { LIVING_RENDER_COLLECTIONS, isLivingRenderCollection };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { normalizeAddress } from "@medialane/sdk";
|
|
2
|
+
const LIVING_RENDER_COLLECTIONS = {
|
|
3
|
+
STARKNET: [
|
|
4
|
+
// TODO(gol_starknet mainnet launch): GolLifeformsV3 ("Digital Bacteria" / BACT)
|
|
5
|
+
// TODO(gol_starknet mainnet launch): GolWanderersV3 ("Digital Wanderers" / WNDR)
|
|
6
|
+
]
|
|
7
|
+
};
|
|
8
|
+
function isLivingRenderCollection(chain, contractAddress) {
|
|
9
|
+
const listed = LIVING_RENDER_COLLECTIONS[chain];
|
|
10
|
+
if (!listed || listed.length === 0) return false;
|
|
11
|
+
const normalized = normalizeAddress(chain, contractAddress);
|
|
12
|
+
return listed.some((addr) => normalizeAddress(chain, addr) === normalized);
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
LIVING_RENDER_COLLECTIONS,
|
|
16
|
+
isLivingRenderCollection
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=living-render-collections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/living-render-collections.ts"],"sourcesContent":["import { normalizeAddress, type Chain } from \"@medialane/sdk\";\n\n/**\n * Curated allowlist of external collections whose asset media renders as a\n * live on-chain animation (`animation_url`, sandboxed iframe) instead of the\n * static `image` everywhere else. Not protocol coordinates — this is\n * partner-launch curation, deliberately kept out of the SDK\n * (see medialane-core/docs/specs/2026-07-28-gol-starknet-living-render-design.md §7).\n *\n * Empty until gol_starknet (https://github.com/l-henri/gol_starknet) deploys\n * to Starknet mainnet — Sepolia-only as of this file's creation.\n */\nexport const LIVING_RENDER_COLLECTIONS: Partial<Record<Chain, string[]>> = {\n STARKNET: [\n // TODO(gol_starknet mainnet launch): GolLifeformsV3 (\"Digital Bacteria\" / BACT)\n // TODO(gol_starknet mainnet launch): GolWanderersV3 (\"Digital Wanderers\" / WNDR)\n ],\n};\n\nexport function isLivingRenderCollection(chain: Chain, contractAddress: string): boolean {\n const listed = LIVING_RENDER_COLLECTIONS[chain];\n if (!listed || listed.length === 0) return false;\n const normalized = normalizeAddress(chain, contractAddress);\n return listed.some((addr) => normalizeAddress(chain, addr) === normalized);\n}\n"],"mappings":"AAAA,SAAS,wBAAoC;AAYtC,MAAM,4BAA8D;AAAA,EACzE,UAAU;AAAA;AAAA;AAAA,EAGV;AACF;AAEO,SAAS,yBAAyB,OAAc,iBAAkC;AACvF,QAAM,SAAS,0BAA0B,KAAK;AAC9C,MAAI,CAAC,UAAU,OAAO,WAAW,EAAG,QAAO;AAC3C,QAAM,aAAa,iBAAiB,OAAO,eAAe;AAC1D,SAAO,OAAO,KAAK,CAAC,SAAS,iBAAiB,OAAO,IAAI,MAAM,UAAU;AAC3E;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,7 @@ __export(index_exports, {
|
|
|
29
29
|
ActivityRow: () => import_activity_row.ActivityRow,
|
|
30
30
|
ActivityTicker: () => import_activity_ticker.ActivityTicker,
|
|
31
31
|
AddressDisplay: () => import_address_display.AddressDisplay,
|
|
32
|
+
AnimatedTokenMedia: () => import_animated_token_media.AnimatedTokenMedia,
|
|
32
33
|
AssetCard: () => import_asset_card.AssetCard,
|
|
33
34
|
AssetCardSkeleton: () => import_asset_card.AssetCardSkeleton,
|
|
34
35
|
AssetCollectionBar: () => import_asset_collection_bar.AssetCollectionBar,
|
|
@@ -104,6 +105,7 @@ __export(index_exports, {
|
|
|
104
105
|
LAUNCHPAD_SERVICE_GROUPS: () => import_launchpad_services2.LAUNCHPAD_SERVICE_GROUPS,
|
|
105
106
|
LICENSE_TRAIT_TYPES: () => import_ip.LICENSE_TRAIT_TYPES,
|
|
106
107
|
LICENSE_TYPES: () => import_ip.LICENSE_TYPES,
|
|
108
|
+
LIVING_RENDER_COLLECTIONS: () => import_living_render_collections.LIVING_RENDER_COLLECTIONS,
|
|
107
109
|
LaunchpadFilterBar: () => import_launchpad_filter_bar.LaunchpadFilterBar,
|
|
108
110
|
LaunchpadGroupedSections: () => import_launchpad_services.LaunchpadGroupedSections,
|
|
109
111
|
LaunchpadServiceCard: () => import_launchpad_services.LaunchpadServiceCard,
|
|
@@ -161,6 +163,7 @@ __export(index_exports, {
|
|
|
161
163
|
formatDisplayPrice: () => import_format.formatDisplayPrice,
|
|
162
164
|
formatFdv: () => import_coins.formatFdv,
|
|
163
165
|
ipfsToHttp: () => import_ipfs.ipfsToHttp,
|
|
166
|
+
isLivingRenderCollection: () => import_living_render_collections.isLivingRenderCollection,
|
|
164
167
|
licenseSummary: () => import_license_summary.licenseSummary,
|
|
165
168
|
parsePriceDisplay: () => import_format.parsePriceDisplay,
|
|
166
169
|
shortenAddress: () => import_address.shortenAddress,
|
|
@@ -169,6 +172,7 @@ __export(index_exports, {
|
|
|
169
172
|
toDurationDays: () => import_license_terms_builder.toDurationDays,
|
|
170
173
|
toLicenseMetadata: () => import_license_terms_builder.toLicenseMetadata,
|
|
171
174
|
useCollectionFilters: () => import_collection_filters.useCollectionFilters,
|
|
175
|
+
useIntersectionActive: () => import_use_intersection_active.useIntersectionActive,
|
|
172
176
|
useLaunchpadFilter: () => import_launchpad_services.useLaunchpadFilter,
|
|
173
177
|
useNavAccountSheet: () => import_nav_shell.useNavAccountSheet,
|
|
174
178
|
useNavCommandMenu: () => import_nav_command_menu.useNavCommandMenu
|
|
@@ -178,6 +182,7 @@ var import_cn = require("./utils/cn.js");
|
|
|
178
182
|
var import_format = require("./utils/format.js");
|
|
179
183
|
var import_address = require("./utils/address.js");
|
|
180
184
|
var import_ipfs = require("./utils/ipfs.js");
|
|
185
|
+
var import_use_intersection_active = require("./utils/use-intersection-active.js");
|
|
181
186
|
var import_license_summary = require("./utils/license-summary.js");
|
|
182
187
|
var import_ip_types = require("./data/ip-types.js");
|
|
183
188
|
var import_ip = require("./data/ip.js");
|
|
@@ -192,6 +197,7 @@ var import_asset_collection_bar = require("./components/asset-collection-bar.js"
|
|
|
192
197
|
var import_asset_utility_icons = require("./components/asset-utility-icons.js");
|
|
193
198
|
var import_asset_marketplace_panel = require("./components/asset-marketplace-panel.js");
|
|
194
199
|
var import_brand = require("./data/brand.js");
|
|
200
|
+
var import_living_render_collections = require("./data/living-render-collections.js");
|
|
195
201
|
var import_currency_icon = require("./components/currency-icon.js");
|
|
196
202
|
var import_ip_type_badge = require("./components/ip-type-badge.js");
|
|
197
203
|
var import_address_display = require("./components/address-display.js");
|
|
@@ -202,6 +208,7 @@ var import_scroll_section = require("./components/scroll-section.js");
|
|
|
202
208
|
var import_share_button = require("./components/share-button.js");
|
|
203
209
|
var import_collection_card = require("./components/collection-card.js");
|
|
204
210
|
var import_token_card = require("./components/token-card.js");
|
|
211
|
+
var import_animated_token_media = require("./components/animated-token-media.js");
|
|
205
212
|
var import_theme_ambient_background = require("./components/theme-ambient-background.js");
|
|
206
213
|
var import_collection_filters = require("./components/collection-filters.js");
|
|
207
214
|
var import_dropdown_menu = require("./components/dropdown-menu.js");
|
|
@@ -269,6 +276,7 @@ var import_action_dialog = require("./components/action-dialog.js");
|
|
|
269
276
|
ActivityRow,
|
|
270
277
|
ActivityTicker,
|
|
271
278
|
AddressDisplay,
|
|
279
|
+
AnimatedTokenMedia,
|
|
272
280
|
AssetCard,
|
|
273
281
|
AssetCardSkeleton,
|
|
274
282
|
AssetCollectionBar,
|
|
@@ -344,6 +352,7 @@ var import_action_dialog = require("./components/action-dialog.js");
|
|
|
344
352
|
LAUNCHPAD_SERVICE_GROUPS,
|
|
345
353
|
LICENSE_TRAIT_TYPES,
|
|
346
354
|
LICENSE_TYPES,
|
|
355
|
+
LIVING_RENDER_COLLECTIONS,
|
|
347
356
|
LaunchpadFilterBar,
|
|
348
357
|
LaunchpadGroupedSections,
|
|
349
358
|
LaunchpadServiceCard,
|
|
@@ -401,6 +410,7 @@ var import_action_dialog = require("./components/action-dialog.js");
|
|
|
401
410
|
formatDisplayPrice,
|
|
402
411
|
formatFdv,
|
|
403
412
|
ipfsToHttp,
|
|
413
|
+
isLivingRenderCollection,
|
|
404
414
|
licenseSummary,
|
|
405
415
|
parsePriceDisplay,
|
|
406
416
|
shortenAddress,
|
|
@@ -409,6 +419,7 @@ var import_action_dialog = require("./components/action-dialog.js");
|
|
|
409
419
|
toDurationDays,
|
|
410
420
|
toLicenseMetadata,
|
|
411
421
|
useCollectionFilters,
|
|
422
|
+
useIntersectionActive,
|
|
412
423
|
useLaunchpadFilter,
|
|
413
424
|
useNavAccountSheet,
|
|
414
425
|
useNavCommandMenu
|