@medialane/ui 0.108.0 → 0.110.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.
@@ -62,6 +62,7 @@ function AssetMarketplacePanel({
62
62
  onOpenSponsorSolicit,
63
63
  floorPriceRaw,
64
64
  lastSaleRaw,
65
+ usdValue,
65
66
  renderAuthAction,
66
67
  renderHelp,
67
68
  onCancelClick,
@@ -84,12 +85,18 @@ function AssetMarketplacePanel({
84
85
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative space-y-4", children: [
85
86
  cheapest ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-4", children: [
86
87
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-baseline gap-x-5 gap-y-1.5", children: [
87
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-baseline gap-2", children: [
88
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: cheapest.price.currency ?? "", size: 26 }),
89
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-4xl font-bold tracking-tight", children: (0, import_format.formatDisplayPrice)(cheapest.price.formatted) }),
90
- renderHelp(
91
- `${isOwner && !canBuyMore ? "Your listing" : "Current price"} \xB7 Expires ${(0, import_time.timeUntil)(cheapest.endTime)}`
92
- )
88
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
89
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-baseline gap-2", children: [
90
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: cheapest.price.currency ?? "", size: 26 }),
91
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-4xl font-bold tracking-tight", children: (0, import_format.formatDisplayPrice)(cheapest.price.formatted) }),
92
+ renderHelp(
93
+ `${isOwner && !canBuyMore ? "Your listing" : "Current price"} \xB7 Expires ${(0, import_time.timeUntil)(cheapest.endTime)}`
94
+ )
95
+ ] }),
96
+ usdValue && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-sm text-muted-foreground mt-0.5", children: [
97
+ "\u2248 ",
98
+ usdValue
99
+ ] })
93
100
  ] }),
94
101
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatRow, { floorPriceRaw, lastSaleRaw })
95
102
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/asset-marketplace-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport {\n ArrowRightLeft, CheckCircle, Clock, GitBranch, HandCoins, Handshake, Loader2,\n ShoppingCart, Tag, X,\n} from \"lucide-react\";\nimport { CurrencyIcon, CurrencyAmount } from \"./currency-icon.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ActionButton } from \"./action-button.js\";\nimport { formatDisplayPrice, parsePriceDisplay } from \"../utils/format.js\";\nimport { timeUntil } from \"../utils/time.js\";\n\n/** Structural subset of `ApiOrder` (both apps' `@medialane/sdk` types satisfy this). */\nexport interface ApiOrderLike {\n orderHash: string;\n offerer: string;\n endTime: string;\n price: { formatted: string | null; currency: string | null };\n}\n\nexport interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {\n cheapest?: T;\n isOwner: boolean;\n isSignedIn: boolean;\n isProcessing: boolean;\n isERC1155: boolean;\n isMarketLoading?: boolean;\n myListing: T | null;\n activeBids: T[];\n walletAddress?: string | null;\n remixEnabled?: boolean;\n showDealOption?: boolean;\n /** Raw \"0.07 STRK\"-style strings — already resolved by the caller. `null`/undefined renders \"—\". */\n floorPriceRaw?: string | null;\n lastSaleRaw?: string | null;\n /** Renders the sign-in/connect-wallet CTA for the given label (e.g. \"Sign in to trade\"). */\n renderAuthAction: (label: string) => ReactNode;\n /** Renders an inline help/info affordance for the given tooltip text. */\n renderHelp: (content: string) => ReactNode;\n onCancelClick: (order: T) => void;\n onAcceptBid: (order: T) => void;\n onOpenListing: () => void;\n onOpenTransfer: () => void;\n onOpenPurchase: (order: T) => void;\n onOpenOffer: () => void;\n onOpenRemix?: () => void;\n onProposeDeal?: () => void;\n /** Non-owner: propose a sponsorship deal on this asset. */\n showSponsorOption?: boolean;\n onOpenSponsorProposal?: () => void;\n /** Owner: open this asset for sponsorship bidding. */\n showSponsorSolicitOption?: boolean;\n onOpenSponsorSolicit?: () => void;\n}\n\n/** Floor + last-sale stats — each hides itself when its data is absent\n * (no dangling \"—\" placeholders), and the whole row disappears when\n * neither is available. */\nfunction StatRow({ floorPriceRaw, lastSaleRaw }: { floorPriceRaw?: string | null; lastSaleRaw?: string | null }) {\n const floor = floorPriceRaw ? parsePriceDisplay(floorPriceRaw) : null;\n const lastSale = lastSaleRaw ? parsePriceDisplay(lastSaleRaw) : null;\n if (!floor?.symbol && !lastSale?.symbol) return null;\n return (\n <div className=\"flex items-center gap-4 text-sm text-muted-foreground\">\n {floor?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Floor</span>\n <CurrencyAmount amount={floor.numStr} symbol={floor.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n {lastSale?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Last sale</span>\n <CurrencyAmount amount={lastSale.numStr} symbol={lastSale.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n </div>\n );\n}\n\nexport function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({\n cheapest,\n isOwner,\n isSignedIn,\n isProcessing,\n isERC1155,\n isMarketLoading = false,\n myListing,\n activeBids,\n walletAddress,\n remixEnabled = false,\n showDealOption = false,\n showSponsorOption = false,\n onOpenSponsorProposal,\n showSponsorSolicitOption = false,\n onOpenSponsorSolicit,\n floorPriceRaw,\n lastSaleRaw,\n renderAuthAction,\n renderHelp,\n onCancelClick,\n onAcceptBid,\n onOpenListing,\n onOpenTransfer,\n onOpenPurchase,\n onOpenOffer,\n onOpenRemix,\n onProposeDeal,\n}: AssetMarketplacePanelProps<T>) {\n const myBid = !isOwner && walletAddress\n ? activeBids.find((bid) => bid.offerer.toLowerCase() === walletAddress.toLowerCase()) ?? null\n : null;\n\n const canBuyMore =\n isERC1155 && isOwner && !!cheapest && !!walletAddress &&\n cheapest.offerer.toLowerCase() !== walletAddress.toLowerCase();\n\n if (isMarketLoading && !cheapest) {\n return (\n <div className=\"space-y-4\">\n <div className=\"h-9 w-32 rounded-md bg-muted animate-pulse\" />\n <div className=\"h-12 w-full rounded-2xl bg-muted animate-pulse\" />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n\n <div className=\"relative space-y-4\">\n {cheapest ? (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-baseline gap-x-5 gap-y-1.5\">\n <div className=\"flex items-baseline gap-2\">\n <CurrencyIcon symbol={cheapest.price.currency ?? \"\"} size={26} />\n <span className=\"text-4xl font-bold tracking-tight\">\n {formatDisplayPrice(cheapest.price.formatted)}\n </span>\n {renderHelp(\n `${isOwner && !canBuyMore ? \"Your listing\" : \"Current price\"} · Expires ${timeUntil(cheapest.endTime)}`\n )}\n </div>\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n </div>\n\n {isOwner ? (\n <div className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2\">\n {myListing ? (\n <ActionButton big\n icon={isProcessing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <X className=\"h-4 w-4\" />}\n onClick={() => onCancelClick(myListing)}\n disabled={isProcessing}\n tone=\"red\"\n renderHelp={renderHelp}\n >\n Cancel Listing\n </ActionButton>\n ) : null}\n {/* ERC-721 has exactly one possible listing — once myListing exists,\n \"List on Marketplace\" is redundant next to \"Cancel Listing\" and\n reads as a broken/confusing pair. An ERC-1155 owner can still hold\n un-listed editions while one listing is active, so it stays for them. */}\n {(!myListing || isERC1155) ? (\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n ) : null}\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n\n {canBuyMore && (\n <>\n <div className=\"border-t border-border/40 pt-2 mt-1\" />\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest!)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n </div>\n </>\n )}\n </div>\n ) : isSignedIn ? (\n <>\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Create your own attributed derivative of this work.\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showDealOption && onProposeDeal ? (\n <ActionButton big\n action=\"license\"\n icon={<HandCoins className=\"h-4 w-4\" />}\n onClick={onProposeDeal}\n helpContent=\"Propose a license deal to the creator to use this work.\"\n renderHelp={renderHelp}\n >\n License\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n {!remixEnabled && !showDealOption ? (\n <p className=\"text-xs text-muted-foreground mt-2 leading-relaxed\">\n The creator marked this asset as no-derivatives.\n </p>\n ) : null}\n </>\n ) : (\n renderAuthAction(\"Sign in to trade\")\n )}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n {isOwner ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n ) : isSignedIn ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n ) : (\n renderAuthAction(\"Sign in to make an offer\")\n )}\n </div>\n )}\n\n {myBid ? (\n <div className=\"rounded-xl bg-amber-500/8 px-4 py-3 flex items-center justify-between gap-3\">\n <div className=\"min-w-0 flex items-center gap-2.5\">\n <HandCoins className=\"h-4 w-4 text-amber-500 shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-xs font-semibold text-amber-500\">Your active offer</p>\n <p className=\"text-xs text-muted-foreground flex items-center gap-1.5 mt-0.5\">\n <span className=\"font-bold text-foreground inline-flex items-center gap-1\">\n {formatDisplayPrice(myBid.price.formatted)}\n <CurrencyIcon symbol={myBid.price.currency ?? \"\"} size={12} />\n </span>\n <span>·</span>\n <Clock className=\"h-3 w-3\" />\n {timeUntil(myBid.endTime)}\n </p>\n </div>\n </div>\n <button\n className=\"shrink-0 text-xs font-semibold text-red-400 hover:text-red-300 transition-colors flex items-center gap-1\"\n onClick={() => onCancelClick(myBid)}\n >\n <X className=\"h-3.5 w-3.5\" />\n Cancel\n </button>\n </div>\n ) : null}\n\n {isOwner && activeBids.length > 0 ? (\n <div className=\"rounded-xl bg-card/40 p-5 space-y-3\">\n <p className=\"text-xs font-semibold text-muted-foreground\">\n Incoming offers ({activeBids.length})\n </p>\n <div className=\"space-y-2\">\n {activeBids.map((bid) => (\n <div key={bid.orderHash} className=\"flex items-center justify-between gap-3 rounded-lg bg-muted/30 px-3 py-2\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-bold\">\n <span className=\"inline-flex items-center gap-1.5\">\n {formatDisplayPrice(bid.price.formatted)}\n <CurrencyIcon symbol={bid.price.currency ?? \"\"} size={14} />\n </span>\n </p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <AddressDisplay address={bid.offerer} chars={4} showCopy={false} className=\"text-xs text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">·</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {timeUntil(bid.endTime)}\n </div>\n </div>\n </div>\n <button\n disabled={isProcessing}\n onClick={() => onAcceptBid(bid)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-xs font-semibold text-primary-foreground disabled:opacity-50\"\n >\n <CheckCircle className=\"h-3.5 w-3.5\" />\n Accept\n </button>\n </div>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/asset-marketplace-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport {\n ArrowRightLeft, CheckCircle, Clock, GitBranch, HandCoins, Handshake, Loader2,\n ShoppingCart, Tag, X,\n} from \"lucide-react\";\nimport { CurrencyIcon, CurrencyAmount } from \"./currency-icon.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ActionButton } from \"./action-button.js\";\nimport { formatDisplayPrice, parsePriceDisplay } from \"../utils/format.js\";\nimport { timeUntil } from \"../utils/time.js\";\n\n/** Structural subset of `ApiOrder` (both apps' `@medialane/sdk` types satisfy this). */\nexport interface ApiOrderLike {\n orderHash: string;\n offerer: string;\n endTime: string;\n price: { formatted: string | null; currency: string | null };\n}\n\nexport interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {\n cheapest?: T;\n isOwner: boolean;\n isSignedIn: boolean;\n isProcessing: boolean;\n isERC1155: boolean;\n isMarketLoading?: boolean;\n myListing: T | null;\n activeBids: T[];\n walletAddress?: string | null;\n remixEnabled?: boolean;\n showDealOption?: boolean;\n /** Raw \"0.07 STRK\"-style strings — already resolved by the caller. `null`/undefined renders \"—\". */\n floorPriceRaw?: string | null;\n lastSaleRaw?: string | null;\n /**\n * Pre-formatted USD equivalent of `cheapest.price` (e.g. \"$12.34\"), computed\n * by the host from its own live rate feed — this package has no price-feed\n * access by design. Omit (or pass null) to render no USD line.\n */\n usdValue?: string | null;\n /** Renders the sign-in/connect-wallet CTA for the given label (e.g. \"Sign in to trade\"). */\n renderAuthAction: (label: string) => ReactNode;\n /** Renders an inline help/info affordance for the given tooltip text. */\n renderHelp: (content: string) => ReactNode;\n onCancelClick: (order: T) => void;\n onAcceptBid: (order: T) => void;\n onOpenListing: () => void;\n onOpenTransfer: () => void;\n onOpenPurchase: (order: T) => void;\n onOpenOffer: () => void;\n onOpenRemix?: () => void;\n onProposeDeal?: () => void;\n /** Non-owner: propose a sponsorship deal on this asset. */\n showSponsorOption?: boolean;\n onOpenSponsorProposal?: () => void;\n /** Owner: open this asset for sponsorship bidding. */\n showSponsorSolicitOption?: boolean;\n onOpenSponsorSolicit?: () => void;\n}\n\n/** Floor + last-sale stats — each hides itself when its data is absent\n * (no dangling \"—\" placeholders), and the whole row disappears when\n * neither is available. */\nfunction StatRow({ floorPriceRaw, lastSaleRaw }: { floorPriceRaw?: string | null; lastSaleRaw?: string | null }) {\n const floor = floorPriceRaw ? parsePriceDisplay(floorPriceRaw) : null;\n const lastSale = lastSaleRaw ? parsePriceDisplay(lastSaleRaw) : null;\n if (!floor?.symbol && !lastSale?.symbol) return null;\n return (\n <div className=\"flex items-center gap-4 text-sm text-muted-foreground\">\n {floor?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Floor</span>\n <CurrencyAmount amount={floor.numStr} symbol={floor.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n {lastSale?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Last sale</span>\n <CurrencyAmount amount={lastSale.numStr} symbol={lastSale.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n </div>\n );\n}\n\nexport function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({\n cheapest,\n isOwner,\n isSignedIn,\n isProcessing,\n isERC1155,\n isMarketLoading = false,\n myListing,\n activeBids,\n walletAddress,\n remixEnabled = false,\n showDealOption = false,\n showSponsorOption = false,\n onOpenSponsorProposal,\n showSponsorSolicitOption = false,\n onOpenSponsorSolicit,\n floorPriceRaw,\n lastSaleRaw,\n usdValue,\n renderAuthAction,\n renderHelp,\n onCancelClick,\n onAcceptBid,\n onOpenListing,\n onOpenTransfer,\n onOpenPurchase,\n onOpenOffer,\n onOpenRemix,\n onProposeDeal,\n}: AssetMarketplacePanelProps<T>) {\n const myBid = !isOwner && walletAddress\n ? activeBids.find((bid) => bid.offerer.toLowerCase() === walletAddress.toLowerCase()) ?? null\n : null;\n\n const canBuyMore =\n isERC1155 && isOwner && !!cheapest && !!walletAddress &&\n cheapest.offerer.toLowerCase() !== walletAddress.toLowerCase();\n\n if (isMarketLoading && !cheapest) {\n return (\n <div className=\"space-y-4\">\n <div className=\"h-9 w-32 rounded-md bg-muted animate-pulse\" />\n <div className=\"h-12 w-full rounded-2xl bg-muted animate-pulse\" />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n\n <div className=\"relative space-y-4\">\n {cheapest ? (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-baseline gap-x-5 gap-y-1.5\">\n <div>\n <div className=\"flex items-baseline gap-2\">\n <CurrencyIcon symbol={cheapest.price.currency ?? \"\"} size={26} />\n <span className=\"text-4xl font-bold tracking-tight\">\n {formatDisplayPrice(cheapest.price.formatted)}\n </span>\n {renderHelp(\n `${isOwner && !canBuyMore ? \"Your listing\" : \"Current price\"} · Expires ${timeUntil(cheapest.endTime)}`\n )}\n </div>\n {usdValue && <p className=\"text-sm text-muted-foreground mt-0.5\">≈ {usdValue}</p>}\n </div>\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n </div>\n\n {isOwner ? (\n <div className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2\">\n {myListing ? (\n <ActionButton big\n icon={isProcessing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <X className=\"h-4 w-4\" />}\n onClick={() => onCancelClick(myListing)}\n disabled={isProcessing}\n tone=\"red\"\n renderHelp={renderHelp}\n >\n Cancel Listing\n </ActionButton>\n ) : null}\n {/* ERC-721 has exactly one possible listing — once myListing exists,\n \"List on Marketplace\" is redundant next to \"Cancel Listing\" and\n reads as a broken/confusing pair. An ERC-1155 owner can still hold\n un-listed editions while one listing is active, so it stays for them. */}\n {(!myListing || isERC1155) ? (\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n ) : null}\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n\n {canBuyMore && (\n <>\n <div className=\"border-t border-border/40 pt-2 mt-1\" />\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest!)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n </div>\n </>\n )}\n </div>\n ) : isSignedIn ? (\n <>\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Create your own attributed derivative of this work.\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showDealOption && onProposeDeal ? (\n <ActionButton big\n action=\"license\"\n icon={<HandCoins className=\"h-4 w-4\" />}\n onClick={onProposeDeal}\n helpContent=\"Propose a license deal to the creator to use this work.\"\n renderHelp={renderHelp}\n >\n License\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n {!remixEnabled && !showDealOption ? (\n <p className=\"text-xs text-muted-foreground mt-2 leading-relaxed\">\n The creator marked this asset as no-derivatives.\n </p>\n ) : null}\n </>\n ) : (\n renderAuthAction(\"Sign in to trade\")\n )}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n {isOwner ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n ) : isSignedIn ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n ) : (\n renderAuthAction(\"Sign in to make an offer\")\n )}\n </div>\n )}\n\n {myBid ? (\n <div className=\"rounded-xl bg-amber-500/8 px-4 py-3 flex items-center justify-between gap-3\">\n <div className=\"min-w-0 flex items-center gap-2.5\">\n <HandCoins className=\"h-4 w-4 text-amber-500 shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-xs font-semibold text-amber-500\">Your active offer</p>\n <p className=\"text-xs text-muted-foreground flex items-center gap-1.5 mt-0.5\">\n <span className=\"font-bold text-foreground inline-flex items-center gap-1\">\n {formatDisplayPrice(myBid.price.formatted)}\n <CurrencyIcon symbol={myBid.price.currency ?? \"\"} size={12} />\n </span>\n <span>·</span>\n <Clock className=\"h-3 w-3\" />\n {timeUntil(myBid.endTime)}\n </p>\n </div>\n </div>\n <button\n className=\"shrink-0 text-xs font-semibold text-red-400 hover:text-red-300 transition-colors flex items-center gap-1\"\n onClick={() => onCancelClick(myBid)}\n >\n <X className=\"h-3.5 w-3.5\" />\n Cancel\n </button>\n </div>\n ) : null}\n\n {isOwner && activeBids.length > 0 ? (\n <div className=\"rounded-xl bg-card/40 p-5 space-y-3\">\n <p className=\"text-xs font-semibold text-muted-foreground\">\n Incoming offers ({activeBids.length})\n </p>\n <div className=\"space-y-2\">\n {activeBids.map((bid) => (\n <div key={bid.orderHash} className=\"flex items-center justify-between gap-3 rounded-lg bg-muted/30 px-3 py-2\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-bold\">\n <span className=\"inline-flex items-center gap-1.5\">\n {formatDisplayPrice(bid.price.formatted)}\n <CurrencyIcon symbol={bid.price.currency ?? \"\"} size={14} />\n </span>\n </p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <AddressDisplay address={bid.offerer} chars={4} showCopy={false} className=\"text-xs text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">·</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {timeUntil(bid.endTime)}\n </div>\n </div>\n </div>\n <button\n disabled={isProcessing}\n onClick={() => onAcceptBid(bid)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-xs font-semibold text-primary-foreground disabled:opacity-50\"\n >\n <CheckCircle className=\"h-3.5 w-3.5\" />\n Accept\n </button>\n </div>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwEQ;AArER,0BAGO;AACP,2BAA6C;AAC7C,6BAA+B;AAC/B,2BAA6B;AAC7B,oBAAsD;AACtD,kBAA0B;AAsD1B,SAAS,QAAQ,EAAE,eAAe,YAAY,GAAmE;AAC/G,QAAM,QAAQ,oBAAgB,iCAAkB,aAAa,IAAI;AACjE,QAAM,WAAW,kBAAc,iCAAkB,WAAW,IAAI;AAChE,MAAI,CAAC,OAAO,UAAU,CAAC,UAAU,OAAQ,QAAO;AAChD,SACE,6CAAC,SAAI,WAAU,yDACZ;AAAA,WAAO,UACN,6CAAC,UAAK,WAAU,6BACd;AAAA,kDAAC,UAAK,mBAAK;AAAA,MACX,4CAAC,uCAAe,QAAQ,MAAM,QAAQ,QAAQ,MAAM,QAAQ,UAAU,IAAI,iBAAgB,iCAAgC;AAAA,OAC5H;AAAA,IAED,UAAU,UACT,6CAAC,UAAK,WAAU,6BACd;AAAA,kDAAC,UAAK,uBAAS;AAAA,MACf,4CAAC,uCAAe,QAAQ,SAAS,QAAQ,QAAQ,SAAS,QAAQ,UAAU,IAAI,iBAAgB,iCAAgC;AAAA,OAClI;AAAA,KAEJ;AAEJ;AAEO,SAAS,sBAA6D;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB;AAAA,EACA,2BAA2B;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkC;AAChC,QAAM,QAAQ,CAAC,WAAW,gBACtB,WAAW,KAAK,CAAC,QAAQ,IAAI,QAAQ,YAAY,MAAM,cAAc,YAAY,CAAC,KAAK,OACvF;AAEJ,QAAM,aACJ,aAAa,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,iBACxC,SAAS,QAAQ,YAAY,MAAM,cAAc,YAAY;AAE/D,MAAI,mBAAmB,CAAC,UAAU;AAChC,WACE,6CAAC,SAAI,WAAU,aACb;AAAA,kDAAC,SAAI,WAAU,8CAA6C;AAAA,MAC5D,4CAAC,SAAI,WAAU,kDAAiD;AAAA,OAClE;AAAA,EAEJ;AAEA,SACE,4CAAC,SAAI,WAAU,YAEb,uDAAC,SAAI,WAAU,sBACZ;AAAA,eACC,6CAAC,SAAI,WAAU,aACb;AAAA,mDAAC,SAAI,WAAU,mDACb;AAAA,qDAAC,SACC;AAAA,uDAAC,SAAI,WAAU,6BACb;AAAA,wDAAC,qCAAa,QAAQ,SAAS,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,YAC/D,4CAAC,UAAK,WAAU,qCACb,gDAAmB,SAAS,MAAM,SAAS,GAC9C;AAAA,YACC;AAAA,cACC,GAAG,WAAW,CAAC,aAAa,iBAAiB,eAAe,qBAAc,uBAAU,SAAS,OAAO,CAAC;AAAA,YACvG;AAAA,aACF;AAAA,UACC,YAAY,6CAAC,OAAE,WAAU,wCAAuC;AAAA;AAAA,YAAG;AAAA,aAAS;AAAA,WAC/E;AAAA,QACA,4CAAC,WAAQ,eAA8B,aAA0B;AAAA,SACnE;AAAA,MAEC,UACC,6CAAC,SAAI,WAAU,aACb;AAAA,qDAAC,SAAI,WAAU,0BACZ;AAAA,sBACC;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,MAAM,eAAe,4CAAC,+BAAQ,WAAU,wBAAuB,IAAK,4CAAC,yBAAE,WAAU,WAAU;AAAA,cAC3F,SAAS,MAAM,cAAc,SAAS;AAAA,cACtC,UAAU;AAAA,cACV,MAAK;AAAA,cACL;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UAKF,CAAC,aAAa,YACd,4CAAC,qCAAa,KAAG,MAAC,MAAK,QAAO,MAAM,4CAAC,2BAAI,WAAU,WAAU,GAAI,SAAS,eAAe,YAAwB,iCAAmB,IAClI;AAAA,UACJ,4CAAC,qCAAa,KAAG,MAAC,MAAK,UAAS,MAAM,4CAAC,sCAAe,WAAU,WAAU,GAAI,SAAS,gBAAgB,YAAwB,sBAAQ;AAAA,UACtI,gBAAgB,cACf;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,QAAO;AAAA,cACP,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UACH,4BAA4B,uBAC3B;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,MAAK;AAAA,cACL,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,WACN;AAAA,QAEC,cACC,4EACE;AAAA,sDAAC,SAAI,WAAU,uCAAsC;AAAA,UACrD,6CAAC,SAAI,WAAU,0BACb;AAAA,wDAAC,qCAAa,KAAG,MAAC,QAAO,OAAM,MAAM,4CAAC,oCAAa,WAAU,WAAU,GAAI,SAAS,MAAM,eAAe,QAAS,GAAG,YAAwB,iBAAG;AAAA,YAChJ,4CAAC,qCAAa,KAAG,MAAC,QAAO,SAAQ,MAAM,4CAAC,iCAAU,WAAU,WAAU,GAAI,SAAS,aAAa,YAAwB,wBAAU;AAAA,aACpI;AAAA,WACF;AAAA,SAEJ,IACE,aACF,4EACE;AAAA,qDAAC,SAAI,WAAU,0BACb;AAAA,sDAAC,qCAAa,KAAG,MAAC,QAAO,OAAM,MAAM,4CAAC,oCAAa,WAAU,WAAU,GAAI,SAAS,MAAM,eAAe,QAAQ,GAAG,YAAwB,iBAAG;AAAA,UAC/I,4CAAC,qCAAa,KAAG,MAAC,QAAO,SAAQ,MAAM,4CAAC,iCAAU,WAAU,WAAU,GAAI,SAAS,aAAa,YAAwB,wBAAU;AAAA,UACjI,gBAAgB,cACf;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,QAAO;AAAA,cACP,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UACH,kBAAkB,gBACjB;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,QAAO;AAAA,cACP,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UACH,qBAAqB,wBACpB;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,MAAK;AAAA,cACL,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,WACN;AAAA,QACC,CAAC,gBAAgB,CAAC,iBACjB,4CAAC,OAAE,WAAU,sDAAqD,8DAElE,IACE;AAAA,SACN,IAEA,iBAAiB,kBAAkB;AAAA,OAEvC,IAEA,6CAAC,SAAI,WAAU,aACb;AAAA,kDAAC,WAAQ,eAA8B,aAA0B;AAAA,MAChE,UACC,6CAAC,SAAI,WAAU,0BACb;AAAA,oDAAC,qCAAa,KAAG,MAAC,MAAK,QAAO,MAAM,4CAAC,2BAAI,WAAU,WAAU,GAAI,SAAS,eAAe,YAAwB,iCAAmB;AAAA,QACpI,4CAAC,qCAAa,KAAG,MAAC,MAAK,UAAS,MAAM,4CAAC,sCAAe,WAAU,WAAU,GAAI,SAAS,gBAAgB,YAAwB,sBAAQ;AAAA,QACtI,gBAAgB,cACf;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,QAAO;AAAA,YACP,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,QACH,4BAA4B,uBAC3B;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,MAAK;AAAA,YACL,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,SACN,IACE,aACF,6CAAC,SAAI,WAAU,0BACb;AAAA,oDAAC,qCAAa,KAAG,MAAC,QAAO,SAAQ,MAAM,4CAAC,iCAAU,WAAU,WAAU,GAAI,SAAS,aAAa,YAAwB,wBAAU;AAAA,QACjI,gBAAgB,cACf;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,QAAO;AAAA,YACP,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,QACH,qBAAqB,wBACpB;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,MAAK;AAAA,YACL,MAAM,4CAAC,iCAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,SACN,IAEA,iBAAiB,0BAA0B;AAAA,OAE/C;AAAA,IAGD,QACC,6CAAC,SAAI,WAAU,+EACb;AAAA,mDAAC,SAAI,WAAU,qCACb;AAAA,oDAAC,iCAAU,WAAU,mCAAkC;AAAA,QACvD,6CAAC,SAAI,WAAU,WACb;AAAA,sDAAC,OAAE,WAAU,wCAAuC,+BAAiB;AAAA,UACrE,6CAAC,OAAE,WAAU,kEACX;AAAA,yDAAC,UAAK,WAAU,4DACb;AAAA,oDAAmB,MAAM,MAAM,SAAS;AAAA,cACzC,4CAAC,qCAAa,QAAQ,MAAM,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,eAC9D;AAAA,YACA,4CAAC,UAAK,kBAAC;AAAA,YACP,4CAAC,6BAAM,WAAU,WAAU;AAAA,gBAC1B,uBAAU,MAAM,OAAO;AAAA,aAC1B;AAAA,WACF;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,cAAc,KAAK;AAAA,UAElC;AAAA,wDAAC,yBAAE,WAAU,eAAc;AAAA,YAAE;AAAA;AAAA;AAAA,MAE/B;AAAA,OACF,IACE;AAAA,IAEH,WAAW,WAAW,SAAS,IAC9B,6CAAC,SAAI,WAAU,uCACb;AAAA,mDAAC,OAAE,WAAU,+CAA8C;AAAA;AAAA,QACvC,WAAW;AAAA,QAAO;AAAA,SACtC;AAAA,MACA,4CAAC,SAAI,WAAU,aACZ,qBAAW,IAAI,CAAC,QACf,6CAAC,SAAwB,WAAU,4EACjC;AAAA,qDAAC,SAAI,WAAU,WACb;AAAA,sDAAC,OAAE,WAAU,qBACX,uDAAC,UAAK,WAAU,oCACb;AAAA,kDAAmB,IAAI,MAAM,SAAS;AAAA,YACvC,4CAAC,qCAAa,QAAQ,IAAI,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,aAC5D,GACF;AAAA,UACA,6CAAC,SAAI,WAAU,kCACb;AAAA,wDAAC,yCAAe,SAAS,IAAI,SAAS,OAAO,GAAG,UAAU,OAAO,WAAU,iCAAgC;AAAA,YAC3G,4CAAC,UAAK,WAAU,iCAAgC,kBAAC;AAAA,YACjD,6CAAC,SAAI,WAAU,yDACb;AAAA,0DAAC,6BAAM,WAAU,WAAU;AAAA,kBAC1B,uBAAU,IAAI,OAAO;AAAA,eACxB;AAAA,aACF;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,SAAS,MAAM,YAAY,GAAG;AAAA,YAC9B,WAAU;AAAA,YAEV;AAAA,0DAAC,mCAAY,WAAU,eAAc;AAAA,cAAE;AAAA;AAAA;AAAA,QAEzC;AAAA,WAxBQ,IAAI,SAyBd,CACD,GACH;AAAA,OACF,IACE;AAAA,KACN,GACF;AAEJ;","names":[]}
@@ -26,6 +26,12 @@ interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {
26
26
  /** Raw "0.07 STRK"-style strings — already resolved by the caller. `null`/undefined renders "—". */
27
27
  floorPriceRaw?: string | null;
28
28
  lastSaleRaw?: string | null;
29
+ /**
30
+ * Pre-formatted USD equivalent of `cheapest.price` (e.g. "$12.34"), computed
31
+ * by the host from its own live rate feed — this package has no price-feed
32
+ * access by design. Omit (or pass null) to render no USD line.
33
+ */
34
+ usdValue?: string | null;
29
35
  /** Renders the sign-in/connect-wallet CTA for the given label (e.g. "Sign in to trade"). */
30
36
  renderAuthAction: (label: string) => ReactNode;
31
37
  /** Renders an inline help/info affordance for the given tooltip text. */
@@ -45,6 +51,6 @@ interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {
45
51
  showSponsorSolicitOption?: boolean;
46
52
  onOpenSponsorSolicit?: () => void;
47
53
  }
48
- declare function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({ cheapest, isOwner, isSignedIn, isProcessing, isERC1155, isMarketLoading, myListing, activeBids, walletAddress, remixEnabled, showDealOption, showSponsorOption, onOpenSponsorProposal, showSponsorSolicitOption, onOpenSponsorSolicit, floorPriceRaw, lastSaleRaw, renderAuthAction, renderHelp, onCancelClick, onAcceptBid, onOpenListing, onOpenTransfer, onOpenPurchase, onOpenOffer, onOpenRemix, onProposeDeal, }: AssetMarketplacePanelProps<T>): react_jsx_runtime.JSX.Element;
54
+ declare function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({ cheapest, isOwner, isSignedIn, isProcessing, isERC1155, isMarketLoading, myListing, activeBids, walletAddress, remixEnabled, showDealOption, showSponsorOption, onOpenSponsorProposal, showSponsorSolicitOption, onOpenSponsorSolicit, floorPriceRaw, lastSaleRaw, usdValue, renderAuthAction, renderHelp, onCancelClick, onAcceptBid, onOpenListing, onOpenTransfer, onOpenPurchase, onOpenOffer, onOpenRemix, onProposeDeal, }: AssetMarketplacePanelProps<T>): react_jsx_runtime.JSX.Element;
49
55
 
50
56
  export { type ApiOrderLike, AssetMarketplacePanel, type AssetMarketplacePanelProps };
@@ -26,6 +26,12 @@ interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {
26
26
  /** Raw "0.07 STRK"-style strings — already resolved by the caller. `null`/undefined renders "—". */
27
27
  floorPriceRaw?: string | null;
28
28
  lastSaleRaw?: string | null;
29
+ /**
30
+ * Pre-formatted USD equivalent of `cheapest.price` (e.g. "$12.34"), computed
31
+ * by the host from its own live rate feed — this package has no price-feed
32
+ * access by design. Omit (or pass null) to render no USD line.
33
+ */
34
+ usdValue?: string | null;
29
35
  /** Renders the sign-in/connect-wallet CTA for the given label (e.g. "Sign in to trade"). */
30
36
  renderAuthAction: (label: string) => ReactNode;
31
37
  /** Renders an inline help/info affordance for the given tooltip text. */
@@ -45,6 +51,6 @@ interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {
45
51
  showSponsorSolicitOption?: boolean;
46
52
  onOpenSponsorSolicit?: () => void;
47
53
  }
48
- declare function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({ cheapest, isOwner, isSignedIn, isProcessing, isERC1155, isMarketLoading, myListing, activeBids, walletAddress, remixEnabled, showDealOption, showSponsorOption, onOpenSponsorProposal, showSponsorSolicitOption, onOpenSponsorSolicit, floorPriceRaw, lastSaleRaw, renderAuthAction, renderHelp, onCancelClick, onAcceptBid, onOpenListing, onOpenTransfer, onOpenPurchase, onOpenOffer, onOpenRemix, onProposeDeal, }: AssetMarketplacePanelProps<T>): react_jsx_runtime.JSX.Element;
54
+ declare function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({ cheapest, isOwner, isSignedIn, isProcessing, isERC1155, isMarketLoading, myListing, activeBids, walletAddress, remixEnabled, showDealOption, showSponsorOption, onOpenSponsorProposal, showSponsorSolicitOption, onOpenSponsorSolicit, floorPriceRaw, lastSaleRaw, usdValue, renderAuthAction, renderHelp, onCancelClick, onAcceptBid, onOpenListing, onOpenTransfer, onOpenPurchase, onOpenOffer, onOpenRemix, onProposeDeal, }: AssetMarketplacePanelProps<T>): react_jsx_runtime.JSX.Element;
49
55
 
50
56
  export { type ApiOrderLike, AssetMarketplacePanel, type AssetMarketplacePanelProps };
@@ -50,6 +50,7 @@ function AssetMarketplacePanel({
50
50
  onOpenSponsorSolicit,
51
51
  floorPriceRaw,
52
52
  lastSaleRaw,
53
+ usdValue,
53
54
  renderAuthAction,
54
55
  renderHelp,
55
56
  onCancelClick,
@@ -72,12 +73,18 @@ function AssetMarketplacePanel({
72
73
  return /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs("div", { className: "relative space-y-4", children: [
73
74
  cheapest ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
74
75
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-5 gap-y-1.5", children: [
75
- /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
76
- /* @__PURE__ */ jsx(CurrencyIcon, { symbol: cheapest.price.currency ?? "", size: 26 }),
77
- /* @__PURE__ */ jsx("span", { className: "text-4xl font-bold tracking-tight", children: formatDisplayPrice(cheapest.price.formatted) }),
78
- renderHelp(
79
- `${isOwner && !canBuyMore ? "Your listing" : "Current price"} \xB7 Expires ${timeUntil(cheapest.endTime)}`
80
- )
76
+ /* @__PURE__ */ jsxs("div", { children: [
77
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
78
+ /* @__PURE__ */ jsx(CurrencyIcon, { symbol: cheapest.price.currency ?? "", size: 26 }),
79
+ /* @__PURE__ */ jsx("span", { className: "text-4xl font-bold tracking-tight", children: formatDisplayPrice(cheapest.price.formatted) }),
80
+ renderHelp(
81
+ `${isOwner && !canBuyMore ? "Your listing" : "Current price"} \xB7 Expires ${timeUntil(cheapest.endTime)}`
82
+ )
83
+ ] }),
84
+ usdValue && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mt-0.5", children: [
85
+ "\u2248 ",
86
+ usdValue
87
+ ] })
81
88
  ] }),
82
89
  /* @__PURE__ */ jsx(StatRow, { floorPriceRaw, lastSaleRaw })
83
90
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/asset-marketplace-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport {\n ArrowRightLeft, CheckCircle, Clock, GitBranch, HandCoins, Handshake, Loader2,\n ShoppingCart, Tag, X,\n} from \"lucide-react\";\nimport { CurrencyIcon, CurrencyAmount } from \"./currency-icon.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ActionButton } from \"./action-button.js\";\nimport { formatDisplayPrice, parsePriceDisplay } from \"../utils/format.js\";\nimport { timeUntil } from \"../utils/time.js\";\n\n/** Structural subset of `ApiOrder` (both apps' `@medialane/sdk` types satisfy this). */\nexport interface ApiOrderLike {\n orderHash: string;\n offerer: string;\n endTime: string;\n price: { formatted: string | null; currency: string | null };\n}\n\nexport interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {\n cheapest?: T;\n isOwner: boolean;\n isSignedIn: boolean;\n isProcessing: boolean;\n isERC1155: boolean;\n isMarketLoading?: boolean;\n myListing: T | null;\n activeBids: T[];\n walletAddress?: string | null;\n remixEnabled?: boolean;\n showDealOption?: boolean;\n /** Raw \"0.07 STRK\"-style strings — already resolved by the caller. `null`/undefined renders \"—\". */\n floorPriceRaw?: string | null;\n lastSaleRaw?: string | null;\n /** Renders the sign-in/connect-wallet CTA for the given label (e.g. \"Sign in to trade\"). */\n renderAuthAction: (label: string) => ReactNode;\n /** Renders an inline help/info affordance for the given tooltip text. */\n renderHelp: (content: string) => ReactNode;\n onCancelClick: (order: T) => void;\n onAcceptBid: (order: T) => void;\n onOpenListing: () => void;\n onOpenTransfer: () => void;\n onOpenPurchase: (order: T) => void;\n onOpenOffer: () => void;\n onOpenRemix?: () => void;\n onProposeDeal?: () => void;\n /** Non-owner: propose a sponsorship deal on this asset. */\n showSponsorOption?: boolean;\n onOpenSponsorProposal?: () => void;\n /** Owner: open this asset for sponsorship bidding. */\n showSponsorSolicitOption?: boolean;\n onOpenSponsorSolicit?: () => void;\n}\n\n/** Floor + last-sale stats — each hides itself when its data is absent\n * (no dangling \"—\" placeholders), and the whole row disappears when\n * neither is available. */\nfunction StatRow({ floorPriceRaw, lastSaleRaw }: { floorPriceRaw?: string | null; lastSaleRaw?: string | null }) {\n const floor = floorPriceRaw ? parsePriceDisplay(floorPriceRaw) : null;\n const lastSale = lastSaleRaw ? parsePriceDisplay(lastSaleRaw) : null;\n if (!floor?.symbol && !lastSale?.symbol) return null;\n return (\n <div className=\"flex items-center gap-4 text-sm text-muted-foreground\">\n {floor?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Floor</span>\n <CurrencyAmount amount={floor.numStr} symbol={floor.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n {lastSale?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Last sale</span>\n <CurrencyAmount amount={lastSale.numStr} symbol={lastSale.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n </div>\n );\n}\n\nexport function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({\n cheapest,\n isOwner,\n isSignedIn,\n isProcessing,\n isERC1155,\n isMarketLoading = false,\n myListing,\n activeBids,\n walletAddress,\n remixEnabled = false,\n showDealOption = false,\n showSponsorOption = false,\n onOpenSponsorProposal,\n showSponsorSolicitOption = false,\n onOpenSponsorSolicit,\n floorPriceRaw,\n lastSaleRaw,\n renderAuthAction,\n renderHelp,\n onCancelClick,\n onAcceptBid,\n onOpenListing,\n onOpenTransfer,\n onOpenPurchase,\n onOpenOffer,\n onOpenRemix,\n onProposeDeal,\n}: AssetMarketplacePanelProps<T>) {\n const myBid = !isOwner && walletAddress\n ? activeBids.find((bid) => bid.offerer.toLowerCase() === walletAddress.toLowerCase()) ?? null\n : null;\n\n const canBuyMore =\n isERC1155 && isOwner && !!cheapest && !!walletAddress &&\n cheapest.offerer.toLowerCase() !== walletAddress.toLowerCase();\n\n if (isMarketLoading && !cheapest) {\n return (\n <div className=\"space-y-4\">\n <div className=\"h-9 w-32 rounded-md bg-muted animate-pulse\" />\n <div className=\"h-12 w-full rounded-2xl bg-muted animate-pulse\" />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n\n <div className=\"relative space-y-4\">\n {cheapest ? (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-baseline gap-x-5 gap-y-1.5\">\n <div className=\"flex items-baseline gap-2\">\n <CurrencyIcon symbol={cheapest.price.currency ?? \"\"} size={26} />\n <span className=\"text-4xl font-bold tracking-tight\">\n {formatDisplayPrice(cheapest.price.formatted)}\n </span>\n {renderHelp(\n `${isOwner && !canBuyMore ? \"Your listing\" : \"Current price\"} · Expires ${timeUntil(cheapest.endTime)}`\n )}\n </div>\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n </div>\n\n {isOwner ? (\n <div className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2\">\n {myListing ? (\n <ActionButton big\n icon={isProcessing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <X className=\"h-4 w-4\" />}\n onClick={() => onCancelClick(myListing)}\n disabled={isProcessing}\n tone=\"red\"\n renderHelp={renderHelp}\n >\n Cancel Listing\n </ActionButton>\n ) : null}\n {/* ERC-721 has exactly one possible listing — once myListing exists,\n \"List on Marketplace\" is redundant next to \"Cancel Listing\" and\n reads as a broken/confusing pair. An ERC-1155 owner can still hold\n un-listed editions while one listing is active, so it stays for them. */}\n {(!myListing || isERC1155) ? (\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n ) : null}\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n\n {canBuyMore && (\n <>\n <div className=\"border-t border-border/40 pt-2 mt-1\" />\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest!)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n </div>\n </>\n )}\n </div>\n ) : isSignedIn ? (\n <>\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Create your own attributed derivative of this work.\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showDealOption && onProposeDeal ? (\n <ActionButton big\n action=\"license\"\n icon={<HandCoins className=\"h-4 w-4\" />}\n onClick={onProposeDeal}\n helpContent=\"Propose a license deal to the creator to use this work.\"\n renderHelp={renderHelp}\n >\n License\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n {!remixEnabled && !showDealOption ? (\n <p className=\"text-xs text-muted-foreground mt-2 leading-relaxed\">\n The creator marked this asset as no-derivatives.\n </p>\n ) : null}\n </>\n ) : (\n renderAuthAction(\"Sign in to trade\")\n )}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n {isOwner ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n ) : isSignedIn ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n ) : (\n renderAuthAction(\"Sign in to make an offer\")\n )}\n </div>\n )}\n\n {myBid ? (\n <div className=\"rounded-xl bg-amber-500/8 px-4 py-3 flex items-center justify-between gap-3\">\n <div className=\"min-w-0 flex items-center gap-2.5\">\n <HandCoins className=\"h-4 w-4 text-amber-500 shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-xs font-semibold text-amber-500\">Your active offer</p>\n <p className=\"text-xs text-muted-foreground flex items-center gap-1.5 mt-0.5\">\n <span className=\"font-bold text-foreground inline-flex items-center gap-1\">\n {formatDisplayPrice(myBid.price.formatted)}\n <CurrencyIcon symbol={myBid.price.currency ?? \"\"} size={12} />\n </span>\n <span>·</span>\n <Clock className=\"h-3 w-3\" />\n {timeUntil(myBid.endTime)}\n </p>\n </div>\n </div>\n <button\n className=\"shrink-0 text-xs font-semibold text-red-400 hover:text-red-300 transition-colors flex items-center gap-1\"\n onClick={() => onCancelClick(myBid)}\n >\n <X className=\"h-3.5 w-3.5\" />\n Cancel\n </button>\n </div>\n ) : null}\n\n {isOwner && activeBids.length > 0 ? (\n <div className=\"rounded-xl bg-card/40 p-5 space-y-3\">\n <p className=\"text-xs font-semibold text-muted-foreground\">\n Incoming offers ({activeBids.length})\n </p>\n <div className=\"space-y-2\">\n {activeBids.map((bid) => (\n <div key={bid.orderHash} className=\"flex items-center justify-between gap-3 rounded-lg bg-muted/30 px-3 py-2\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-bold\">\n <span className=\"inline-flex items-center gap-1.5\">\n {formatDisplayPrice(bid.price.formatted)}\n <CurrencyIcon symbol={bid.price.currency ?? \"\"} size={14} />\n </span>\n </p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <AddressDisplay address={bid.offerer} chars={4} showCopy={false} className=\"text-xs text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">·</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {timeUntil(bid.endTime)}\n </div>\n </div>\n </div>\n <button\n disabled={isProcessing}\n onClick={() => onAcceptBid(bid)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-xs font-semibold text-primary-foreground disabled:opacity-50\"\n >\n <CheckCircle className=\"h-3.5 w-3.5\" />\n Accept\n </button>\n </div>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/asset-marketplace-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport {\n ArrowRightLeft, CheckCircle, Clock, GitBranch, HandCoins, Handshake, Loader2,\n ShoppingCart, Tag, X,\n} from \"lucide-react\";\nimport { CurrencyIcon, CurrencyAmount } from \"./currency-icon.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ActionButton } from \"./action-button.js\";\nimport { formatDisplayPrice, parsePriceDisplay } from \"../utils/format.js\";\nimport { timeUntil } from \"../utils/time.js\";\n\n/** Structural subset of `ApiOrder` (both apps' `@medialane/sdk` types satisfy this). */\nexport interface ApiOrderLike {\n orderHash: string;\n offerer: string;\n endTime: string;\n price: { formatted: string | null; currency: string | null };\n}\n\nexport interface AssetMarketplacePanelProps<T extends ApiOrderLike = ApiOrderLike> {\n cheapest?: T;\n isOwner: boolean;\n isSignedIn: boolean;\n isProcessing: boolean;\n isERC1155: boolean;\n isMarketLoading?: boolean;\n myListing: T | null;\n activeBids: T[];\n walletAddress?: string | null;\n remixEnabled?: boolean;\n showDealOption?: boolean;\n /** Raw \"0.07 STRK\"-style strings — already resolved by the caller. `null`/undefined renders \"—\". */\n floorPriceRaw?: string | null;\n lastSaleRaw?: string | null;\n /**\n * Pre-formatted USD equivalent of `cheapest.price` (e.g. \"$12.34\"), computed\n * by the host from its own live rate feed — this package has no price-feed\n * access by design. Omit (or pass null) to render no USD line.\n */\n usdValue?: string | null;\n /** Renders the sign-in/connect-wallet CTA for the given label (e.g. \"Sign in to trade\"). */\n renderAuthAction: (label: string) => ReactNode;\n /** Renders an inline help/info affordance for the given tooltip text. */\n renderHelp: (content: string) => ReactNode;\n onCancelClick: (order: T) => void;\n onAcceptBid: (order: T) => void;\n onOpenListing: () => void;\n onOpenTransfer: () => void;\n onOpenPurchase: (order: T) => void;\n onOpenOffer: () => void;\n onOpenRemix?: () => void;\n onProposeDeal?: () => void;\n /** Non-owner: propose a sponsorship deal on this asset. */\n showSponsorOption?: boolean;\n onOpenSponsorProposal?: () => void;\n /** Owner: open this asset for sponsorship bidding. */\n showSponsorSolicitOption?: boolean;\n onOpenSponsorSolicit?: () => void;\n}\n\n/** Floor + last-sale stats — each hides itself when its data is absent\n * (no dangling \"—\" placeholders), and the whole row disappears when\n * neither is available. */\nfunction StatRow({ floorPriceRaw, lastSaleRaw }: { floorPriceRaw?: string | null; lastSaleRaw?: string | null }) {\n const floor = floorPriceRaw ? parsePriceDisplay(floorPriceRaw) : null;\n const lastSale = lastSaleRaw ? parsePriceDisplay(lastSaleRaw) : null;\n if (!floor?.symbol && !lastSale?.symbol) return null;\n return (\n <div className=\"flex items-center gap-4 text-sm text-muted-foreground\">\n {floor?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Floor</span>\n <CurrencyAmount amount={floor.numStr} symbol={floor.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n {lastSale?.symbol && (\n <span className=\"flex items-center gap-1.5\">\n <span>Last sale</span>\n <CurrencyAmount amount={lastSale.numStr} symbol={lastSale.symbol} iconSize={12} amountClassName=\"text-foreground font-semibold\" />\n </span>\n )}\n </div>\n );\n}\n\nexport function AssetMarketplacePanel<T extends ApiOrderLike = ApiOrderLike>({\n cheapest,\n isOwner,\n isSignedIn,\n isProcessing,\n isERC1155,\n isMarketLoading = false,\n myListing,\n activeBids,\n walletAddress,\n remixEnabled = false,\n showDealOption = false,\n showSponsorOption = false,\n onOpenSponsorProposal,\n showSponsorSolicitOption = false,\n onOpenSponsorSolicit,\n floorPriceRaw,\n lastSaleRaw,\n usdValue,\n renderAuthAction,\n renderHelp,\n onCancelClick,\n onAcceptBid,\n onOpenListing,\n onOpenTransfer,\n onOpenPurchase,\n onOpenOffer,\n onOpenRemix,\n onProposeDeal,\n}: AssetMarketplacePanelProps<T>) {\n const myBid = !isOwner && walletAddress\n ? activeBids.find((bid) => bid.offerer.toLowerCase() === walletAddress.toLowerCase()) ?? null\n : null;\n\n const canBuyMore =\n isERC1155 && isOwner && !!cheapest && !!walletAddress &&\n cheapest.offerer.toLowerCase() !== walletAddress.toLowerCase();\n\n if (isMarketLoading && !cheapest) {\n return (\n <div className=\"space-y-4\">\n <div className=\"h-9 w-32 rounded-md bg-muted animate-pulse\" />\n <div className=\"h-12 w-full rounded-2xl bg-muted animate-pulse\" />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n\n <div className=\"relative space-y-4\">\n {cheapest ? (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-baseline gap-x-5 gap-y-1.5\">\n <div>\n <div className=\"flex items-baseline gap-2\">\n <CurrencyIcon symbol={cheapest.price.currency ?? \"\"} size={26} />\n <span className=\"text-4xl font-bold tracking-tight\">\n {formatDisplayPrice(cheapest.price.formatted)}\n </span>\n {renderHelp(\n `${isOwner && !canBuyMore ? \"Your listing\" : \"Current price\"} · Expires ${timeUntil(cheapest.endTime)}`\n )}\n </div>\n {usdValue && <p className=\"text-sm text-muted-foreground mt-0.5\">≈ {usdValue}</p>}\n </div>\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n </div>\n\n {isOwner ? (\n <div className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2\">\n {myListing ? (\n <ActionButton big\n icon={isProcessing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <X className=\"h-4 w-4\" />}\n onClick={() => onCancelClick(myListing)}\n disabled={isProcessing}\n tone=\"red\"\n renderHelp={renderHelp}\n >\n Cancel Listing\n </ActionButton>\n ) : null}\n {/* ERC-721 has exactly one possible listing — once myListing exists,\n \"List on Marketplace\" is redundant next to \"Cancel Listing\" and\n reads as a broken/confusing pair. An ERC-1155 owner can still hold\n un-listed editions while one listing is active, so it stays for them. */}\n {(!myListing || isERC1155) ? (\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n ) : null}\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n\n {canBuyMore && (\n <>\n <div className=\"border-t border-border/40 pt-2 mt-1\" />\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest!)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n </div>\n </>\n )}\n </div>\n ) : isSignedIn ? (\n <>\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"buy\" icon={<ShoppingCart className=\"h-4 w-4\" />} onClick={() => onOpenPurchase(cheapest)} renderHelp={renderHelp}>Buy</ActionButton>\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Create your own attributed derivative of this work.\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showDealOption && onProposeDeal ? (\n <ActionButton big\n action=\"license\"\n icon={<HandCoins className=\"h-4 w-4\" />}\n onClick={onProposeDeal}\n helpContent=\"Propose a license deal to the creator to use this work.\"\n renderHelp={renderHelp}\n >\n License\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n {!remixEnabled && !showDealOption ? (\n <p className=\"text-xs text-muted-foreground mt-2 leading-relaxed\">\n The creator marked this asset as no-derivatives.\n </p>\n ) : null}\n </>\n ) : (\n renderAuthAction(\"Sign in to trade\")\n )}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <StatRow floorPriceRaw={floorPriceRaw} lastSaleRaw={lastSaleRaw} />\n {isOwner ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big tone=\"blue\" icon={<Tag className=\"h-4 w-4\" />} onClick={onOpenListing} renderHelp={renderHelp}>List on Marketplace</ActionButton>\n <ActionButton big tone=\"orange\" icon={<ArrowRightLeft className=\"h-4 w-4\" />} onClick={onOpenTransfer} renderHelp={renderHelp}>Transfer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorSolicitOption && onOpenSponsorSolicit ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorSolicit}\n helpContent=\"Let sponsors bid on a license for this asset.\"\n renderHelp={renderHelp}\n >\n Open for Sponsorship\n </ActionButton>\n ) : null}\n </div>\n ) : isSignedIn ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <ActionButton big action=\"offer\" icon={<HandCoins className=\"h-4 w-4\" />} onClick={onOpenOffer} renderHelp={renderHelp}>Make offer</ActionButton>\n {remixEnabled && onOpenRemix ? (\n <ActionButton big\n action=\"remix\"\n icon={<GitBranch className=\"h-4 w-4\" />}\n onClick={onOpenRemix}\n helpContent=\"Build a licensed derivative of this digital asset — your remix is minted as a new onchain NFT linked to the original\"\n renderHelp={renderHelp}\n >\n Remix\n </ActionButton>\n ) : null}\n {showSponsorOption && onOpenSponsorProposal ? (\n <ActionButton big\n tone=\"blue\"\n icon={<Handshake className=\"h-4 w-4\" />}\n onClick={onOpenSponsorProposal}\n helpContent=\"Propose to sponsor this creator's work — pay them directly for a license, no escrow.\"\n renderHelp={renderHelp}\n >\n Sponsor this IP\n </ActionButton>\n ) : null}\n </div>\n ) : (\n renderAuthAction(\"Sign in to make an offer\")\n )}\n </div>\n )}\n\n {myBid ? (\n <div className=\"rounded-xl bg-amber-500/8 px-4 py-3 flex items-center justify-between gap-3\">\n <div className=\"min-w-0 flex items-center gap-2.5\">\n <HandCoins className=\"h-4 w-4 text-amber-500 shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-xs font-semibold text-amber-500\">Your active offer</p>\n <p className=\"text-xs text-muted-foreground flex items-center gap-1.5 mt-0.5\">\n <span className=\"font-bold text-foreground inline-flex items-center gap-1\">\n {formatDisplayPrice(myBid.price.formatted)}\n <CurrencyIcon symbol={myBid.price.currency ?? \"\"} size={12} />\n </span>\n <span>·</span>\n <Clock className=\"h-3 w-3\" />\n {timeUntil(myBid.endTime)}\n </p>\n </div>\n </div>\n <button\n className=\"shrink-0 text-xs font-semibold text-red-400 hover:text-red-300 transition-colors flex items-center gap-1\"\n onClick={() => onCancelClick(myBid)}\n >\n <X className=\"h-3.5 w-3.5\" />\n Cancel\n </button>\n </div>\n ) : null}\n\n {isOwner && activeBids.length > 0 ? (\n <div className=\"rounded-xl bg-card/40 p-5 space-y-3\">\n <p className=\"text-xs font-semibold text-muted-foreground\">\n Incoming offers ({activeBids.length})\n </p>\n <div className=\"space-y-2\">\n {activeBids.map((bid) => (\n <div key={bid.orderHash} className=\"flex items-center justify-between gap-3 rounded-lg bg-muted/30 px-3 py-2\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-bold\">\n <span className=\"inline-flex items-center gap-1.5\">\n {formatDisplayPrice(bid.price.formatted)}\n <CurrencyIcon symbol={bid.price.currency ?? \"\"} size={14} />\n </span>\n </p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <AddressDisplay address={bid.offerer} chars={4} showCopy={false} className=\"text-xs text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">·</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {timeUntil(bid.endTime)}\n </div>\n </div>\n </div>\n <button\n disabled={isProcessing}\n onClick={() => onAcceptBid(bid)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-xs font-semibold text-primary-foreground disabled:opacity-50\"\n >\n <CheckCircle className=\"h-3.5 w-3.5\" />\n Accept\n </button>\n </div>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":";AAwEQ,SAmIU,UAlIR,KADF;AArER;AAAA,EACE;AAAA,EAAgB;AAAA,EAAa;AAAA,EAAO;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EACrE;AAAA,EAAc;AAAA,EAAK;AAAA,OACd;AACP,SAAS,cAAc,sBAAsB;AAC7C,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB,yBAAyB;AACtD,SAAS,iBAAiB;AAsD1B,SAAS,QAAQ,EAAE,eAAe,YAAY,GAAmE;AAC/G,QAAM,QAAQ,gBAAgB,kBAAkB,aAAa,IAAI;AACjE,QAAM,WAAW,cAAc,kBAAkB,WAAW,IAAI;AAChE,MAAI,CAAC,OAAO,UAAU,CAAC,UAAU,OAAQ,QAAO;AAChD,SACE,qBAAC,SAAI,WAAU,yDACZ;AAAA,WAAO,UACN,qBAAC,UAAK,WAAU,6BACd;AAAA,0BAAC,UAAK,mBAAK;AAAA,MACX,oBAAC,kBAAe,QAAQ,MAAM,QAAQ,QAAQ,MAAM,QAAQ,UAAU,IAAI,iBAAgB,iCAAgC;AAAA,OAC5H;AAAA,IAED,UAAU,UACT,qBAAC,UAAK,WAAU,6BACd;AAAA,0BAAC,UAAK,uBAAS;AAAA,MACf,oBAAC,kBAAe,QAAQ,SAAS,QAAQ,QAAQ,SAAS,QAAQ,UAAU,IAAI,iBAAgB,iCAAgC;AAAA,OAClI;AAAA,KAEJ;AAEJ;AAEO,SAAS,sBAA6D;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB;AAAA,EACA,2BAA2B;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkC;AAChC,QAAM,QAAQ,CAAC,WAAW,gBACtB,WAAW,KAAK,CAAC,QAAQ,IAAI,QAAQ,YAAY,MAAM,cAAc,YAAY,CAAC,KAAK,OACvF;AAEJ,QAAM,aACJ,aAAa,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,iBACxC,SAAS,QAAQ,YAAY,MAAM,cAAc,YAAY;AAE/D,MAAI,mBAAmB,CAAC,UAAU;AAChC,WACE,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,SAAI,WAAU,8CAA6C;AAAA,MAC5D,oBAAC,SAAI,WAAU,kDAAiD;AAAA,OAClE;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,YAEb,+BAAC,SAAI,WAAU,sBACZ;AAAA,eACC,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,mDACb;AAAA,6BAAC,SACC;AAAA,+BAAC,SAAI,WAAU,6BACb;AAAA,gCAAC,gBAAa,QAAQ,SAAS,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,YAC/D,oBAAC,UAAK,WAAU,qCACb,6BAAmB,SAAS,MAAM,SAAS,GAC9C;AAAA,YACC;AAAA,cACC,GAAG,WAAW,CAAC,aAAa,iBAAiB,eAAe,iBAAc,UAAU,SAAS,OAAO,CAAC;AAAA,YACvG;AAAA,aACF;AAAA,UACC,YAAY,qBAAC,OAAE,WAAU,wCAAuC;AAAA;AAAA,YAAG;AAAA,aAAS;AAAA,WAC/E;AAAA,QACA,oBAAC,WAAQ,eAA8B,aAA0B;AAAA,SACnE;AAAA,MAEC,UACC,qBAAC,SAAI,WAAU,aACb;AAAA,6BAAC,SAAI,WAAU,0BACZ;AAAA,sBACC;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,MAAM,eAAe,oBAAC,WAAQ,WAAU,wBAAuB,IAAK,oBAAC,KAAE,WAAU,WAAU;AAAA,cAC3F,SAAS,MAAM,cAAc,SAAS;AAAA,cACtC,UAAU;AAAA,cACV,MAAK;AAAA,cACL;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UAKF,CAAC,aAAa,YACd,oBAAC,gBAAa,KAAG,MAAC,MAAK,QAAO,MAAM,oBAAC,OAAI,WAAU,WAAU,GAAI,SAAS,eAAe,YAAwB,iCAAmB,IAClI;AAAA,UACJ,oBAAC,gBAAa,KAAG,MAAC,MAAK,UAAS,MAAM,oBAAC,kBAAe,WAAU,WAAU,GAAI,SAAS,gBAAgB,YAAwB,sBAAQ;AAAA,UACtI,gBAAgB,cACf;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,QAAO;AAAA,cACP,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UACH,4BAA4B,uBAC3B;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,MAAK;AAAA,cACL,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,WACN;AAAA,QAEC,cACC,iCACE;AAAA,8BAAC,SAAI,WAAU,uCAAsC;AAAA,UACrD,qBAAC,SAAI,WAAU,0BACb;AAAA,gCAAC,gBAAa,KAAG,MAAC,QAAO,OAAM,MAAM,oBAAC,gBAAa,WAAU,WAAU,GAAI,SAAS,MAAM,eAAe,QAAS,GAAG,YAAwB,iBAAG;AAAA,YAChJ,oBAAC,gBAAa,KAAG,MAAC,QAAO,SAAQ,MAAM,oBAAC,aAAU,WAAU,WAAU,GAAI,SAAS,aAAa,YAAwB,wBAAU;AAAA,aACpI;AAAA,WACF;AAAA,SAEJ,IACE,aACF,iCACE;AAAA,6BAAC,SAAI,WAAU,0BACb;AAAA,8BAAC,gBAAa,KAAG,MAAC,QAAO,OAAM,MAAM,oBAAC,gBAAa,WAAU,WAAU,GAAI,SAAS,MAAM,eAAe,QAAQ,GAAG,YAAwB,iBAAG;AAAA,UAC/I,oBAAC,gBAAa,KAAG,MAAC,QAAO,SAAQ,MAAM,oBAAC,aAAU,WAAU,WAAU,GAAI,SAAS,aAAa,YAAwB,wBAAU;AAAA,UACjI,gBAAgB,cACf;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,QAAO;AAAA,cACP,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UACH,kBAAkB,gBACjB;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,QAAO;AAAA,cACP,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,UACH,qBAAqB,wBACpB;AAAA,YAAC;AAAA;AAAA,cAAa,KAAG;AAAA,cACf,MAAK;AAAA,cACL,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,cACrC,SAAS;AAAA,cACT,aAAY;AAAA,cACZ;AAAA,cACD;AAAA;AAAA,UAED,IACE;AAAA,WACN;AAAA,QACC,CAAC,gBAAgB,CAAC,iBACjB,oBAAC,OAAE,WAAU,sDAAqD,8DAElE,IACE;AAAA,SACN,IAEA,iBAAiB,kBAAkB;AAAA,OAEvC,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,WAAQ,eAA8B,aAA0B;AAAA,MAChE,UACC,qBAAC,SAAI,WAAU,0BACb;AAAA,4BAAC,gBAAa,KAAG,MAAC,MAAK,QAAO,MAAM,oBAAC,OAAI,WAAU,WAAU,GAAI,SAAS,eAAe,YAAwB,iCAAmB;AAAA,QACpI,oBAAC,gBAAa,KAAG,MAAC,MAAK,UAAS,MAAM,oBAAC,kBAAe,WAAU,WAAU,GAAI,SAAS,gBAAgB,YAAwB,sBAAQ;AAAA,QACtI,gBAAgB,cACf;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,QAAO;AAAA,YACP,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,QACH,4BAA4B,uBAC3B;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,MAAK;AAAA,YACL,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,SACN,IACE,aACF,qBAAC,SAAI,WAAU,0BACb;AAAA,4BAAC,gBAAa,KAAG,MAAC,QAAO,SAAQ,MAAM,oBAAC,aAAU,WAAU,WAAU,GAAI,SAAS,aAAa,YAAwB,wBAAU;AAAA,QACjI,gBAAgB,cACf;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,QAAO;AAAA,YACP,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,QACH,qBAAqB,wBACpB;AAAA,UAAC;AAAA;AAAA,YAAa,KAAG;AAAA,YACf,MAAK;AAAA,YACL,MAAM,oBAAC,aAAU,WAAU,WAAU;AAAA,YACrC,SAAS;AAAA,YACT,aAAY;AAAA,YACZ;AAAA,YACD;AAAA;AAAA,QAED,IACE;AAAA,SACN,IAEA,iBAAiB,0BAA0B;AAAA,OAE/C;AAAA,IAGD,QACC,qBAAC,SAAI,WAAU,+EACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,aAAU,WAAU,mCAAkC;AAAA,QACvD,qBAAC,SAAI,WAAU,WACb;AAAA,8BAAC,OAAE,WAAU,wCAAuC,+BAAiB;AAAA,UACrE,qBAAC,OAAE,WAAU,kEACX;AAAA,iCAAC,UAAK,WAAU,4DACb;AAAA,iCAAmB,MAAM,MAAM,SAAS;AAAA,cACzC,oBAAC,gBAAa,QAAQ,MAAM,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,eAC9D;AAAA,YACA,oBAAC,UAAK,kBAAC;AAAA,YACP,oBAAC,SAAM,WAAU,WAAU;AAAA,YAC1B,UAAU,MAAM,OAAO;AAAA,aAC1B;AAAA,WACF;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,cAAc,KAAK;AAAA,UAElC;AAAA,gCAAC,KAAE,WAAU,eAAc;AAAA,YAAE;AAAA;AAAA;AAAA,MAE/B;AAAA,OACF,IACE;AAAA,IAEH,WAAW,WAAW,SAAS,IAC9B,qBAAC,SAAI,WAAU,uCACb;AAAA,2BAAC,OAAE,WAAU,+CAA8C;AAAA;AAAA,QACvC,WAAW;AAAA,QAAO;AAAA,SACtC;AAAA,MACA,oBAAC,SAAI,WAAU,aACZ,qBAAW,IAAI,CAAC,QACf,qBAAC,SAAwB,WAAU,4EACjC;AAAA,6BAAC,SAAI,WAAU,WACb;AAAA,8BAAC,OAAE,WAAU,qBACX,+BAAC,UAAK,WAAU,oCACb;AAAA,+BAAmB,IAAI,MAAM,SAAS;AAAA,YACvC,oBAAC,gBAAa,QAAQ,IAAI,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,aAC5D,GACF;AAAA,UACA,qBAAC,SAAI,WAAU,kCACb;AAAA,gCAAC,kBAAe,SAAS,IAAI,SAAS,OAAO,GAAG,UAAU,OAAO,WAAU,iCAAgC;AAAA,YAC3G,oBAAC,UAAK,WAAU,iCAAgC,kBAAC;AAAA,YACjD,qBAAC,SAAI,WAAU,yDACb;AAAA,kCAAC,SAAM,WAAU,WAAU;AAAA,cAC1B,UAAU,IAAI,OAAO;AAAA,eACxB;AAAA,aACF;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,SAAS,MAAM,YAAY,GAAG;AAAA,YAC9B,WAAU;AAAA,YAEV;AAAA,kCAAC,eAAY,WAAU,eAAc;AAAA,cAAE;AAAA;AAAA;AAAA,QAEzC;AAAA,WAxBQ,IAAI,SAyBd,CACD,GACH;AAAA,OACF,IACE;AAAA,KACN,GACF;AAEJ;","names":[]}
@@ -45,7 +45,7 @@ var import_ipfs = require("../utils/ipfs.js");
45
45
  var import_format = require("../utils/format.js");
46
46
  var import_time = require("../utils/time.js");
47
47
  var import_living_render_collections = require("../data/living-render-collections.js");
48
- function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl }) {
48
+ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }) {
49
49
  const order = rawOrder;
50
50
  const [imgError, setImgError] = (0, import_react.useState)(false);
51
51
  const isListing = order.offer.itemType === "ERC721" || order.offer.itemType === "ERC1155";
@@ -81,6 +81,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
81
81
  order.price.currency && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: order.price.currency, size: 11 }),
82
82
  (0, import_format.formatDisplayPrice)(order.price.formatted)
83
83
  ] }),
84
+ usdValue && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground/70", children: usdValue }),
84
85
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground", children: (0, import_time.timeAgo)(order.createdAt) })
85
86
  ] })
86
87
  ] }) });
@@ -116,7 +117,8 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
116
117
  order.price.currency && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: order.price.currency, size: 18 }),
117
118
  (0, import_format.formatDisplayPrice)(order.price.formatted),
118
119
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: order.price.currency })
119
- ] })
120
+ ] }),
121
+ usdValue && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground/60 mt-0.5", children: usdValue })
120
122
  ] }),
121
123
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground/60 whitespace-nowrap shrink-0", children: (0, import_time.timeAgo)(order.createdAt) })
122
124
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport type { ApiOrder, Chain } from \"@medialane/sdk\";\n\n/** ui's pinned SDK lags the apps — extend structurally for fields newer SDKs carry. */\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n /** App passes a fully constructed <DropdownMenu> here */\n overflowMenu?: React.ReactNode;\n /**\n * Optional flex-1 primary control for listings, replacing the default\n * Buy/View button — lets a host inject its own action (e.g. an owner\n * \"Cancel\" with an app-specific, auth-coupled handler) while keeping this\n * card's layout. Ignored for offers (which always render \"View asset\").\n */\n primaryAction?: React.ReactNode;\n compact?: boolean;\n /**\n * Pre-resolved, browser-loadable image URL. When provided (including null),\n * overrides the card's internal ipfsToHttp resolution — apps that proxy or\n * resize images (e.g. a same-origin /api/ipfs?w= proxy) pass it here.\n * Omit for the default gateway resolution; null renders the no-image fallback.\n */\n imageUrl?: string | null;\n}\n\nexport function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl }: ListingCardProps) {\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 ? ipfsToHttp(order.token.image) : null);\n // Not resolved through ipfsToHttp — animation_url is legitimately a data: URI for\n // fully on-chain-rendered collections (ipfsToHttp rejects data: by design).\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 = `/asset/${order.nftContract}/${order.nftTokenId}`;\n\n // Show the action bar for listings (Buy/View) and for offers (View asset),\n // whenever the host wired any action or an overflow menu.\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n // ─── Compact variant ──────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold truncate\">{name}</p>\n {order.price?.formatted && (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={11} />}\n {formatDisplayPrice(order.price.formatted)}\n </p>\n )}\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n // ─── Full variant ─────────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"font-semibold text-base truncate leading-snug\">{name}</p>\n <p className=\"text-2xs text-muted-foreground truncate leading-snug mt-0.5\">\n {order.token?.description ? order.token.description : `#${order.nftTokenId}`}\n </p>\n </div>\n\n {/* Price / Offer + age */}\n {order.price?.formatted && (\n <div className=\"flex items-end justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-2xs uppercase tracking-widest text-muted-foreground/55 leading-none\">\n {isListing ? \"Price\" : \"Offer\"}\n </p>\n <p className=\"text-lg font-bold price-value leading-none inline-flex items-center gap-1.5 mt-1.5\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={18} />}\n {formatDisplayPrice(order.price.formatted)}\n <span className=\"sr-only\">{order.price.currency}</span>\n </p>\n </div>\n <p className=\"text-2xs text-muted-foreground/60 whitespace-nowrap shrink-0\">\n {timeAgo(order.createdAt)}\n </p>\n </div>\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2EgB;AAzEhB,mBAAyB;AACzB,kBAAiB;AACjB,0BAAuD;AACvD,+BAA2B;AAC3B,2BAA6B;AAC7B,kCAAmC;AACnC,gBAAmB;AACnB,kBAA2B;AAC3B,oBAAmC;AACnC,kBAAwB;AACxB,uCAAyC;AA8BlC,SAAS,YAAY,EAAE,OAAO,UAAU,SAAS,OAAO,OAAO,QAAQ,cAAc,eAAe,UAAU,OAAO,SAAS,GAAqB;AACxJ,QAAM,QAAQ;AACd,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,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,YAAQ,wBAAW,MAAM,MAAM,KAAK,IAAI;AAGxG,QAAM,eAAe,MAAM,OAAO,gBAAgB;AAClD,QAAM,OAAO,CAAC,EAAE,MAAM,SAAS,MAAM,oBAAgB,2DAAyB,MAAM,MAAM,YAAY,GAAY,MAAM,WAAY;AACpI,QAAM,YAAY,UAAU,MAAM,WAAW,IAAI,MAAM,UAAU;AAIjE,QAAM,gBAAgB,CAAC,EAAE,SAAS,UAAU,gBAAgB;AAG5D,MAAI,SAAS;AACX,WACE,4CAAC,uCAAW,WAAU,aACpB,uDAAC,YAAAA,SAAA,EAAK,MAAM,WAAW,WAAU,SAC/B;AAAA,kDAAC,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,4CAAC,SAAI,WAAU,6GACb,uDAAC,UAAK,WAAU,2CAA0C;AAAA;AAAA,YAAE,MAAM;AAAA,aAAW,GAC/E;AAAA;AAAA,MAEJ,GACF;AAAA,MACA,6CAAC,SAAI,WAAU,qBACb;AAAA,oDAAC,OAAE,WAAU,kCAAkC,gBAAK;AAAA,QACnD,MAAM,OAAO,aACZ,6CAAC,OAAE,WAAU,iEACV;AAAA,gBAAM,MAAM,YAAY,4CAAC,qCAAa,QAAQ,MAAM,MAAM,UAAU,MAAM,IAAI;AAAA,cAC9E,kCAAmB,MAAM,MAAM,SAAS;AAAA,WAC3C;AAAA,QAEF,4CAAC,OAAE,WAAU,kCAAkC,mCAAQ,MAAM,SAAS,GAAE;AAAA,SAC1E;AAAA,OACF,GACF;AAAA,EAEJ;AAGA,SACE,4CAAC,uCAAW,WAAU,aACpB,uDAAC,YAAAA,SAAA,EAAK,MAAM,WAAW,WAAU,SAC/B;AAAA,gDAAC,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,4CAAC,SAAI,WAAU,6GACb,uDAAC,UAAK,WAAU,4CAA2C;AAAA;AAAA,UAAE,MAAM;AAAA,WAAW,GAChF;AAAA;AAAA,IAEJ,GACF;AAAA,IAEA,6CAAC,SAAI,WAAU,mBACb;AAAA,mDAAC,SAAI,WAAU,WACb;AAAA,oDAAC,OAAE,WAAU,iDAAiD,gBAAK;AAAA,QACnE,4CAAC,OAAE,WAAU,+DACV,gBAAM,OAAO,cAAc,MAAM,MAAM,cAAc,IAAI,MAAM,UAAU,IAC5E;AAAA,SACF;AAAA,MAGC,MAAM,OAAO,aACZ,6CAAC,SAAI,WAAU,wCACb;AAAA,qDAAC,SAAI,WAAU,WACb;AAAA,sDAAC,OAAE,WAAU,4EACV,sBAAY,UAAU,SACzB;AAAA,UACA,6CAAC,OAAE,WAAU,sFACV;AAAA,kBAAM,MAAM,YAAY,4CAAC,qCAAa,QAAQ,MAAM,MAAM,UAAU,MAAM,IAAI;AAAA,gBAC9E,kCAAmB,MAAM,MAAM,SAAS;AAAA,YACzC,4CAAC,UAAK,WAAU,WAAW,gBAAM,MAAM,UAAS;AAAA,aAClD;AAAA,WACF;AAAA,QACA,4CAAC,OAAE,WAAU,gEACV,mCAAQ,MAAM,SAAS,GAC1B;AAAA,SACF;AAAA,MAGD,iBACC,6CAAC,SAAI,WAAU,6BACZ;AAAA,oBACC,gBACE,gBACE,QACF,4CAAC,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,0DAAC,2BAAI,WAAU,wBAAuB;AAAA,cAAE;AAAA;AAAA;AAAA,QAC1C,GACF,IAEA;AAAA,UAAC,YAAAA;AAAA,UAAA;AAAA,YACC,MAAM;AAAA,YACN,WAAU;AAAA,YAEV;AAAA,0DAAC,oCAAa,WAAU,wBAAuB;AAAA,cAAE;AAAA;AAAA;AAAA,QACnD,IAGF;AAAA,UAAC,YAAAA;AAAA,UAAA;AAAA,YACC,MAAM;AAAA,YACN,WAAU;AAAA,YAEV;AAAA,0DAAC,oCAAa,WAAU,wBAAuB;AAAA,cAAE;AAAA;AAAA;AAAA,QACnD;AAAA,QAED,UACC;AAAA,UAAC;AAAA;AAAA,YACC,eAAW;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,4CAAC,6BAAM,WAAU,eAAc,IAAK,4CAAC,oCAAa,WAAU,eAAc;AAAA;AAAA,QACtF;AAAA,QAED;AAAA,SACH;AAAA,OAEJ;AAAA,KACF,GACF;AAEJ;AAEO,SAAS,sBAAsB;AACpC,SACE,6CAAC,SAAI,WAAU,aACb;AAAA,gDAAC,SAAI,WAAU,+CAA8C;AAAA,IAC7D,6CAAC,SAAI,WAAU,mBACb;AAAA,mDAAC,SAAI,WAAU,aACb;AAAA,oDAAC,SAAI,WAAU,4CAA2C;AAAA,QAC1D,4CAAC,SAAI,WAAU,4CAA2C;AAAA,SAC5D;AAAA,MACA,4CAAC,SAAI,WAAU,4CAA2C;AAAA,MAC1D,4CAAC,SAAI,WAAU,4CAA2C;AAAA,OAC5D;AAAA,KACF;AAEJ;","names":["Link"]}
1
+ {"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport type { ApiOrder, Chain } from \"@medialane/sdk\";\n\n/** ui's pinned SDK lags the apps — extend structurally for fields newer SDKs carry. */\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n /** App passes a fully constructed <DropdownMenu> here */\n overflowMenu?: React.ReactNode;\n /**\n * Optional flex-1 primary control for listings, replacing the default\n * Buy/View button — lets a host inject its own action (e.g. an owner\n * \"Cancel\" with an app-specific, auth-coupled handler) while keeping this\n * card's layout. Ignored for offers (which always render \"View asset\").\n */\n primaryAction?: React.ReactNode;\n compact?: boolean;\n /**\n * Pre-resolved, browser-loadable image URL. When provided (including null),\n * overrides the card's internal ipfsToHttp resolution — apps that proxy or\n * resize images (e.g. a same-origin /api/ipfs?w= proxy) pass it here.\n * Omit for the default gateway resolution; null renders the no-image fallback.\n */\n imageUrl?: string | null;\n /**\n * Pre-formatted USD equivalent of order.price (e.g. \"$12.34\"), computed by\n * the host from its own live rate feed — this package has no price-feed\n * access by design. Omit (or pass null) to render no USD line, e.g. when\n * the host has no live rate for this order's currency.\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 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 ? ipfsToHttp(order.token.image) : null);\n // Not resolved through ipfsToHttp — animation_url is legitimately a data: URI for\n // fully on-chain-rendered collections (ipfsToHttp rejects data: by design).\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 = `/asset/${order.nftContract}/${order.nftTokenId}`;\n\n // Show the action bar for listings (Buy/View) and for offers (View asset),\n // whenever the host wired any action or an overflow menu.\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n // ─── Compact variant ──────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold truncate\">{name}</p>\n {order.price?.formatted && (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={11} />}\n {formatDisplayPrice(order.price.formatted)}\n </p>\n )}\n {usdValue && <p className=\"text-2xs text-muted-foreground/70\">{usdValue}</p>}\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n // ─── Full variant ─────────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"font-semibold text-base truncate leading-snug\">{name}</p>\n <p className=\"text-2xs text-muted-foreground truncate leading-snug mt-0.5\">\n {order.token?.description ? order.token.description : `#${order.nftTokenId}`}\n </p>\n </div>\n\n {/* Price / Offer + age */}\n {order.price?.formatted && (\n <div className=\"flex items-end justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-2xs uppercase tracking-widest text-muted-foreground/55 leading-none\">\n {isListing ? \"Price\" : \"Offer\"}\n </p>\n <p className=\"text-lg font-bold price-value leading-none inline-flex items-center gap-1.5 mt-1.5\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={18} />}\n {formatDisplayPrice(order.price.formatted)}\n <span className=\"sr-only\">{order.price.currency}</span>\n </p>\n {usdValue && <p className=\"text-2xs text-muted-foreground/60 mt-0.5\">{usdValue}</p>}\n </div>\n <p className=\"text-2xs text-muted-foreground/60 whitespace-nowrap shrink-0\">\n {timeAgo(order.createdAt)}\n </p>\n </div>\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":["Link"]}
@@ -23,8 +23,15 @@ interface ListingCardProps {
23
23
  * Omit for the default gateway resolution; null renders the no-image fallback.
24
24
  */
25
25
  imageUrl?: string | null;
26
+ /**
27
+ * Pre-formatted USD equivalent of order.price (e.g. "$12.34"), computed by
28
+ * the host from its own live rate feed — this package has no price-feed
29
+ * access by design. Omit (or pass null) to render no USD line, e.g. when
30
+ * the host has no live rate for this order's currency.
31
+ */
32
+ usdValue?: string | null;
26
33
  }
27
- declare function ListingCard({ order: rawOrder, inCart, onBuy, onCart, overflowMenu, primaryAction, compact, imageUrl }: ListingCardProps): react_jsx_runtime.JSX.Element;
34
+ declare function ListingCard({ order: rawOrder, inCart, onBuy, onCart, overflowMenu, primaryAction, compact, imageUrl, usdValue }: ListingCardProps): react_jsx_runtime.JSX.Element;
28
35
  declare function ListingCardSkeleton(): react_jsx_runtime.JSX.Element;
29
36
 
30
37
  export { ListingCard, type ListingCardProps, ListingCardSkeleton };
@@ -23,8 +23,15 @@ interface ListingCardProps {
23
23
  * Omit for the default gateway resolution; null renders the no-image fallback.
24
24
  */
25
25
  imageUrl?: string | null;
26
+ /**
27
+ * Pre-formatted USD equivalent of order.price (e.g. "$12.34"), computed by
28
+ * the host from its own live rate feed — this package has no price-feed
29
+ * access by design. Omit (or pass null) to render no USD line, e.g. when
30
+ * the host has no live rate for this order's currency.
31
+ */
32
+ usdValue?: string | null;
26
33
  }
27
- declare function ListingCard({ order: rawOrder, inCart, onBuy, onCart, overflowMenu, primaryAction, compact, imageUrl }: ListingCardProps): react_jsx_runtime.JSX.Element;
34
+ declare function ListingCard({ order: rawOrder, inCart, onBuy, onCart, overflowMenu, primaryAction, compact, imageUrl, usdValue }: ListingCardProps): react_jsx_runtime.JSX.Element;
28
35
  declare function ListingCardSkeleton(): react_jsx_runtime.JSX.Element;
29
36
 
30
37
  export { ListingCard, type ListingCardProps, ListingCardSkeleton };
@@ -11,7 +11,7 @@ import { ipfsToHttp } from "../utils/ipfs.js";
11
11
  import { formatDisplayPrice } from "../utils/format.js";
12
12
  import { timeAgo } from "../utils/time.js";
13
13
  import { isLivingRenderCollection } from "../data/living-render-collections.js";
14
- function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl }) {
14
+ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }) {
15
15
  const order = rawOrder;
16
16
  const [imgError, setImgError] = useState(false);
17
17
  const isListing = order.offer.itemType === "ERC721" || order.offer.itemType === "ERC1155";
@@ -47,6 +47,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
47
47
  order.price.currency && /* @__PURE__ */ jsx(CurrencyIcon, { symbol: order.price.currency, size: 11 }),
48
48
  formatDisplayPrice(order.price.formatted)
49
49
  ] }),
50
+ usdValue && /* @__PURE__ */ jsx("p", { className: "text-2xs text-muted-foreground/70", children: usdValue }),
50
51
  /* @__PURE__ */ jsx("p", { className: "text-2xs text-muted-foreground", children: timeAgo(order.createdAt) })
51
52
  ] })
52
53
  ] }) });
@@ -82,7 +83,8 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
82
83
  order.price.currency && /* @__PURE__ */ jsx(CurrencyIcon, { symbol: order.price.currency, size: 18 }),
83
84
  formatDisplayPrice(order.price.formatted),
84
85
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: order.price.currency })
85
- ] })
86
+ ] }),
87
+ usdValue && /* @__PURE__ */ jsx("p", { className: "text-2xs text-muted-foreground/60 mt-0.5", children: usdValue })
86
88
  ] }),
87
89
  /* @__PURE__ */ jsx("p", { className: "text-2xs text-muted-foreground/60 whitespace-nowrap shrink-0", children: timeAgo(order.createdAt) })
88
90
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/listing-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport type { ApiOrder, Chain } from \"@medialane/sdk\";\n\n/** ui's pinned SDK lags the apps — extend structurally for fields newer SDKs carry. */\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n /** App passes a fully constructed <DropdownMenu> here */\n overflowMenu?: React.ReactNode;\n /**\n * Optional flex-1 primary control for listings, replacing the default\n * Buy/View button — lets a host inject its own action (e.g. an owner\n * \"Cancel\" with an app-specific, auth-coupled handler) while keeping this\n * card's layout. Ignored for offers (which always render \"View asset\").\n */\n primaryAction?: React.ReactNode;\n compact?: boolean;\n /**\n * Pre-resolved, browser-loadable image URL. When provided (including null),\n * overrides the card's internal ipfsToHttp resolution — apps that proxy or\n * resize images (e.g. a same-origin /api/ipfs?w= proxy) pass it here.\n * Omit for the default gateway resolution; null renders the no-image fallback.\n */\n imageUrl?: string | null;\n}\n\nexport function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl }: ListingCardProps) {\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 ? ipfsToHttp(order.token.image) : null);\n // Not resolved through ipfsToHttp — animation_url is legitimately a data: URI for\n // fully on-chain-rendered collections (ipfsToHttp rejects data: by design).\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 = `/asset/${order.nftContract}/${order.nftTokenId}`;\n\n // Show the action bar for listings (Buy/View) and for offers (View asset),\n // whenever the host wired any action or an overflow menu.\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n // ─── Compact variant ──────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold truncate\">{name}</p>\n {order.price?.formatted && (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={11} />}\n {formatDisplayPrice(order.price.formatted)}\n </p>\n )}\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n // ─── Full variant ─────────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"font-semibold text-base truncate leading-snug\">{name}</p>\n <p className=\"text-2xs text-muted-foreground truncate leading-snug mt-0.5\">\n {order.token?.description ? order.token.description : `#${order.nftTokenId}`}\n </p>\n </div>\n\n {/* Price / Offer + age */}\n {order.price?.formatted && (\n <div className=\"flex items-end justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-2xs uppercase tracking-widest text-muted-foreground/55 leading-none\">\n {isListing ? \"Price\" : \"Offer\"}\n </p>\n <p className=\"text-lg font-bold price-value leading-none inline-flex items-center gap-1.5 mt-1.5\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={18} />}\n {formatDisplayPrice(order.price.formatted)}\n <span className=\"sr-only\">{order.price.currency}</span>\n </p>\n </div>\n <p className=\"text-2xs text-muted-foreground/60 whitespace-nowrap shrink-0\">\n {timeAgo(order.createdAt)}\n </p>\n </div>\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 \"next/link\";\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 { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport type { ApiOrder, Chain } from \"@medialane/sdk\";\n\n/** ui's pinned SDK lags the apps — extend structurally for fields newer SDKs carry. */\ntype OrderWithAnimation = ApiOrder & { token: (ApiOrder[\"token\"] & { animationUrl?: string | null }) | null };\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n /** App passes a fully constructed <DropdownMenu> here */\n overflowMenu?: React.ReactNode;\n /**\n * Optional flex-1 primary control for listings, replacing the default\n * Buy/View button — lets a host inject its own action (e.g. an owner\n * \"Cancel\" with an app-specific, auth-coupled handler) while keeping this\n * card's layout. Ignored for offers (which always render \"View asset\").\n */\n primaryAction?: React.ReactNode;\n compact?: boolean;\n /**\n * Pre-resolved, browser-loadable image URL. When provided (including null),\n * overrides the card's internal ipfsToHttp resolution — apps that proxy or\n * resize images (e.g. a same-origin /api/ipfs?w= proxy) pass it here.\n * Omit for the default gateway resolution; null renders the no-image fallback.\n */\n imageUrl?: string | null;\n /**\n * Pre-formatted USD equivalent of order.price (e.g. \"$12.34\"), computed by\n * the host from its own live rate feed — this package has no price-feed\n * access by design. Omit (or pass null) to render no USD line, e.g. when\n * the host has no live rate for this order's currency.\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 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 ? ipfsToHttp(order.token.image) : null);\n // Not resolved through ipfsToHttp — animation_url is legitimately a data: URI for\n // fully on-chain-rendered collections (ipfsToHttp rejects data: by design).\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 = `/asset/${order.nftContract}/${order.nftTokenId}`;\n\n // Show the action bar for listings (Buy/View) and for offers (View asset),\n // whenever the host wired any action or an overflow menu.\n const showActionBar = !!(onBuy || onCart || overflowMenu || primaryAction);\n\n // ─── Compact variant ──────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n <div className=\"p-2.5 space-y-0.5\">\n <p className=\"text-xs font-semibold truncate\">{name}</p>\n {order.price?.formatted && (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={11} />}\n {formatDisplayPrice(order.price.formatted)}\n </p>\n )}\n {usdValue && <p className=\"text-2xs text-muted-foreground/70\">{usdValue}</p>}\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n // ─── Full variant ─────────────────────────────────────────────────────────\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 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl font-mono text-muted-foreground\">#{order.nftTokenId}</span>\n </div>\n }\n />\n </div>\n\n <div className=\"p-3.5 space-y-3\">\n <div className=\"min-w-0\">\n <p className=\"font-semibold text-base truncate leading-snug\">{name}</p>\n <p className=\"text-2xs text-muted-foreground truncate leading-snug mt-0.5\">\n {order.token?.description ? order.token.description : `#${order.nftTokenId}`}\n </p>\n </div>\n\n {/* Price / Offer + age */}\n {order.price?.formatted && (\n <div className=\"flex items-end justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-2xs uppercase tracking-widest text-muted-foreground/55 leading-none\">\n {isListing ? \"Price\" : \"Offer\"}\n </p>\n <p className=\"text-lg font-bold price-value leading-none inline-flex items-center gap-1.5 mt-1.5\">\n {order.price.currency && <CurrencyIcon symbol={order.price.currency} size={18} />}\n {formatDisplayPrice(order.price.formatted)}\n <span className=\"sr-only\">{order.price.currency}</span>\n </p>\n {usdValue && <p className=\"text-2xs text-muted-foreground/60 mt-0.5\">{usdValue}</p>}\n </div>\n <p className=\"text-2xs text-muted-foreground/60 whitespace-nowrap shrink-0\">\n {timeAgo(order.createdAt)}\n </p>\n </div>\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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.108.0",
3
+ "version": "0.110.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,